merge main

This commit is contained in:
Frooodle
2026-06-29 11:33:00 +01:00
16 changed files with 93 additions and 36 deletions
@@ -64,11 +64,19 @@ jobs:
gradle-version: 9.6.0
cache-disabled: true
# When the PR changes the base image, test.sh builds it locally
# (stirling-pdf-base:local) into the daemon image store. A buildx
# container builder can't see that store, so skip it here and let
# `docker buildx build` fall back to the default docker driver, which
# resolves the local base. The gha cache backend is also skipped (its
# runtime token isn't exposed) since the docker driver can't use it.
- name: Set up Docker Buildx
if: inputs.docker-base-changed != 'true'
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
# Expose ACTIONS_RUNTIME_TOKEN / ACTIONS_RESULTS_URL for docker buildx type=gha cache backend.
- name: Expose GitHub runtime for Buildx cache
if: inputs.docker-base-changed != 'true'
uses: crazy-max/ghaction-github-runtime@04d248b84655b509d8c44dc1d6f990c879747487 # v4.0.0
- name: Install Docker Compose
+16 -1
View File
@@ -155,6 +155,19 @@ jobs:
echo "platforms=linux/amd64,linux/arm64/v8" >> "$GITHUB_OUTPUT"
fi
# Base-changed PRs build the embedded image with the local docker driver
# so the locally-built stirling-pdf-base:pr-test (in the daemon image
# store) resolves. A buildx container builder cannot see it and would try
# to pull it from a registry, which fails. Single-platform, no gha cache.
- name: Build ${{ matrix.docker-rev }} against local base (PR base change)
if: github.event_name == 'pull_request' && inputs.docker-base-changed == 'true'
run: |
DOCKER_BUILDKIT=1 docker build \
--build-arg BASE_IMAGE=${{ steps.build-params.outputs.base_image }} \
--file ./${{ matrix.docker-rev }} \
--tag stirling-pdf-embedded:pr-test \
.
- name: Build ${{ matrix.docker-rev }} (Depot)
if: env.USE_DEPOT == 'true'
uses: depot/build-push-action@98e78adca7817480b8185f474a400b451d74e287 # v1.16.0
@@ -169,8 +182,10 @@ jobs:
provenance: true
sbom: true
# Fork PRs that did NOT change the base use the buildx container builder
# (multi-platform + gha cache) against the published base image.
- name: Build ${{ matrix.docker-rev }} (Docker fork fallback)
if: env.USE_DEPOT != 'true'
if: env.USE_DEPOT != 'true' && inputs.docker-base-changed != 'true'
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
builder: ${{ steps.buildx.outputs.name }}
@@ -150,7 +150,7 @@ const FileListItem: React.FC<FileListItemProps> = ({
shareLinks?: Array<{ token?: string }>;
}>(`/api/v1/storage/files/${file.remoteStorageId}`, {
suppressErrorToast: true,
} as any);
});
const links = response.data?.shareLinks ?? [];
const token = links[links.length - 1]?.token;
if (!token) {
@@ -536,8 +536,10 @@ const SignPopout = ({
pdfFile = new File([pdfResponse.data], session.documentName, {
type: "application/pdf",
});
} catch (pdfError: any) {
if (pdfError?.response?.status === 404) {
} catch (pdfError: unknown) {
const status = (pdfError as { response?: { status?: number } })
?.response?.status;
if (status === 404) {
// Finalized but signed PDF not available - backend issue
alert({
alertType: "warning",
@@ -760,7 +762,7 @@ const SignPopout = ({
// Update workbench data, preserving PDF and callbacks
setCustomWorkbenchViewData(
SESSION_DETAIL_WORKBENCH_ID,
(prevData: any) => ({
(prevData: Record<string, unknown>) => ({
...prevData,
session: response.data,
}),
@@ -105,8 +105,8 @@ const AddAttachmentsSettings = ({
fontWeight: 400,
lineHeight: 1.2,
display: "-webkit-box",
WebkitLineClamp: 2 as any,
WebkitBoxOrient: "vertical" as any,
WebkitLineClamp: 2,
WebkitBoxOrient: "vertical",
overflow: "hidden",
whiteSpace: "normal",
wordBreak: "break-word",
@@ -36,7 +36,10 @@ const AddPageNumbersAppearanceSettings = ({
label={t("addPageNumbers.selectText.2", "Margin")}
value={parameters.customMargin}
onChange={(v) =>
onParameterChange("customMargin", (v as any) || "medium")
onParameterChange(
"customMargin",
(v as AddPageNumbersParameters["customMargin"]) || "medium",
)
}
data={[
{ value: "small", label: t("sizes.small", "Small") },
@@ -95,7 +98,12 @@ const AddPageNumbersAppearanceSettings = ({
<Select
label={t("addPageNumbers.fontName", "Font Type")}
value={parameters.fontType}
onChange={(v) => onParameterChange("fontType", (v as any) || "Times")}
onChange={(v) =>
onParameterChange(
"fontType",
(v as AddPageNumbersParameters["fontType"]) || "Times",
)
}
data={[
{ value: "Times", label: "Times Roman" },
{ value: "Helvetica", label: "Helvetica" },
@@ -260,7 +260,12 @@ export default function PageNumberPreview({
key={idx}
type="button"
className={`${styles.gridTile} ${selected || hoverTile === idx ? styles.gridTileSelected : ""} ${hoverTile === idx ? styles.gridTileHovered : ""}`}
onClick={() => onParameterChange("position", idx as any)}
onClick={() =>
onParameterChange(
"position",
idx as AddPageNumbersParameters["position"],
)
}
onMouseEnter={() => setHoverTile(idx)}
onMouseLeave={() => setHoverTile(null)}
style={{
@@ -24,19 +24,19 @@ export default function AdjustContrastBasicSettings({
<SliderWithInput
label={t("adjustContrast.contrast", "Contrast")}
value={parameters.contrast}
onChange={(v) => onParameterChange("contrast", v as any)}
onChange={(v) => onParameterChange("contrast", v)}
disabled={disabled}
/>
<SliderWithInput
label={t("adjustContrast.brightness", "Brightness")}
value={parameters.brightness}
onChange={(v) => onParameterChange("brightness", v as any)}
onChange={(v) => onParameterChange("brightness", v)}
disabled={disabled}
/>
<SliderWithInput
label={t("adjustContrast.saturation", "Saturation")}
value={parameters.saturation}
onChange={(v) => onParameterChange("saturation", v as any)}
onChange={(v) => onParameterChange("saturation", v)}
disabled={disabled}
/>
</Stack>
@@ -24,19 +24,19 @@ export default function AdjustContrastColorSettings({
<SliderWithInput
label={t("adjustContrast.red", "Red")}
value={parameters.red}
onChange={(v) => onParameterChange("red", v as any)}
onChange={(v) => onParameterChange("red", v)}
disabled={disabled}
/>
<SliderWithInput
label={t("adjustContrast.green", "Green")}
value={parameters.green}
onChange={(v) => onParameterChange("green", v as any)}
onChange={(v) => onParameterChange("green", v)}
disabled={disabled}
/>
<SliderWithInput
label={t("adjustContrast.blue", "Blue")}
value={parameters.blue}
onChange={(v) => onParameterChange("blue", v as any)}
onChange={(v) => onParameterChange("blue", v)}
disabled={disabled}
/>
</Stack>
@@ -523,10 +523,10 @@ export const useComparePanZoom = ({
};
el.addEventListener("scroll", onScroll, { passive: true });
return () => {
el.removeEventListener("wheel", onStart as any);
el.removeEventListener("mousedown", onStart as any);
el.removeEventListener("touchstart", onStart as any);
el.removeEventListener("scroll", onScroll as any);
el.removeEventListener("wheel", onStart);
el.removeEventListener("mousedown", onStart);
el.removeEventListener("touchstart", onStart);
el.removeEventListener("scroll", onScroll);
if (timeout != null) window.clearTimeout(timeout);
};
};
@@ -26,9 +26,8 @@ const ExtractImagesSettings = ({
value={parameters.format}
onChange={(value) => {
const allowedFormats = ["png", "jpg", "gif"] as const;
const format = allowedFormats.includes(value as any)
? (value as (typeof allowedFormats)[number])
: "png";
const candidate = value as (typeof allowedFormats)[number];
const format = allowedFormats.includes(candidate) ? candidate : "png";
onParameterChange("format", format);
}}
data={[
@@ -26,7 +26,7 @@ export function useDocumentReady() {
let mounted = true;
const unsubOpen = documentManagerCapability.onDocumentOpened?.(
(event: any) => {
(event: { documentId?: string; id?: string }) => {
if (mounted && (event?.documentId || event?.id)) {
setDocumentReady(true);
}
@@ -33,7 +33,7 @@ export function useAutomationForm({
const getToolName = useCallback(
(operation: string) => {
const tool = toolRegistry?.[operation as ToolId] as any;
const tool = toolRegistry?.[operation as ToolId];
return tool?.name || t(`tools.${operation}.name`, operation);
},
[toolRegistry, t],
@@ -368,7 +368,7 @@ export const extractContentFromPdf = async (
const prevX = prev.transform[4];
const approxLine = Math.max(
10,
Math.abs((curr as any).height ?? 0) * 0.9,
Math.abs((curr as { height?: number }).height ?? 0) * 0.9,
);
const looksLikeParagraph = dy > approxLine * 1.8;
const likelySoftWrap = currX < prevX && dy < approxLine * 0.6;
@@ -20,8 +20,8 @@ const buildFormData = (
formData.append("fileInput", file);
});
// Provide stable client file IDs (align with files order)
const clientIds: string[] = files.map((f: any) =>
String((f as any).fileId || f.name),
const clientIds: string[] = files.map((f) =>
String((f as { fileId?: string }).fileId || f.name),
);
formData.append("clientFileIds", JSON.stringify(clientIds));
formData.append("sortType", "orderProvided"); // Always use orderProvided since UI handles sorting
+28 -8
View File
@@ -207,18 +207,38 @@ export default defineConfig(
},
},
// Stricter rules that not all sub-folders are conformant to yet.
// Keep this non-type-aware: `parserOptions.project`/`projectService` here OOMs
// the lint step (builds the whole TS program); tsc covers type correctness.
{
files: srcGlobs,
ignores: [
"editor/src/core/components/**/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/contexts/**/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/hooks/**/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/services/**/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/annotation/**/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/pageEditor/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/pageEditor/commands/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/pageEditor/hooks/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/shared/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/shared/config/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/shared/config/configSections/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/shared/pageEditor/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/tools/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/tools/addStamp/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/tools/automate/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/tools/bookletImposition/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/tools/certSign/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/tools/pdfTextEditor/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/tools/shared/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/components/viewer/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/contexts/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/contexts/file/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/contexts/viewer/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/hooks/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/hooks/signing/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/hooks/tools/adjustContrast/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/hooks/tools/convert/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/hooks/tools/removePassword/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/hooks/tools/shared/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/services/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/tools/annotate/useAnnotationSelection.ts",
"editor/src/core/types/**/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/utils/**/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/types/*.{js,mjs,jsx,ts,tsx}",
"editor/src/core/utils/*.{js,mjs,jsx,ts,tsx}",
],
rules: {
"@typescript-eslint/no-explicit-any": "error",