paperclip-github-plugin 0.8.8 → 0.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -3
- package/dist/manifest.js +63 -1
- package/dist/ui/index.js +73 -12
- package/dist/ui/index.js.map +3 -3
- package/dist/worker.js +390 -26
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -215,13 +215,19 @@ Notes:
|
|
|
215
215
|
- The raw token is never persisted back into plugin state or plugin config.
|
|
216
216
|
- A GitHub token secret saved through the settings UI takes precedence over the local file.
|
|
217
217
|
|
|
218
|
+
### Worker-facing Paperclip API URL
|
|
219
|
+
|
|
220
|
+
GitHub Sync uses direct worker-side Paperclip REST calls for host paths that are not fully covered by the plugin SDK, such as label reconciliation and some issue repair paths. By default, manual setup and sync actions use the current browser origin. If that origin is not reachable from the plugin worker, set **Worker Paperclip API URL** in GitHub Sync settings; the value is saved internally as plugin config `paperclipApiBaseUrl`.
|
|
221
|
+
|
|
222
|
+
For private LAN, Docker, Kubernetes, custom DNS, or self-signed-certificate deployments, set that field to a local route the plugin worker can reach, such as `http://localhost:3100`, and port-forward or route that address to the Paperclip API when needed. Do not rely on exporting a process environment variable named `PAPERCLIP_API_URL` to Paperclip; Paperclip `2026.428.0` does not pass that value through to plugin worker runtime.
|
|
223
|
+
|
|
218
224
|
## GitHub agent tools
|
|
219
225
|
|
|
220
226
|
The plugin exposes GitHub workflow tools to Paperclip agents, including:
|
|
221
227
|
|
|
222
228
|
- repository-scoped search for issues and pull requests
|
|
223
229
|
- issue reads, comment reads, comment writes, metadata updates, and `assign_to_current_user` assignment to the saved token owner
|
|
224
|
-
- pull request creation, reads, updates, changed-file inspection,
|
|
230
|
+
- pull request creation, reads, updates, changed-file inspection, CI-check inspection, and asset upload for PR visual evidence
|
|
225
231
|
- review-thread reads, replies, resolve and unresolve actions, and `request_pull_request_reviewers` reviewer requests
|
|
226
232
|
- organization-level GitHub Project search/listing and pull-request-to-project association
|
|
227
233
|
|
|
@@ -266,6 +272,34 @@ Current host caveat: on authenticated Paperclip deployments, the Paperclip host
|
|
|
266
272
|
|
|
267
273
|
Because the KPI attribution endpoint is a native plugin JSON route rather than a plugin tool, authenticated agent runs can still call it directly with `PAPERCLIP_API_KEY` even while that host bug blocks the GitHub Sync tool surface.
|
|
268
274
|
|
|
275
|
+
### Pull request asset upload
|
|
276
|
+
|
|
277
|
+
For PRs that need durable assets in the description, agents can call the `upload_pull_request_asset` tool. The tool accepts a PR target plus `fileName` and either `contentBase64` or a `dataUrl`; optional fields include `label`, `alt` (an alias for image alt text), `caption`, `mimeType`, and `artifactBranch`. Common MIME types are inferred from filenames, including images and PDFs. Unknown types are stored as `application/octet-stream`. Assets are limited to 10 MiB.
|
|
278
|
+
|
|
279
|
+
The plugin writes the asset to a non-merge artifact branch named `paperclip-artifacts-pr-<number>` by default, stores it under `assets/pr-<number>/<head-sha>/`, and returns immutable raw GitHub URLs plus Markdown suitable for a PR description. Images return image Markdown; PDFs and other files return normal Markdown links.
|
|
280
|
+
|
|
281
|
+
Authenticated agent runs that cannot call plugin tools can post the same JSON payload to `/api/plugins/paperclip-github-plugin/api/pull-request-assets` with `Authorization: Bearer ${PAPERCLIP_API_KEY}`. The native plugin route is agent-authenticated by the Paperclip host before worker dispatch.
|
|
282
|
+
|
|
283
|
+
Example:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
contentBase64="$(base64 -w0 /tmp/review-report.pdf)"
|
|
287
|
+
payload="$(jq -n \
|
|
288
|
+
--arg repository paperclipai/example-repo \
|
|
289
|
+
--argjson pullRequestNumber 21 \
|
|
290
|
+
--arg fileName review-report.pdf \
|
|
291
|
+
--arg label 'Review report PDF' \
|
|
292
|
+
--arg contentBase64 "$contentBase64" \
|
|
293
|
+
'{repository:$repository,pullRequestNumber:$pullRequestNumber,fileName:$fileName,label:$label,contentBase64:$contentBase64,mimeType:"application/pdf"}')"
|
|
294
|
+
|
|
295
|
+
curl -X POST "${PAPERCLIP_API_URL%/}/api/plugins/paperclip-github-plugin/api/pull-request-assets" \
|
|
296
|
+
-H "content-type: application/json" \
|
|
297
|
+
-H "authorization: Bearer ${PAPERCLIP_API_KEY}" \
|
|
298
|
+
-d "${payload}"
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The response body contains `asset.markdown`, `asset.rawUrl`, `asset.artifactBranch`, `asset.path`, and `asset.commitSha`.
|
|
302
|
+
|
|
269
303
|
### Issue link API route
|
|
270
304
|
|
|
271
305
|
Authenticated agent runs can link the current Paperclip issue to a GitHub issue or pull request by posting to `/api/plugins/paperclip-github-plugin/api/issue-link`. This is useful after creating a PR with `gh` in a repository that is not mapped to a Paperclip project.
|
|
@@ -296,9 +330,10 @@ curl -X POST "${PAPERCLIP_API_URL%/}/api/plugins/paperclip-github-plugin/api/iss
|
|
|
296
330
|
- If Paperclip says board access is required, open plugin settings inside the affected company and complete the Paperclip board access flow before retrying sync.
|
|
297
331
|
- If GitHub Sync agent tools fail with `403 {"error":"Board access required"}` on `/api/plugins/tools` or `/api/plugins/tools/execute`, the current Paperclip host rejected the request before the plugin worker ran. Re-run from a board-authenticated session or agent run that has board access to the target company.
|
|
298
332
|
- If a KPI API route call is rejected, make sure the request includes `Authorization: Bearer ${PAPERCLIP_API_KEY}`, that the token is still valid for the current run, and that any `companyId` in the payload matches the calling agent's company.
|
|
299
|
-
- If the worker reaches an authenticated HTML page instead of the Paperclip API JSON responses it expects, connect Paperclip board access for that company or set
|
|
333
|
+
- If the worker reaches an authenticated HTML page instead of the Paperclip API JSON responses it expects, connect Paperclip board access for that company or set **Worker Paperclip API URL** in GitHub Sync settings to a worker-accessible Paperclip API origin.
|
|
334
|
+
- If a Paperclip API fetch fails before any HTTP response is returned, the saved diagnostics include the method, URL, primary error, nested cause, and cause code when Node exposes them.
|
|
300
335
|
- If a sync run finishes with partial failures, open the saved troubleshooting panel in GitHub Sync to inspect the repository, issue number, raw error, and suggested fix for each recorded failure.
|
|
301
|
-
- If sync says the Paperclip API URL is not trusted,
|
|
336
|
+
- If sync says the Paperclip API URL is not trusted, set **Worker Paperclip API URL** in GitHub Sync settings to the worker-accessible Paperclip API origin and retry.
|
|
302
337
|
- If a pull request comment or review action is rejected, read the full toast message. Fine-grained GitHub tokens need write access to that repository, and GitHub requires a review summary when requesting changes.
|
|
303
338
|
- If a GitHub-linked project does not show the **Pull requests** sidebar entry, reopen the plugin settings and re-save the mapping. The project pull request surfaces also recover older mappings when saved ids are missing, and they can fall back to the active project's bound GitHub repository when the project already has a GitHub workspace configured.
|
|
304
339
|
- If GitHub rate limiting is hit, the plugin pauses sync until the reported reset time instead of retrying pointlessly.
|
package/dist/manifest.js
CHANGED
|
@@ -523,6 +523,58 @@ var GITHUB_AGENT_TOOLS = [
|
|
|
523
523
|
}
|
|
524
524
|
}
|
|
525
525
|
},
|
|
526
|
+
{
|
|
527
|
+
name: "upload_pull_request_asset",
|
|
528
|
+
displayName: "Upload Pull Request Asset",
|
|
529
|
+
description: "Upload a PR-visible asset such as an image, PDF, log, archive, or report to a non-merge artifact branch and return durable markdown that can be embedded in the PR body.",
|
|
530
|
+
parametersSchema: {
|
|
531
|
+
type: "object",
|
|
532
|
+
additionalProperties: false,
|
|
533
|
+
required: ["fileName"],
|
|
534
|
+
allOf: [pullRequestTargetSchema],
|
|
535
|
+
anyOf: [
|
|
536
|
+
{ required: ["contentBase64"] },
|
|
537
|
+
{ required: ["dataUrl"] }
|
|
538
|
+
],
|
|
539
|
+
properties: {
|
|
540
|
+
repository: repositoryProperty,
|
|
541
|
+
pullRequestNumber: pullRequestNumberProperty,
|
|
542
|
+
paperclipIssueId: paperclipIssueIdProperty,
|
|
543
|
+
fileName: {
|
|
544
|
+
type: "string",
|
|
545
|
+
description: "Asset filename. The plugin sanitizes it and preserves a safe extension."
|
|
546
|
+
},
|
|
547
|
+
label: {
|
|
548
|
+
type: "string",
|
|
549
|
+
description: "Human-readable link text for the returned Markdown. Defaults to the sanitized filename."
|
|
550
|
+
},
|
|
551
|
+
alt: {
|
|
552
|
+
type: "string",
|
|
553
|
+
description: "Backward-compatible alias for label, useful as image alt text."
|
|
554
|
+
},
|
|
555
|
+
caption: {
|
|
556
|
+
type: "string",
|
|
557
|
+
description: "Optional human-facing caption returned with the uploaded asset metadata."
|
|
558
|
+
},
|
|
559
|
+
contentBase64: {
|
|
560
|
+
type: "string",
|
|
561
|
+
description: "Base64-encoded asset bytes. Assets are limited to 10 MiB."
|
|
562
|
+
},
|
|
563
|
+
dataUrl: {
|
|
564
|
+
type: "string",
|
|
565
|
+
description: "Alternative base64 data URL input such as data:application/pdf;base64,... or data:image/png;base64,... ."
|
|
566
|
+
},
|
|
567
|
+
mimeType: {
|
|
568
|
+
type: "string",
|
|
569
|
+
description: "Optional MIME type such as application/pdf or image/png. If omitted, the plugin infers common types from fileName and otherwise uses application/octet-stream."
|
|
570
|
+
},
|
|
571
|
+
artifactBranch: {
|
|
572
|
+
type: "string",
|
|
573
|
+
description: "Optional artifact branch name. Defaults to paperclip-artifacts-pr-<pullRequestNumber>."
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
},
|
|
526
578
|
{
|
|
527
579
|
name: "link_github_item",
|
|
528
580
|
displayName: "Link GitHub Item",
|
|
@@ -582,12 +634,15 @@ var COMPANY_METRIC_API_ROUTE_URL_PATH = `/api/plugins/${GITHUB_SYNC_PLUGIN_ID}/a
|
|
|
582
634
|
var ISSUE_LINK_API_ROUTE_KEY = "link-github-item";
|
|
583
635
|
var ISSUE_LINK_API_ROUTE_PATH = "/issue-link";
|
|
584
636
|
var ISSUE_LINK_API_ROUTE_URL_PATH = `/api/plugins/${GITHUB_SYNC_PLUGIN_ID}/api${ISSUE_LINK_API_ROUTE_PATH}`;
|
|
637
|
+
var PULL_REQUEST_ASSET_API_ROUTE_KEY = "upload-pull-request-asset";
|
|
638
|
+
var PULL_REQUEST_ASSET_API_ROUTE_PATH = "/pull-request-assets";
|
|
639
|
+
var PULL_REQUEST_ASSET_API_ROUTE_URL_PATH = `/api/plugins/${GITHUB_SYNC_PLUGIN_ID}/api${PULL_REQUEST_ASSET_API_ROUTE_PATH}`;
|
|
585
640
|
|
|
586
641
|
// src/manifest.ts
|
|
587
642
|
var require2 = createRequire(import.meta.url);
|
|
588
643
|
var packageJson = require2("../package.json");
|
|
589
644
|
var SCHEDULE_TICK_CRON = "* * * * *";
|
|
590
|
-
var MANIFEST_VERSION = "0.8.
|
|
645
|
+
var MANIFEST_VERSION = "0.8.10"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
|
|
591
646
|
var manifest = {
|
|
592
647
|
id: GITHUB_SYNC_PLUGIN_ID,
|
|
593
648
|
apiVersion: 1,
|
|
@@ -666,6 +721,13 @@ var manifest = {
|
|
|
666
721
|
path: ISSUE_LINK_API_ROUTE_PATH,
|
|
667
722
|
auth: "agent",
|
|
668
723
|
capability: "api.routes.register"
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
routeKey: PULL_REQUEST_ASSET_API_ROUTE_KEY,
|
|
727
|
+
method: "POST",
|
|
728
|
+
path: PULL_REQUEST_ASSET_API_ROUTE_PATH,
|
|
729
|
+
auth: "agent",
|
|
730
|
+
capability: "api.routes.register"
|
|
669
731
|
}
|
|
670
732
|
],
|
|
671
733
|
tools: GITHUB_AGENT_TOOLS,
|
package/dist/ui/index.js
CHANGED
|
@@ -11984,7 +11984,7 @@ var urlAttributes = {
|
|
|
11984
11984
|
]
|
|
11985
11985
|
};
|
|
11986
11986
|
|
|
11987
|
-
// node_modules/.pnpm/react-markdown@10.1.0_@types+react@19.2.14_react@19.2.
|
|
11987
|
+
// node_modules/.pnpm/react-markdown@10.1.0_@types+react@19.2.14_react@19.2.6/node_modules/react-markdown/lib/index.js
|
|
11988
11988
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11989
11989
|
import { useEffect, useState } from "react";
|
|
11990
11990
|
|
|
@@ -19140,7 +19140,7 @@ function isUint8Array2(value) {
|
|
|
19140
19140
|
);
|
|
19141
19141
|
}
|
|
19142
19142
|
|
|
19143
|
-
// node_modules/.pnpm/react-markdown@10.1.0_@types+react@19.2.14_react@19.2.
|
|
19143
|
+
// node_modules/.pnpm/react-markdown@10.1.0_@types+react@19.2.14_react@19.2.6/node_modules/react-markdown/lib/index.js
|
|
19144
19144
|
var changelog = "https://github.com/remarkjs/react-markdown/blob/main/changelog.md";
|
|
19145
19145
|
var emptyPlugins = [];
|
|
19146
19146
|
var emptyRemarkRehypeOptions = { allowDangerousHtml: true };
|
|
@@ -22694,6 +22694,9 @@ function normalizePluginConfig(value) {
|
|
|
22694
22694
|
}
|
|
22695
22695
|
return record;
|
|
22696
22696
|
}
|
|
22697
|
+
function resolvePaperclipApiBaseUrlForPluginAction(value, fallbackOrigin) {
|
|
22698
|
+
return normalizePluginConfig(value).paperclipApiBaseUrl ?? normalizePaperclipApiBaseUrl(fallbackOrigin);
|
|
22699
|
+
}
|
|
22697
22700
|
function mergePluginConfig(currentValue, patch5) {
|
|
22698
22701
|
const current = normalizePluginConfig(currentValue);
|
|
22699
22702
|
const currentGitHubTokenRefs = normalizePluginConfigGitHubTokenRefs(current.githubTokenRefs);
|
|
@@ -27577,7 +27580,7 @@ function shouldAutofillProjectName(mapping) {
|
|
|
27577
27580
|
const previousSuggestedProjectName = formatProjectNameFromRepository(mapping.repositoryUrl);
|
|
27578
27581
|
return previousSuggestedProjectName !== "" && currentProjectName === previousSuggestedProjectName;
|
|
27579
27582
|
}
|
|
27580
|
-
function
|
|
27583
|
+
function getPaperclipApiBrowserOrigin() {
|
|
27581
27584
|
if (typeof window === "undefined" || !window.location?.origin) {
|
|
27582
27585
|
return void 0;
|
|
27583
27586
|
}
|
|
@@ -27616,23 +27619,22 @@ async function fetchPluginDataResult(params) {
|
|
|
27616
27619
|
return response.data;
|
|
27617
27620
|
}
|
|
27618
27621
|
async function syncTrustedPaperclipApiBaseUrl(pluginId) {
|
|
27619
|
-
const paperclipApiBaseUrl = getPaperclipApiBaseUrl();
|
|
27620
|
-
if (!paperclipApiBaseUrl) {
|
|
27621
|
-
return void 0;
|
|
27622
|
-
}
|
|
27623
27622
|
const resolvedPluginId = await resolveCurrentPluginId(pluginId);
|
|
27624
27623
|
if (!resolvedPluginId) {
|
|
27625
27624
|
throw new Error(
|
|
27626
27625
|
"Unable to sync the trusted Paperclip API origin because the plugin ID is missing. Reload the plugin and try again before saving or syncing."
|
|
27627
27626
|
);
|
|
27628
27627
|
}
|
|
27628
|
+
const currentConfigResponse = await fetchJson(`/api/plugins/${resolvedPluginId}/config`);
|
|
27629
|
+
const currentConfig = normalizePluginConfig(currentConfigResponse?.configJson);
|
|
27630
|
+
const paperclipApiBaseUrl = resolvePaperclipApiBaseUrlForPluginAction(currentConfig, getPaperclipApiBrowserOrigin());
|
|
27631
|
+
if (!paperclipApiBaseUrl) {
|
|
27632
|
+
return void 0;
|
|
27633
|
+
}
|
|
27629
27634
|
const lastSyncedPaperclipApiBaseUrl = syncedPaperclipApiBaseUrlsByPluginId.get(resolvedPluginId);
|
|
27630
27635
|
if (lastSyncedPaperclipApiBaseUrl === paperclipApiBaseUrl) {
|
|
27631
27636
|
return paperclipApiBaseUrl;
|
|
27632
27637
|
}
|
|
27633
|
-
await patchPluginConfig(resolvedPluginId, {
|
|
27634
|
-
paperclipApiBaseUrl
|
|
27635
|
-
});
|
|
27636
27638
|
syncedPaperclipApiBaseUrlsByPluginId.set(resolvedPluginId, paperclipApiBaseUrl);
|
|
27637
27639
|
return paperclipApiBaseUrl;
|
|
27638
27640
|
}
|
|
@@ -31964,6 +31966,7 @@ function GitHubSyncSettingsPage() {
|
|
|
31964
31966
|
const [cancellingSync, setCancellingSync] = useState2(false);
|
|
31965
31967
|
const [manualSyncRequestError, setManualSyncRequestError] = useState2(null);
|
|
31966
31968
|
const [scheduleFrequencyDraft, setScheduleFrequencyDraft] = useState2(String(DEFAULT_SCHEDULE_FREQUENCY_MINUTES));
|
|
31969
|
+
const [paperclipApiBaseUrlDraft, setPaperclipApiBaseUrlDraft] = useState2("");
|
|
31967
31970
|
const [ignoredAuthorsDraft, setIgnoredAuthorsDraft] = useState2(DEFAULT_ADVANCED_SETTINGS.ignoredIssueAuthorUsernames.join(", "));
|
|
31968
31971
|
const [tokenStatusOverride, setTokenStatusOverride] = useState2(null);
|
|
31969
31972
|
const [validatedLogin, setValidatedLogin] = useState2(null);
|
|
@@ -32012,6 +32015,9 @@ function GitHubSyncSettingsPage() {
|
|
|
32012
32015
|
updatedAt: settings.data.updatedAt
|
|
32013
32016
|
});
|
|
32014
32017
|
setScheduleFrequencyDraft(String(nextScheduleFrequencyMinutes));
|
|
32018
|
+
setPaperclipApiBaseUrlDraft(
|
|
32019
|
+
settings.data.paperclipApiBaseUrlConfigured ? settings.data.paperclipApiBaseUrl ?? "" : getPaperclipApiBrowserOrigin() ?? ""
|
|
32020
|
+
);
|
|
32015
32021
|
setIgnoredAuthorsDraft(normalizeAdvancedSettings(settings.data.advancedSettings).ignoredIssueAuthorUsernames.join(", "));
|
|
32016
32022
|
setTokenDraft("");
|
|
32017
32023
|
setValidatedLogin(tokenUiState.validatedLogin);
|
|
@@ -32283,12 +32289,21 @@ function GitHubSyncSettingsPage() {
|
|
|
32283
32289
|
const scheduleFrequencyMinutes = parseScheduleFrequencyDraft(scheduleFrequencyDraft) ?? form.scheduleFrequencyMinutes;
|
|
32284
32290
|
const savedScheduleFrequencyMinutes = normalizeScheduleFrequencyMinutes(currentSettings?.scheduleFrequencyMinutes);
|
|
32285
32291
|
const scheduleDirty = scheduleFrequencyError === null && scheduleFrequencyMinutes !== savedScheduleFrequencyMinutes;
|
|
32292
|
+
const browserPaperclipApiBaseUrl = getPaperclipApiBrowserOrigin();
|
|
32293
|
+
const normalizedPaperclipApiBaseUrlDraft = normalizePaperclipApiBaseUrl(paperclipApiBaseUrlDraft);
|
|
32294
|
+
const paperclipApiBaseUrlError = paperclipApiBaseUrlDraft.trim() && !normalizedPaperclipApiBaseUrlDraft ? "Enter a valid URL." : null;
|
|
32295
|
+
const effectivePaperclipApiBaseUrl = normalizedPaperclipApiBaseUrlDraft ?? browserPaperclipApiBaseUrl;
|
|
32296
|
+
const paperclipApiBaseUrlIsOverride = Boolean(
|
|
32297
|
+
normalizedPaperclipApiBaseUrlDraft && browserPaperclipApiBaseUrl && normalizedPaperclipApiBaseUrlDraft !== browserPaperclipApiBaseUrl
|
|
32298
|
+
);
|
|
32299
|
+
const savedPaperclipApiBaseUrl = currentSettings?.paperclipApiBaseUrlConfigured ? currentSettings.paperclipApiBaseUrl ?? "" : browserPaperclipApiBaseUrl ?? "";
|
|
32300
|
+
const paperclipApiBaseUrlDirty = paperclipApiBaseUrlError === null && (normalizedPaperclipApiBaseUrlDraft ?? "") !== savedPaperclipApiBaseUrl;
|
|
32286
32301
|
const mappings = form.mappings.length > 0 ? form.mappings : [createEmptyMapping(0)];
|
|
32287
32302
|
const settingsMutationsLocked = syncInFlight;
|
|
32288
32303
|
const settingsMutationsLockReason = settingsMutationsLocked ? "Settings are temporarily locked while a sync is running to avoid overwriting local edits." : null;
|
|
32289
32304
|
const syncStatus = getSyncStatus(displaySyncState, runningSync, syncUnlocked);
|
|
32290
32305
|
const canSaveToken = hasCompanyContext && !settingsMutationsLocked && !submittingToken && !showInitialLoadingState && tokenDraft.trim().length > 0;
|
|
32291
|
-
const canSaveSetup = hasCompanyContext && repositoriesUnlocked && !settingsMutationsLocked && !submittingSetup && !showInitialLoadingState && scheduleFrequencyError === null && (mappingsDirty || advancedSettingsDirty || scheduleDirty);
|
|
32306
|
+
const canSaveSetup = hasCompanyContext && repositoriesUnlocked && !settingsMutationsLocked && !submittingSetup && !showInitialLoadingState && scheduleFrequencyError === null && paperclipApiBaseUrlError === null && (mappingsDirty || advancedSettingsDirty || scheduleDirty || paperclipApiBaseUrlDirty);
|
|
32292
32307
|
const canConnectBoardAccess = hasCompanyContext && !settingsMutationsLocked && !connectingBoardAccess && !showInitialLoadingState;
|
|
32293
32308
|
const boardAccessStatusLabel = !hasCompanyContext ? "Unavailable" : boardAccessBannerLabel;
|
|
32294
32309
|
const boardAccessStatusTone = !hasCompanyContext ? boardAccessRequired ? "warning" : "neutral" : boardAccessTone;
|
|
@@ -32693,6 +32708,9 @@ function GitHubSyncSettingsPage() {
|
|
|
32693
32708
|
if (scheduleFrequencyError) {
|
|
32694
32709
|
throw new Error(scheduleFrequencyError);
|
|
32695
32710
|
}
|
|
32711
|
+
if (paperclipApiBaseUrlError) {
|
|
32712
|
+
throw new Error(paperclipApiBaseUrlError);
|
|
32713
|
+
}
|
|
32696
32714
|
const resolvedMappings = [];
|
|
32697
32715
|
for (const mapping of form.mappings) {
|
|
32698
32716
|
const repositoryInput = mapping.repositoryUrl.trim();
|
|
@@ -32717,7 +32735,18 @@ function GitHubSyncSettingsPage() {
|
|
|
32717
32735
|
companyId
|
|
32718
32736
|
});
|
|
32719
32737
|
}
|
|
32720
|
-
const
|
|
32738
|
+
const pluginId = await resolveCurrentPluginId(pluginIdFromLocation);
|
|
32739
|
+
if (!pluginId) {
|
|
32740
|
+
throw new Error("Plugin id is required to save setup.");
|
|
32741
|
+
}
|
|
32742
|
+
const trustedPaperclipApiBaseUrl = effectivePaperclipApiBaseUrl;
|
|
32743
|
+
if (!trustedPaperclipApiBaseUrl) {
|
|
32744
|
+
throw new Error("Could not resolve the current browser origin for Paperclip API calls.");
|
|
32745
|
+
}
|
|
32746
|
+
const nextConfiguredPaperclipApiBaseUrl = paperclipApiBaseUrlIsOverride ? normalizedPaperclipApiBaseUrlDraft ?? "" : "";
|
|
32747
|
+
await patchPluginConfig(pluginId, {
|
|
32748
|
+
paperclipApiBaseUrl: nextConfiguredPaperclipApiBaseUrl
|
|
32749
|
+
});
|
|
32721
32750
|
const result = await saveRegistration({
|
|
32722
32751
|
companyId,
|
|
32723
32752
|
mappings: resolvedMappings,
|
|
@@ -32743,9 +32772,11 @@ function GitHubSyncSettingsPage() {
|
|
|
32743
32772
|
advancedSettings: normalizeAdvancedSettings(result.advancedSettings),
|
|
32744
32773
|
availableAssignees: result.availableAssignees ?? current.availableAssignees,
|
|
32745
32774
|
paperclipApiBaseUrl: result.paperclipApiBaseUrl,
|
|
32775
|
+
paperclipApiBaseUrlConfigured: paperclipApiBaseUrlIsOverride,
|
|
32746
32776
|
updatedAt: result.updatedAt
|
|
32747
32777
|
}));
|
|
32748
32778
|
setScheduleFrequencyDraft(String(normalizeScheduleFrequencyMinutes(result.scheduleFrequencyMinutes)));
|
|
32779
|
+
setPaperclipApiBaseUrlDraft(paperclipApiBaseUrlIsOverride ? nextConfiguredPaperclipApiBaseUrl : trustedPaperclipApiBaseUrl);
|
|
32749
32780
|
toast({
|
|
32750
32781
|
title: "GitHub sync setup saved",
|
|
32751
32782
|
body: `Advanced defaults, mappings, and automatic sync are saved for ${currentCompanyName}.`,
|
|
@@ -33423,6 +33454,32 @@ function GitHubSyncSettingsPage() {
|
|
|
33423
33454
|
] })
|
|
33424
33455
|
] })
|
|
33425
33456
|
] }),
|
|
33457
|
+
/* @__PURE__ */ jsxs2("div", { className: "ghsync__schedule-card", children: [
|
|
33458
|
+
/* @__PURE__ */ jsxs2("div", { className: "ghsync__field", children: [
|
|
33459
|
+
/* @__PURE__ */ jsx2("label", { htmlFor: "paperclip-api-base-url", children: "Worker Paperclip API URL" }),
|
|
33460
|
+
/* @__PURE__ */ jsx2(
|
|
33461
|
+
"input",
|
|
33462
|
+
{
|
|
33463
|
+
id: "paperclip-api-base-url",
|
|
33464
|
+
className: "ghsync__input",
|
|
33465
|
+
type: "url",
|
|
33466
|
+
value: paperclipApiBaseUrlDraft,
|
|
33467
|
+
disabled: settingsMutationsLocked || !hasCompanyContext,
|
|
33468
|
+
onChange: (event) => {
|
|
33469
|
+
setPaperclipApiBaseUrlDraft(event.currentTarget.value);
|
|
33470
|
+
},
|
|
33471
|
+
placeholder: browserPaperclipApiBaseUrl ?? "https://paperclip.example.com",
|
|
33472
|
+
autoComplete: "off"
|
|
33473
|
+
}
|
|
33474
|
+
),
|
|
33475
|
+
/* @__PURE__ */ jsx2("p", { className: `ghsync__hint${paperclipApiBaseUrlError ? " ghsync__hint--error" : ""}`, children: paperclipApiBaseUrlError ?? "Edit this only when the plugin worker needs a different Paperclip API origin." })
|
|
33476
|
+
] }),
|
|
33477
|
+
/* @__PURE__ */ jsxs2("div", { className: "ghsync__schedule-meta", children: [
|
|
33478
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__scope-pill ghsync__scope-pill--global", children: "Worker" }),
|
|
33479
|
+
/* @__PURE__ */ jsx2("strong", { children: effectivePaperclipApiBaseUrl ?? "Browser origin unavailable" }),
|
|
33480
|
+
/* @__PURE__ */ jsx2("span", { children: paperclipApiBaseUrlIsOverride ? "Configured override." : "Using browser origin." })
|
|
33481
|
+
] })
|
|
33482
|
+
] }),
|
|
33426
33483
|
!syncUnlocked ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__locked", children: [
|
|
33427
33484
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
33428
33485
|
/* @__PURE__ */ jsx2("strong", { children: syncSetupIssue === "missing_board_access" ? "Paperclip board access is required" : "Manual sync is locked" }),
|
|
@@ -33544,6 +33601,10 @@ function GitHubSyncSettingsPage() {
|
|
|
33544
33601
|
/* @__PURE__ */ jsx2("span", { className: "ghsync__detail-label", children: "Auto-sync" }),
|
|
33545
33602
|
/* @__PURE__ */ jsx2("strong", { className: "ghsync__detail-value", children: scheduleDescription })
|
|
33546
33603
|
] }),
|
|
33604
|
+
/* @__PURE__ */ jsxs2("div", { className: "ghsync__detail", children: [
|
|
33605
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__detail-label", children: "Worker API" }),
|
|
33606
|
+
/* @__PURE__ */ jsx2("strong", { className: "ghsync__detail-value", children: effectivePaperclipApiBaseUrl })
|
|
33607
|
+
] }),
|
|
33547
33608
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__detail", children: [
|
|
33548
33609
|
/* @__PURE__ */ jsx2("span", { className: "ghsync__detail-label", children: "Last sync" }),
|
|
33549
33610
|
/* @__PURE__ */ jsx2("strong", { className: "ghsync__detail-value", children: lastSync })
|