merge main
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
+10
-2
@@ -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={{
|
||||
|
||||
+3
-3
@@ -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>
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user