paperclip-github-plugin 0.3.6 → 0.4.1
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 +20 -10
- package/dist/manifest.js +7 -4
- package/dist/ui/index.js +534 -32
- package/dist/ui/index.js.map +3 -3
- package/dist/worker.js +220 -65
- package/package.json +1 -1
package/dist/ui/index.js
CHANGED
|
@@ -22400,6 +22400,11 @@ function requiresPaperclipBoardAccess(value) {
|
|
|
22400
22400
|
const health = normalizePaperclipHealthResponse(value);
|
|
22401
22401
|
return health?.deploymentMode?.toLowerCase() === "authenticated";
|
|
22402
22402
|
}
|
|
22403
|
+
function shouldShowPaperclipBoardAccessSettings(value) {
|
|
22404
|
+
const health = normalizePaperclipHealthResponse(value);
|
|
22405
|
+
const deploymentMode = health?.deploymentMode?.toLowerCase();
|
|
22406
|
+
return deploymentMode === "authenticated" || deploymentMode === "local_trusted";
|
|
22407
|
+
}
|
|
22403
22408
|
|
|
22404
22409
|
// src/ui/assignees.ts
|
|
22405
22410
|
function normalizeCompanyAssigneeOptionsResponse(response) {
|
|
@@ -22648,18 +22653,32 @@ function normalizePluginConfigBoardTokenRefs(value) {
|
|
|
22648
22653
|
}
|
|
22649
22654
|
return Object.fromEntries(entries);
|
|
22650
22655
|
}
|
|
22656
|
+
function normalizePluginConfigGitHubTokenRefs(value) {
|
|
22657
|
+
if (!value || typeof value !== "object") {
|
|
22658
|
+
return void 0;
|
|
22659
|
+
}
|
|
22660
|
+
const entries = Object.entries(value).map(([companyId, secretRef]) => {
|
|
22661
|
+
const normalizedCompanyId = normalizeOptionalString2(companyId);
|
|
22662
|
+
const normalizedSecretRef = normalizeOptionalString2(secretRef);
|
|
22663
|
+
return normalizedCompanyId && normalizedSecretRef ? [normalizedCompanyId, normalizedSecretRef] : null;
|
|
22664
|
+
}).filter((entry) => Boolean(entry));
|
|
22665
|
+
if (entries.length === 0) {
|
|
22666
|
+
return void 0;
|
|
22667
|
+
}
|
|
22668
|
+
return Object.fromEntries(entries);
|
|
22669
|
+
}
|
|
22651
22670
|
function normalizePluginConfig(value) {
|
|
22652
22671
|
if (!value || typeof value !== "object") {
|
|
22653
22672
|
return {};
|
|
22654
22673
|
}
|
|
22655
22674
|
const record = { ...value };
|
|
22656
|
-
const
|
|
22675
|
+
const githubTokenRefs = normalizePluginConfigGitHubTokenRefs(record.githubTokenRefs);
|
|
22657
22676
|
const paperclipBoardApiTokenRefs = normalizePluginConfigBoardTokenRefs(record.paperclipBoardApiTokenRefs);
|
|
22658
22677
|
const paperclipApiBaseUrl = normalizePaperclipApiBaseUrl(record.paperclipApiBaseUrl);
|
|
22659
|
-
if (
|
|
22660
|
-
record.
|
|
22678
|
+
if (githubTokenRefs) {
|
|
22679
|
+
record.githubTokenRefs = githubTokenRefs;
|
|
22661
22680
|
} else {
|
|
22662
|
-
delete record.
|
|
22681
|
+
delete record.githubTokenRefs;
|
|
22663
22682
|
}
|
|
22664
22683
|
if (paperclipBoardApiTokenRefs) {
|
|
22665
22684
|
record.paperclipBoardApiTokenRefs = paperclipBoardApiTokenRefs;
|
|
@@ -22675,12 +22694,27 @@ function normalizePluginConfig(value) {
|
|
|
22675
22694
|
}
|
|
22676
22695
|
function mergePluginConfig(currentValue, patch5) {
|
|
22677
22696
|
const current = normalizePluginConfig(currentValue);
|
|
22697
|
+
const currentGitHubTokenRefs = normalizePluginConfigGitHubTokenRefs(current.githubTokenRefs);
|
|
22698
|
+
const patchGitHubTokenRefs = normalizePluginConfigGitHubTokenRefs(patch5.githubTokenRefs);
|
|
22678
22699
|
const currentBoardTokenRefs = normalizePluginConfigBoardTokenRefs(current.paperclipBoardApiTokenRefs);
|
|
22679
22700
|
const patchBoardTokenRefs = normalizePluginConfigBoardTokenRefs(patch5.paperclipBoardApiTokenRefs);
|
|
22680
22701
|
const next2 = normalizePluginConfig({
|
|
22681
22702
|
...current,
|
|
22682
22703
|
...patch5
|
|
22683
22704
|
});
|
|
22705
|
+
if ("githubTokenRefs" in patch5) {
|
|
22706
|
+
const mergedGitHubTokenRefs = {
|
|
22707
|
+
...currentGitHubTokenRefs ?? {},
|
|
22708
|
+
...patchGitHubTokenRefs ?? {}
|
|
22709
|
+
};
|
|
22710
|
+
if (Object.keys(mergedGitHubTokenRefs).length > 0) {
|
|
22711
|
+
next2.githubTokenRefs = mergedGitHubTokenRefs;
|
|
22712
|
+
} else {
|
|
22713
|
+
delete next2.githubTokenRefs;
|
|
22714
|
+
}
|
|
22715
|
+
} else if (currentGitHubTokenRefs) {
|
|
22716
|
+
next2.githubTokenRefs = currentGitHubTokenRefs;
|
|
22717
|
+
}
|
|
22684
22718
|
if ("paperclipBoardApiTokenRefs" in patch5) {
|
|
22685
22719
|
const mergedBoardTokenRefs = {
|
|
22686
22720
|
...currentBoardTokenRefs ?? {},
|
|
@@ -23011,6 +23045,7 @@ function getSyncSetupMessage(issue, hasCompanyContext) {
|
|
|
23011
23045
|
}
|
|
23012
23046
|
function usePaperclipBoardAccessRequirement() {
|
|
23013
23047
|
const [status, setStatus] = useState2("loading");
|
|
23048
|
+
const [visible, setVisible] = useState2(false);
|
|
23014
23049
|
useEffect2(() => {
|
|
23015
23050
|
let cancelled = false;
|
|
23016
23051
|
void (async () => {
|
|
@@ -23020,8 +23055,10 @@ function usePaperclipBoardAccessRequirement() {
|
|
|
23020
23055
|
}
|
|
23021
23056
|
if (!health) {
|
|
23022
23057
|
setStatus("unknown");
|
|
23058
|
+
setVisible(false);
|
|
23023
23059
|
return;
|
|
23024
23060
|
}
|
|
23061
|
+
setVisible(shouldShowPaperclipBoardAccessSettings(health));
|
|
23025
23062
|
setStatus(requiresPaperclipBoardAccess(health) ? "required" : "not_required");
|
|
23026
23063
|
})();
|
|
23027
23064
|
return () => {
|
|
@@ -23030,7 +23067,8 @@ function usePaperclipBoardAccessRequirement() {
|
|
|
23030
23067
|
}, []);
|
|
23031
23068
|
return {
|
|
23032
23069
|
status,
|
|
23033
|
-
required: status === "required"
|
|
23070
|
+
required: status === "required",
|
|
23071
|
+
visible
|
|
23034
23072
|
};
|
|
23035
23073
|
}
|
|
23036
23074
|
function getGitHubRateLimitResourceLabel(resource) {
|
|
@@ -26535,12 +26573,21 @@ function normalizeGitHubUsername(value) {
|
|
|
26535
26573
|
const trimmed = value.trim().replace(/^@+/, "").toLowerCase();
|
|
26536
26574
|
return trimmed ? trimmed : null;
|
|
26537
26575
|
}
|
|
26576
|
+
function normalizeOptionalText(value) {
|
|
26577
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
26578
|
+
}
|
|
26538
26579
|
function normalizeIgnoredIssueAuthorUsernames(value) {
|
|
26539
26580
|
const rawEntries = Array.isArray(value) ? value : typeof value === "string" ? value.split(/[\s,]+/g) : [];
|
|
26540
26581
|
return [...new Set(
|
|
26541
26582
|
rawEntries.map((entry) => typeof entry === "string" ? normalizeGitHubUsername(entry) : null).filter((entry) => Boolean(entry))
|
|
26542
26583
|
)];
|
|
26543
26584
|
}
|
|
26585
|
+
function normalizeAgentIds(value) {
|
|
26586
|
+
const rawEntries = Array.isArray(value) ? value : [];
|
|
26587
|
+
return [...new Set(
|
|
26588
|
+
rawEntries.map((entry) => typeof entry === "string" && entry.trim() ? entry.trim() : null).filter((entry) => Boolean(entry))
|
|
26589
|
+
)].sort((left, right) => left.localeCompare(right));
|
|
26590
|
+
}
|
|
26544
26591
|
function normalizeAdvancedSettings(value) {
|
|
26545
26592
|
if (!value || typeof value !== "object") {
|
|
26546
26593
|
return DEFAULT_ADVANCED_SETTINGS;
|
|
@@ -26550,7 +26597,8 @@ function normalizeAdvancedSettings(value) {
|
|
|
26550
26597
|
return {
|
|
26551
26598
|
...defaultAssigneeAgentId ? { defaultAssigneeAgentId } : {},
|
|
26552
26599
|
defaultStatus: normalizePaperclipIssueStatus(record.defaultStatus),
|
|
26553
|
-
ignoredIssueAuthorUsernames: "ignoredIssueAuthorUsernames" in record ? normalizeIgnoredIssueAuthorUsernames(record.ignoredIssueAuthorUsernames) : DEFAULT_ADVANCED_SETTINGS.ignoredIssueAuthorUsernames
|
|
26600
|
+
ignoredIssueAuthorUsernames: "ignoredIssueAuthorUsernames" in record ? normalizeIgnoredIssueAuthorUsernames(record.ignoredIssueAuthorUsernames) : DEFAULT_ADVANCED_SETTINGS.ignoredIssueAuthorUsernames,
|
|
26601
|
+
...normalizeAgentIds(record.githubTokenPropagationAgentIds).length > 0 ? { githubTokenPropagationAgentIds: normalizeAgentIds(record.githubTokenPropagationAgentIds) } : {}
|
|
26554
26602
|
};
|
|
26555
26603
|
}
|
|
26556
26604
|
function getComparableMappings(mappings) {
|
|
@@ -26567,7 +26615,8 @@ function getComparableAdvancedSettings(value) {
|
|
|
26567
26615
|
return {
|
|
26568
26616
|
...settings.defaultAssigneeAgentId ? { defaultAssigneeAgentId: settings.defaultAssigneeAgentId } : {},
|
|
26569
26617
|
defaultStatus: settings.defaultStatus,
|
|
26570
|
-
ignoredIssueAuthorUsernames: [...settings.ignoredIssueAuthorUsernames].sort((left, right) => left.localeCompare(right))
|
|
26618
|
+
ignoredIssueAuthorUsernames: [...settings.ignoredIssueAuthorUsernames].sort((left, right) => left.localeCompare(right)),
|
|
26619
|
+
...settings.githubTokenPropagationAgentIds?.length ? { githubTokenPropagationAgentIds: [...settings.githubTokenPropagationAgentIds].sort((left, right) => left.localeCompare(right)) } : {}
|
|
26571
26620
|
};
|
|
26572
26621
|
}
|
|
26573
26622
|
function formatAssigneeOptionLabel(option) {
|
|
@@ -26583,7 +26632,20 @@ function getAvailableAssigneeOptions(options, selectedAgentId) {
|
|
|
26583
26632
|
}
|
|
26584
26633
|
return normalizedOptions;
|
|
26585
26634
|
}
|
|
26586
|
-
function
|
|
26635
|
+
function getAvailablePropagationAgentOptions(options, selectedAgentIds) {
|
|
26636
|
+
const normalizedOptions = [...options ?? []];
|
|
26637
|
+
const selectedIds = normalizeAgentIds(selectedAgentIds);
|
|
26638
|
+
for (const selectedAgentId of selectedIds) {
|
|
26639
|
+
if (!normalizedOptions.some((option) => option.id === selectedAgentId)) {
|
|
26640
|
+
normalizedOptions.push({
|
|
26641
|
+
id: selectedAgentId,
|
|
26642
|
+
name: "Unavailable agent"
|
|
26643
|
+
});
|
|
26644
|
+
}
|
|
26645
|
+
}
|
|
26646
|
+
return normalizedOptions.sort((left, right) => left.name.localeCompare(right.name));
|
|
26647
|
+
}
|
|
26648
|
+
function formatAdvancedSettingsSummary(advancedSettings, availableAssignees, options) {
|
|
26587
26649
|
const assigneeLabel = advancedSettings.defaultAssigneeAgentId ? formatAssigneeOptionLabel(
|
|
26588
26650
|
availableAssignees.find((option) => option.id === advancedSettings.defaultAssigneeAgentId) ?? {
|
|
26589
26651
|
id: advancedSettings.defaultAssigneeAgentId,
|
|
@@ -26592,8 +26654,41 @@ function formatAdvancedSettingsSummary(advancedSettings, availableAssignees) {
|
|
|
26592
26654
|
) : "Unassigned";
|
|
26593
26655
|
const statusLabel = PAPERCLIP_STATUS_OPTIONS.find((option) => option.value === advancedSettings.defaultStatus)?.label ?? "Backlog";
|
|
26594
26656
|
const ignoredAuthorsLabel = advancedSettings.ignoredIssueAuthorUsernames.length > 0 ? advancedSettings.ignoredIssueAuthorUsernames.join(", ") : "none";
|
|
26657
|
+
if (options?.includePropagation) {
|
|
26658
|
+
const propagatedAgentsLabel = advancedSettings.githubTokenPropagationAgentIds?.length ? `${advancedSettings.githubTokenPropagationAgentIds.length} selected` : "none";
|
|
26659
|
+
return `Assignee: ${assigneeLabel} \xB7 Status: ${statusLabel} \xB7 Ignore: ${ignoredAuthorsLabel} \xB7 Propagate: ${propagatedAgentsLabel}`;
|
|
26660
|
+
}
|
|
26595
26661
|
return `Assignee: ${assigneeLabel} \xB7 Status: ${statusLabel} \xB7 Ignore: ${ignoredAuthorsLabel}`;
|
|
26596
26662
|
}
|
|
26663
|
+
function resolveSavedTokenUiState(params) {
|
|
26664
|
+
if (params.githubTokenConfigured) {
|
|
26665
|
+
return {
|
|
26666
|
+
showSavedTokenHint: true,
|
|
26667
|
+
showTokenEditor: false,
|
|
26668
|
+
tokenStatusOverride: "valid",
|
|
26669
|
+
validatedLogin: normalizeOptionalText(params.githubTokenLogin)
|
|
26670
|
+
};
|
|
26671
|
+
}
|
|
26672
|
+
return {
|
|
26673
|
+
showSavedTokenHint: false,
|
|
26674
|
+
showTokenEditor: true,
|
|
26675
|
+
tokenStatusOverride: null,
|
|
26676
|
+
validatedLogin: null
|
|
26677
|
+
};
|
|
26678
|
+
}
|
|
26679
|
+
function formatAgentMultiSelectionLabel(values, options) {
|
|
26680
|
+
if (values.length === 0) {
|
|
26681
|
+
return "No agents selected";
|
|
26682
|
+
}
|
|
26683
|
+
const labels = values.map((value) => options.find((option) => option.value === value)?.label ?? "Unavailable agent").filter((label) => label.trim().length > 0);
|
|
26684
|
+
if (labels.length === 0) {
|
|
26685
|
+
return "No agents selected";
|
|
26686
|
+
}
|
|
26687
|
+
if (labels.length <= 2) {
|
|
26688
|
+
return labels.join(", ");
|
|
26689
|
+
}
|
|
26690
|
+
return `${labels.length} agents selected`;
|
|
26691
|
+
}
|
|
26597
26692
|
function PickerChevronIcon() {
|
|
26598
26693
|
return /* @__PURE__ */ jsx2("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx2("path", { d: "M4 6.5L8 10.5L12 6.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
26599
26694
|
}
|
|
@@ -26748,6 +26843,122 @@ function SettingsAssigneePicker(props) {
|
|
|
26748
26843
|
] }) : null
|
|
26749
26844
|
] });
|
|
26750
26845
|
}
|
|
26846
|
+
function SettingsAgentMultiPicker(props) {
|
|
26847
|
+
const { id, values, options, disabled, onChange } = props;
|
|
26848
|
+
const [open, setOpen] = useState2(false);
|
|
26849
|
+
const [query, setQuery] = useState2("");
|
|
26850
|
+
const rootRef = useRef(null);
|
|
26851
|
+
const searchInputRef = useRef(null);
|
|
26852
|
+
const selectedValues = normalizeAgentIds(values);
|
|
26853
|
+
const selectedValueSet = new Set(selectedValues);
|
|
26854
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
26855
|
+
const filteredOptions = normalizedQuery ? options.filter((option) => option.label.toLowerCase().includes(normalizedQuery)) : options;
|
|
26856
|
+
const selectedLabel = formatAgentMultiSelectionLabel(selectedValues, options);
|
|
26857
|
+
useEffect2(() => {
|
|
26858
|
+
if (!open) {
|
|
26859
|
+
setQuery("");
|
|
26860
|
+
return;
|
|
26861
|
+
}
|
|
26862
|
+
const handlePointerDown = (event) => {
|
|
26863
|
+
const target = event.target;
|
|
26864
|
+
if (target instanceof Node && rootRef.current?.contains(target)) {
|
|
26865
|
+
return;
|
|
26866
|
+
}
|
|
26867
|
+
setOpen(false);
|
|
26868
|
+
};
|
|
26869
|
+
const handleKeyDown = (event) => {
|
|
26870
|
+
if (event.key === "Escape") {
|
|
26871
|
+
setOpen(false);
|
|
26872
|
+
}
|
|
26873
|
+
};
|
|
26874
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
26875
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
26876
|
+
globalThis.setTimeout(() => {
|
|
26877
|
+
searchInputRef.current?.focus();
|
|
26878
|
+
searchInputRef.current?.select();
|
|
26879
|
+
}, 0);
|
|
26880
|
+
return () => {
|
|
26881
|
+
document.removeEventListener("pointerdown", handlePointerDown);
|
|
26882
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
26883
|
+
};
|
|
26884
|
+
}, [open]);
|
|
26885
|
+
useEffect2(() => {
|
|
26886
|
+
if (disabled && open) {
|
|
26887
|
+
setOpen(false);
|
|
26888
|
+
}
|
|
26889
|
+
}, [disabled, open]);
|
|
26890
|
+
return /* @__PURE__ */ jsxs2("div", { className: "ghsync__picker", ref: rootRef, children: [
|
|
26891
|
+
/* @__PURE__ */ jsxs2(
|
|
26892
|
+
"button",
|
|
26893
|
+
{
|
|
26894
|
+
id,
|
|
26895
|
+
type: "button",
|
|
26896
|
+
className: "ghsync__picker-trigger ghsync__picker-trigger--assignee",
|
|
26897
|
+
disabled,
|
|
26898
|
+
"aria-haspopup": "dialog",
|
|
26899
|
+
"aria-expanded": open,
|
|
26900
|
+
onClick: () => {
|
|
26901
|
+
if (disabled) {
|
|
26902
|
+
return;
|
|
26903
|
+
}
|
|
26904
|
+
setOpen((current) => !current);
|
|
26905
|
+
},
|
|
26906
|
+
children: [
|
|
26907
|
+
/* @__PURE__ */ jsxs2("span", { className: "ghsync__picker-trigger-main", children: [
|
|
26908
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__picker-agent-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(AgentIcon, {}) }),
|
|
26909
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__picker-trigger-label", children: selectedLabel })
|
|
26910
|
+
] }),
|
|
26911
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__picker-trigger-icon", children: /* @__PURE__ */ jsx2(PickerChevronIcon, {}) })
|
|
26912
|
+
]
|
|
26913
|
+
}
|
|
26914
|
+
),
|
|
26915
|
+
open ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__picker-panel ghsync__picker-panel--assignee", role: "dialog", "aria-label": "Choose agents", children: [
|
|
26916
|
+
/* @__PURE__ */ jsx2("div", { className: "ghsync__picker-search", children: /* @__PURE__ */ jsx2(
|
|
26917
|
+
"input",
|
|
26918
|
+
{
|
|
26919
|
+
ref: searchInputRef,
|
|
26920
|
+
type: "text",
|
|
26921
|
+
className: "ghsync__picker-search-input",
|
|
26922
|
+
placeholder: "Search agents...",
|
|
26923
|
+
value: query,
|
|
26924
|
+
onChange: (event) => {
|
|
26925
|
+
setQuery(event.currentTarget.value);
|
|
26926
|
+
},
|
|
26927
|
+
onKeyDown: (event) => {
|
|
26928
|
+
if (event.key === "Escape") {
|
|
26929
|
+
event.preventDefault();
|
|
26930
|
+
setOpen(false);
|
|
26931
|
+
}
|
|
26932
|
+
}
|
|
26933
|
+
}
|
|
26934
|
+
) }),
|
|
26935
|
+
/* @__PURE__ */ jsx2("div", { className: "ghsync__picker-list", role: "listbox", "aria-labelledby": id, "aria-multiselectable": "true", children: filteredOptions.length > 0 ? filteredOptions.map((option) => {
|
|
26936
|
+
const selected = selectedValueSet.has(option.value);
|
|
26937
|
+
return /* @__PURE__ */ jsxs2(
|
|
26938
|
+
"button",
|
|
26939
|
+
{
|
|
26940
|
+
type: "button",
|
|
26941
|
+
role: "option",
|
|
26942
|
+
"aria-selected": selected,
|
|
26943
|
+
className: `ghsync__picker-option${selected ? " ghsync__picker-option--selected" : ""}`,
|
|
26944
|
+
onClick: () => {
|
|
26945
|
+
const nextValues = selected ? selectedValues.filter((value) => value !== option.value) : normalizeAgentIds([...selectedValues, option.value]);
|
|
26946
|
+
onChange(nextValues);
|
|
26947
|
+
},
|
|
26948
|
+
children: [
|
|
26949
|
+
/* @__PURE__ */ jsxs2("span", { className: "ghsync__picker-trigger-main", children: [
|
|
26950
|
+
option.icon === "agent" ? /* @__PURE__ */ jsx2("span", { className: "ghsync__picker-agent-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(AgentIcon, {}) }) : null,
|
|
26951
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__picker-option-label", children: option.label })
|
|
26952
|
+
] }),
|
|
26953
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__picker-option-check", "aria-hidden": "true", children: selected ? /* @__PURE__ */ jsx2(PickerCheckIcon, {}) : null })
|
|
26954
|
+
]
|
|
26955
|
+
},
|
|
26956
|
+
option.value
|
|
26957
|
+
);
|
|
26958
|
+
}) : /* @__PURE__ */ jsx2("div", { className: "ghsync__picker-empty", children: "No agents match." }) })
|
|
26959
|
+
] }) : null
|
|
26960
|
+
] });
|
|
26961
|
+
}
|
|
26751
26962
|
function SettingsStatusPicker(props) {
|
|
26752
26963
|
const { id, value, options, disabled, onChange } = props;
|
|
26753
26964
|
const [open, setOpen] = useState2(false);
|
|
@@ -27678,6 +27889,117 @@ async function patchPluginConfig(pluginId, patch5) {
|
|
|
27678
27889
|
})
|
|
27679
27890
|
});
|
|
27680
27891
|
}
|
|
27892
|
+
var GITHUB_TOKEN_PROPAGATION_CONCURRENCY_LIMIT = 4;
|
|
27893
|
+
function normalizeAgentAdapterConfig(value) {
|
|
27894
|
+
return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
|
|
27895
|
+
}
|
|
27896
|
+
function normalizeAgentEnvBindings(value) {
|
|
27897
|
+
return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
|
|
27898
|
+
}
|
|
27899
|
+
function isMatchingSecretRefEnvBinding(value, secretId) {
|
|
27900
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
27901
|
+
return false;
|
|
27902
|
+
}
|
|
27903
|
+
const record = value;
|
|
27904
|
+
return record.type === "secret_ref" && record.secretId === secretId;
|
|
27905
|
+
}
|
|
27906
|
+
function getAgentPropagationPatch(params) {
|
|
27907
|
+
const adapterConfig = normalizeAgentAdapterConfig(params.adapterConfig);
|
|
27908
|
+
const currentEnv = normalizeAgentEnvBindings(adapterConfig.env);
|
|
27909
|
+
if (params.mode === "ensure") {
|
|
27910
|
+
const nextEnv2 = {
|
|
27911
|
+
...currentEnv,
|
|
27912
|
+
GITHUB_TOKEN: {
|
|
27913
|
+
type: "secret_ref",
|
|
27914
|
+
secretId: params.githubTokenSecretRef
|
|
27915
|
+
}
|
|
27916
|
+
};
|
|
27917
|
+
if (JSON.stringify(nextEnv2) === JSON.stringify(currentEnv)) {
|
|
27918
|
+
return null;
|
|
27919
|
+
}
|
|
27920
|
+
return {
|
|
27921
|
+
...adapterConfig,
|
|
27922
|
+
env: nextEnv2
|
|
27923
|
+
};
|
|
27924
|
+
}
|
|
27925
|
+
if (!isMatchingSecretRefEnvBinding(currentEnv.GITHUB_TOKEN, params.githubTokenSecretRef)) {
|
|
27926
|
+
return null;
|
|
27927
|
+
}
|
|
27928
|
+
const nextEnv = { ...currentEnv };
|
|
27929
|
+
delete nextEnv.GITHUB_TOKEN;
|
|
27930
|
+
const nextAdapterConfig = {
|
|
27931
|
+
...adapterConfig
|
|
27932
|
+
};
|
|
27933
|
+
if (Object.keys(nextEnv).length > 0) {
|
|
27934
|
+
nextAdapterConfig.env = nextEnv;
|
|
27935
|
+
} else {
|
|
27936
|
+
delete nextAdapterConfig.env;
|
|
27937
|
+
}
|
|
27938
|
+
return nextAdapterConfig;
|
|
27939
|
+
}
|
|
27940
|
+
async function runWithConcurrencyLimit(items, concurrencyLimit, worker) {
|
|
27941
|
+
if (items.length === 0) {
|
|
27942
|
+
return;
|
|
27943
|
+
}
|
|
27944
|
+
let nextIndex = 0;
|
|
27945
|
+
const runnerCount = Math.min(concurrencyLimit, items.length);
|
|
27946
|
+
await Promise.all(
|
|
27947
|
+
Array.from({ length: runnerCount }, async () => {
|
|
27948
|
+
while (nextIndex < items.length) {
|
|
27949
|
+
const currentIndex = nextIndex;
|
|
27950
|
+
nextIndex += 1;
|
|
27951
|
+
await worker(items[currentIndex]);
|
|
27952
|
+
}
|
|
27953
|
+
})
|
|
27954
|
+
);
|
|
27955
|
+
}
|
|
27956
|
+
async function applyGitHubTokenPropagationUpdate(params) {
|
|
27957
|
+
const agent = await fetchJson(`/api/agents/${params.agentId}`);
|
|
27958
|
+
const nextAdapterConfig = getAgentPropagationPatch({
|
|
27959
|
+
adapterConfig: agent?.adapterConfig,
|
|
27960
|
+
githubTokenSecretRef: params.githubTokenSecretRef,
|
|
27961
|
+
mode: params.mode
|
|
27962
|
+
});
|
|
27963
|
+
if (!nextAdapterConfig) {
|
|
27964
|
+
return;
|
|
27965
|
+
}
|
|
27966
|
+
await fetchJson(`/api/agents/${params.agentId}`, {
|
|
27967
|
+
method: "PATCH",
|
|
27968
|
+
body: JSON.stringify({
|
|
27969
|
+
adapterConfig: nextAdapterConfig
|
|
27970
|
+
})
|
|
27971
|
+
});
|
|
27972
|
+
}
|
|
27973
|
+
async function syncGitHubTokenPropagationForAgents(params) {
|
|
27974
|
+
const selectedAgentIds = normalizeAgentIds(params.selectedAgentIds);
|
|
27975
|
+
const selectedAgentIdSet = new Set(selectedAgentIds);
|
|
27976
|
+
const previousAgentIds = normalizeAgentIds(params.previousAgentIds);
|
|
27977
|
+
const failures = /* @__PURE__ */ new Set();
|
|
27978
|
+
const operations = [
|
|
27979
|
+
...selectedAgentIds.map((agentId) => ({ agentId, mode: "ensure" })),
|
|
27980
|
+
...previousAgentIds.filter((agentId) => !selectedAgentIdSet.has(agentId)).map((agentId) => ({ agentId, mode: "remove" }))
|
|
27981
|
+
];
|
|
27982
|
+
await runWithConcurrencyLimit(
|
|
27983
|
+
operations,
|
|
27984
|
+
GITHUB_TOKEN_PROPAGATION_CONCURRENCY_LIMIT,
|
|
27985
|
+
async (operation) => {
|
|
27986
|
+
try {
|
|
27987
|
+
await applyGitHubTokenPropagationUpdate({
|
|
27988
|
+
agentId: operation.agentId,
|
|
27989
|
+
githubTokenSecretRef: params.githubTokenSecretRef,
|
|
27990
|
+
mode: operation.mode
|
|
27991
|
+
});
|
|
27992
|
+
} catch {
|
|
27993
|
+
failures.add(operation.agentId);
|
|
27994
|
+
}
|
|
27995
|
+
}
|
|
27996
|
+
);
|
|
27997
|
+
if (failures.size > 0) {
|
|
27998
|
+
throw new Error(
|
|
27999
|
+
`GitHub token propagation could not update these agents: ${[...failures].join(", ")}.`
|
|
28000
|
+
);
|
|
28001
|
+
}
|
|
28002
|
+
}
|
|
27681
28003
|
function normalizeCliAuthPollIntervalMs(value) {
|
|
27682
28004
|
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
27683
28005
|
return CLI_AUTH_POLL_INTERVAL_FALLBACK_MS;
|
|
@@ -30765,6 +31087,7 @@ function GitHubSyncSettingsPage() {
|
|
|
30765
31087
|
const themeMode = useResolvedThemeMode();
|
|
30766
31088
|
const boardAccessRequirement = usePaperclipBoardAccessRequirement();
|
|
30767
31089
|
const armSyncCompletionToast = useSyncCompletionToast(form.syncState, toast);
|
|
31090
|
+
const githubTokenConfigSyncAttemptRef = useRef(null);
|
|
30768
31091
|
const boardAccessConfigSyncAttemptRef = useRef(null);
|
|
30769
31092
|
const assigneeFallbackAttemptRef = useRef(null);
|
|
30770
31093
|
const currentSettings = settings.data ?? cachedSettings;
|
|
@@ -30778,6 +31101,11 @@ function GitHubSyncSettingsPage() {
|
|
|
30778
31101
|
if (!settings.data) {
|
|
30779
31102
|
return;
|
|
30780
31103
|
}
|
|
31104
|
+
const tokenUiState = resolveSavedTokenUiState({
|
|
31105
|
+
githubTokenConfigured: settings.data.githubTokenConfigured,
|
|
31106
|
+
githubTokenLogin: settings.data.githubTokenLogin
|
|
31107
|
+
});
|
|
31108
|
+
const savedBoardAccessIdentity = typeof settings.data.paperclipBoardAccessIdentity === "string" && settings.data.paperclipBoardAccessIdentity.trim() ? settings.data.paperclipBoardAccessIdentity.trim() : null;
|
|
30781
31109
|
const nextScheduleFrequencyMinutes = normalizeScheduleFrequencyMinutes(settings.data.scheduleFrequencyMinutes);
|
|
30782
31110
|
setForm({
|
|
30783
31111
|
mappings: settings.data.mappings ?? [],
|
|
@@ -30794,18 +31122,12 @@ function GitHubSyncSettingsPage() {
|
|
|
30794
31122
|
setScheduleFrequencyDraft(String(nextScheduleFrequencyMinutes));
|
|
30795
31123
|
setIgnoredAuthorsDraft(normalizeAdvancedSettings(settings.data.advancedSettings).ignoredIssueAuthorUsernames.join(", "));
|
|
30796
31124
|
setTokenDraft("");
|
|
30797
|
-
|
|
30798
|
-
|
|
30799
|
-
|
|
30800
|
-
|
|
30801
|
-
|
|
30802
|
-
|
|
30803
|
-
setTokenStatusOverride("valid");
|
|
30804
|
-
} else if (!showSavedTokenHint) {
|
|
30805
|
-
setShowTokenEditor(true);
|
|
30806
|
-
setValidatedLogin(null);
|
|
30807
|
-
}
|
|
30808
|
-
}, [settings.data, showSavedTokenHint]);
|
|
31125
|
+
setValidatedLogin(tokenUiState.validatedLogin);
|
|
31126
|
+
setBoardAccessIdentity(settings.data.paperclipBoardAccessConfigured ? savedBoardAccessIdentity : null);
|
|
31127
|
+
setShowSavedTokenHint(tokenUiState.showSavedTokenHint);
|
|
31128
|
+
setShowTokenEditor(tokenUiState.showTokenEditor);
|
|
31129
|
+
setTokenStatusOverride(tokenUiState.tokenStatusOverride);
|
|
31130
|
+
}, [settings.data]);
|
|
30809
31131
|
useEffect2(() => {
|
|
30810
31132
|
const companyId = hostContext.companyId;
|
|
30811
31133
|
if (!companyId || tokenStatusOverride === "invalid") {
|
|
@@ -30879,6 +31201,75 @@ function GitHubSyncSettingsPage() {
|
|
|
30879
31201
|
cancelled = true;
|
|
30880
31202
|
};
|
|
30881
31203
|
}, [currentSettings?.availableAssignees?.length, currentSettings?.updatedAt, hostContext.companyId]);
|
|
31204
|
+
useEffect2(() => {
|
|
31205
|
+
const companyId = hostContext.companyId;
|
|
31206
|
+
const secretRef = settings.data?.githubTokenNeedsConfigSync ? settings.data.githubTokenConfigSyncRef : void 0;
|
|
31207
|
+
if (!companyId || !secretRef) {
|
|
31208
|
+
return;
|
|
31209
|
+
}
|
|
31210
|
+
const attemptKey = `${companyId}:${secretRef}`;
|
|
31211
|
+
if (githubTokenConfigSyncAttemptRef.current === attemptKey) {
|
|
31212
|
+
return;
|
|
31213
|
+
}
|
|
31214
|
+
githubTokenConfigSyncAttemptRef.current = attemptKey;
|
|
31215
|
+
let cancelled = false;
|
|
31216
|
+
void (async () => {
|
|
31217
|
+
try {
|
|
31218
|
+
const pluginId = await resolveCurrentPluginId(pluginIdFromLocation);
|
|
31219
|
+
if (!pluginId) {
|
|
31220
|
+
throw new Error("Plugin id is required to finish syncing the GitHub token secret into plugin config.");
|
|
31221
|
+
}
|
|
31222
|
+
await patchPluginConfig(pluginId, {
|
|
31223
|
+
githubTokenRefs: {
|
|
31224
|
+
[companyId]: secretRef
|
|
31225
|
+
}
|
|
31226
|
+
});
|
|
31227
|
+
if (cancelled) {
|
|
31228
|
+
return;
|
|
31229
|
+
}
|
|
31230
|
+
const selectedAgentIds = normalizeAgentIds(settings.data?.advancedSettings?.githubTokenPropagationAgentIds);
|
|
31231
|
+
if (selectedAgentIds.length > 0) {
|
|
31232
|
+
try {
|
|
31233
|
+
await propagateGitHubTokenToSelectedAgents({
|
|
31234
|
+
selectedAgentIds,
|
|
31235
|
+
previousAgentIds: selectedAgentIds,
|
|
31236
|
+
githubTokenSecretRef: secretRef
|
|
31237
|
+
});
|
|
31238
|
+
} catch {
|
|
31239
|
+
}
|
|
31240
|
+
}
|
|
31241
|
+
notifyGitHubSyncSettingsChanged();
|
|
31242
|
+
try {
|
|
31243
|
+
await settings.refresh();
|
|
31244
|
+
} catch {
|
|
31245
|
+
return;
|
|
31246
|
+
}
|
|
31247
|
+
} catch (error) {
|
|
31248
|
+
if (cancelled) {
|
|
31249
|
+
return;
|
|
31250
|
+
}
|
|
31251
|
+
toast({
|
|
31252
|
+
title: "GitHub token needs reconnection",
|
|
31253
|
+
body: getActionErrorMessage(
|
|
31254
|
+
error,
|
|
31255
|
+
"GitHub Sync could not finish migrating the saved GitHub token secret into plugin config."
|
|
31256
|
+
),
|
|
31257
|
+
tone: "error"
|
|
31258
|
+
});
|
|
31259
|
+
}
|
|
31260
|
+
})();
|
|
31261
|
+
return () => {
|
|
31262
|
+
cancelled = true;
|
|
31263
|
+
};
|
|
31264
|
+
}, [
|
|
31265
|
+
hostContext.companyId,
|
|
31266
|
+
pluginIdFromLocation,
|
|
31267
|
+
settings.data?.advancedSettings?.githubTokenPropagationAgentIds,
|
|
31268
|
+
settings.data?.githubTokenConfigSyncRef,
|
|
31269
|
+
settings.data?.githubTokenNeedsConfigSync,
|
|
31270
|
+
settings.refresh,
|
|
31271
|
+
toast
|
|
31272
|
+
]);
|
|
30882
31273
|
useEffect2(() => {
|
|
30883
31274
|
const companyId = hostContext.companyId;
|
|
30884
31275
|
const secretRef = settings.data?.paperclipBoardAccessNeedsConfigSync ? settings.data.paperclipBoardAccessConfigSyncRef : void 0;
|
|
@@ -31006,6 +31397,7 @@ function GitHubSyncSettingsPage() {
|
|
|
31006
31397
|
const hasSavedToken = Boolean(form.githubTokenConfigured || showSavedTokenHint);
|
|
31007
31398
|
const boardAccessConfigured = Boolean(form.paperclipBoardAccessConfigured);
|
|
31008
31399
|
const boardAccessRequired = boardAccessRequirement.required;
|
|
31400
|
+
const boardAccessVisible = boardAccessRequirement.visible;
|
|
31009
31401
|
const boardAccessReady = !boardAccessRequired || hasCompanyContext && boardAccessConfigured;
|
|
31010
31402
|
const tokenStatus = tokenStatusOverride ?? (hasSavedToken ? "valid" : "required");
|
|
31011
31403
|
const tokenTone = tokenStatus === "valid" ? "success" : tokenStatus === "invalid" ? "danger" : "warning";
|
|
@@ -31028,6 +31420,10 @@ function GitHubSyncSettingsPage() {
|
|
|
31028
31420
|
(currentSettings?.availableAssignees?.length ? currentSettings.availableAssignees : null) ?? (form.availableAssignees?.length ? form.availableAssignees : null) ?? browserAvailableAssignees,
|
|
31029
31421
|
form.advancedSettings.defaultAssigneeAgentId
|
|
31030
31422
|
);
|
|
31423
|
+
const propagationAgents = getAvailablePropagationAgentOptions(
|
|
31424
|
+
(currentSettings?.availableAssignees?.length ? currentSettings.availableAssignees : null) ?? (form.availableAssignees?.length ? form.availableAssignees : null) ?? browserAvailableAssignees,
|
|
31425
|
+
form.advancedSettings.githubTokenPropagationAgentIds
|
|
31426
|
+
);
|
|
31031
31427
|
const savedMappingsSource = currentSettings ? currentSettings.mappings ?? [] : form.mappings;
|
|
31032
31428
|
const savedMappings = getComparableMappings(savedMappingsSource);
|
|
31033
31429
|
const draftMappings = getComparableMappings(form.mappings);
|
|
@@ -31069,7 +31465,7 @@ function GitHubSyncSettingsPage() {
|
|
|
31069
31465
|
const canConnectBoardAccess = hasCompanyContext && !settingsMutationsLocked && !connectingBoardAccess && !showInitialLoadingState;
|
|
31070
31466
|
const boardAccessStatusLabel = !hasCompanyContext ? "Unavailable" : boardAccessBannerLabel;
|
|
31071
31467
|
const boardAccessStatusTone = !hasCompanyContext ? boardAccessRequired ? "warning" : "neutral" : boardAccessTone;
|
|
31072
|
-
const boardAccessSummaryText = !hasCompanyContext ? boardAccessRequired ? "Select a company." : "Select a company." : connectingBoardAccess ? "Approval in progress." : boardAccessConfigured ? "Connected." : boardAccessRequired ? "Required for sync." : boardAccessRequirement.status === "loading" ? "Checking requirement." : "Optional.";
|
|
31468
|
+
const boardAccessSummaryText = !hasCompanyContext ? boardAccessRequired ? "Select a company." : "Select a company." : connectingBoardAccess ? "Approval in progress." : boardAccessConfigured ? boardAccessIdentity ? `Connected as ${boardAccessIdentity}.` : "Connected." : boardAccessRequired ? "Required for sync." : boardAccessRequirement.status === "loading" ? "Checking requirement." : "Optional.";
|
|
31073
31469
|
const showTokenForm = tokenStatus !== "valid" || showTokenEditor;
|
|
31074
31470
|
const lastUpdated = formatDate(form.updatedAt ?? currentSettings?.updatedAt, "Not saved yet");
|
|
31075
31471
|
const lastSync = formatDate(displaySyncState.checkedAt, "Never");
|
|
@@ -31095,7 +31491,9 @@ function GitHubSyncSettingsPage() {
|
|
|
31095
31491
|
const manualSyncScopePillClass = hasCompanyContext ? "ghsync__scope-pill ghsync__scope-pill--company" : "ghsync__scope-pill ghsync__scope-pill--mixed";
|
|
31096
31492
|
const manualSyncScopePillLabel = hasCompanyContext ? "This company" : "All companies";
|
|
31097
31493
|
const manualSyncButtonLabel = hasCompanyContext ? "Run sync for this company" : "Run sync across all companies";
|
|
31098
|
-
const advancedSettingsSummary = formatAdvancedSettingsSummary(form.advancedSettings, availableAssignees
|
|
31494
|
+
const advancedSettingsSummary = formatAdvancedSettingsSummary(form.advancedSettings, availableAssignees, {
|
|
31495
|
+
includePropagation: boardAccessVisible
|
|
31496
|
+
});
|
|
31099
31497
|
const assigneeSelectOptions = [
|
|
31100
31498
|
{ value: "", label: "Unassigned" },
|
|
31101
31499
|
...availableAssignees.map((option) => ({
|
|
@@ -31104,6 +31502,11 @@ function GitHubSyncSettingsPage() {
|
|
|
31104
31502
|
icon: "agent"
|
|
31105
31503
|
}))
|
|
31106
31504
|
];
|
|
31505
|
+
const propagationAgentOptions = propagationAgents.map((option) => ({
|
|
31506
|
+
value: option.id,
|
|
31507
|
+
label: formatAssigneeOptionLabel(option),
|
|
31508
|
+
icon: "agent"
|
|
31509
|
+
}));
|
|
31107
31510
|
const statusSelectOptions = PAPERCLIP_STATUS_OPTIONS.map((option) => ({
|
|
31108
31511
|
value: option.value,
|
|
31109
31512
|
label: option.label,
|
|
@@ -31234,6 +31637,37 @@ function GitHubSyncSettingsPage() {
|
|
|
31234
31637
|
};
|
|
31235
31638
|
});
|
|
31236
31639
|
}
|
|
31640
|
+
async function propagateGitHubTokenToSelectedAgents(options) {
|
|
31641
|
+
if (!boardAccessVisible) {
|
|
31642
|
+
return;
|
|
31643
|
+
}
|
|
31644
|
+
const selectedAgentIds = normalizeAgentIds(options.selectedAgentIds);
|
|
31645
|
+
const previousAgentIds = normalizeAgentIds(options.previousAgentIds);
|
|
31646
|
+
if (selectedAgentIds.length === 0 && previousAgentIds.length === 0) {
|
|
31647
|
+
return;
|
|
31648
|
+
}
|
|
31649
|
+
let githubTokenSecretRef = typeof options.githubTokenSecretRef === "string" && options.githubTokenSecretRef.trim() ? options.githubTokenSecretRef.trim() : void 0;
|
|
31650
|
+
if (!githubTokenSecretRef) {
|
|
31651
|
+
const companyId = hostContext.companyId;
|
|
31652
|
+
if (!companyId) {
|
|
31653
|
+
throw new Error("Company context is required to propagate the GitHub token to selected agents.");
|
|
31654
|
+
}
|
|
31655
|
+
const pluginId = await resolveCurrentPluginId(pluginIdFromLocation);
|
|
31656
|
+
if (!pluginId) {
|
|
31657
|
+
throw new Error("Plugin id is required to propagate the GitHub token to selected agents.");
|
|
31658
|
+
}
|
|
31659
|
+
const currentConfigResponse = await fetchJson(`/api/plugins/${pluginId}/config`);
|
|
31660
|
+
githubTokenSecretRef = normalizePluginConfig(currentConfigResponse?.configJson).githubTokenRefs?.[companyId];
|
|
31661
|
+
}
|
|
31662
|
+
if (!githubTokenSecretRef) {
|
|
31663
|
+
throw new Error("GitHub token propagation requires a GitHub token saved through this settings page.");
|
|
31664
|
+
}
|
|
31665
|
+
await syncGitHubTokenPropagationForAgents({
|
|
31666
|
+
githubTokenSecretRef,
|
|
31667
|
+
selectedAgentIds,
|
|
31668
|
+
previousAgentIds
|
|
31669
|
+
});
|
|
31670
|
+
}
|
|
31237
31671
|
async function handleSaveToken(event) {
|
|
31238
31672
|
event.preventDefault();
|
|
31239
31673
|
setSubmittingToken(true);
|
|
@@ -31273,12 +31707,26 @@ function GitHubSyncSettingsPage() {
|
|
|
31273
31707
|
const secretName = `github_sync_${companyId.replace(/[^a-z0-9]+/gi, "_").toLowerCase()}`;
|
|
31274
31708
|
const secret = await resolveOrCreateCompanySecret(companyId, secretName, trimmedToken);
|
|
31275
31709
|
await patchPluginConfig(pluginId, {
|
|
31276
|
-
|
|
31710
|
+
githubTokenRefs: {
|
|
31711
|
+
[companyId]: secret.id
|
|
31712
|
+
}
|
|
31277
31713
|
});
|
|
31278
31714
|
await saveRegistration({
|
|
31279
31715
|
companyId,
|
|
31280
|
-
githubTokenRef: secret.id
|
|
31716
|
+
githubTokenRef: secret.id,
|
|
31717
|
+
githubTokenLogin: validation.login
|
|
31281
31718
|
});
|
|
31719
|
+
const selectedAgentIds = normalizeAgentIds(currentSettings?.advancedSettings?.githubTokenPropagationAgentIds);
|
|
31720
|
+
let propagationError = null;
|
|
31721
|
+
try {
|
|
31722
|
+
await propagateGitHubTokenToSelectedAgents({
|
|
31723
|
+
selectedAgentIds,
|
|
31724
|
+
previousAgentIds: selectedAgentIds,
|
|
31725
|
+
githubTokenSecretRef: secret.id
|
|
31726
|
+
});
|
|
31727
|
+
} catch (error) {
|
|
31728
|
+
propagationError = error;
|
|
31729
|
+
}
|
|
31282
31730
|
setForm((current) => ({
|
|
31283
31731
|
...current,
|
|
31284
31732
|
githubTokenConfigured: true
|
|
@@ -31293,6 +31741,16 @@ function GitHubSyncSettingsPage() {
|
|
|
31293
31741
|
body: "Token saved.",
|
|
31294
31742
|
tone: "success"
|
|
31295
31743
|
});
|
|
31744
|
+
if (propagationError) {
|
|
31745
|
+
toast({
|
|
31746
|
+
title: "GitHub token saved, but agent propagation needs attention",
|
|
31747
|
+
body: getActionErrorMessage(
|
|
31748
|
+
propagationError,
|
|
31749
|
+
"GitHub Sync could not update the selected agents with the saved token."
|
|
31750
|
+
),
|
|
31751
|
+
tone: "error"
|
|
31752
|
+
});
|
|
31753
|
+
}
|
|
31296
31754
|
notifyGitHubSyncSettingsChanged();
|
|
31297
31755
|
try {
|
|
31298
31756
|
await settings.refresh();
|
|
@@ -31348,7 +31806,8 @@ function GitHubSyncSettingsPage() {
|
|
|
31348
31806
|
});
|
|
31349
31807
|
await updateBoardAccess({
|
|
31350
31808
|
companyId,
|
|
31351
|
-
paperclipBoardApiTokenRef: secret.id
|
|
31809
|
+
paperclipBoardApiTokenRef: secret.id,
|
|
31810
|
+
paperclipBoardAccessIdentity: identity ?? ""
|
|
31352
31811
|
});
|
|
31353
31812
|
setBoardAccessIdentity(identity);
|
|
31354
31813
|
setForm((current) => ({
|
|
@@ -31428,6 +31887,15 @@ function GitHubSyncSettingsPage() {
|
|
|
31428
31887
|
scheduleFrequencyMinutes,
|
|
31429
31888
|
...trustedPaperclipApiBaseUrl ? { paperclipApiBaseUrl: trustedPaperclipApiBaseUrl } : {}
|
|
31430
31889
|
});
|
|
31890
|
+
let propagationError = null;
|
|
31891
|
+
try {
|
|
31892
|
+
await propagateGitHubTokenToSelectedAgents({
|
|
31893
|
+
selectedAgentIds: normalizeAgentIds(normalizeAdvancedSettings(result.advancedSettings).githubTokenPropagationAgentIds),
|
|
31894
|
+
previousAgentIds: normalizeAgentIds(currentSettings?.advancedSettings?.githubTokenPropagationAgentIds)
|
|
31895
|
+
});
|
|
31896
|
+
} catch (error) {
|
|
31897
|
+
propagationError = error;
|
|
31898
|
+
}
|
|
31431
31899
|
setForm((current) => ({
|
|
31432
31900
|
...current,
|
|
31433
31901
|
mappings: result.mappings.length > 0 ? result.mappings : [createEmptyMapping(0)],
|
|
@@ -31444,6 +31912,16 @@ function GitHubSyncSettingsPage() {
|
|
|
31444
31912
|
body: `Advanced defaults, mappings, and automatic sync are saved for ${currentCompanyName}.`,
|
|
31445
31913
|
tone: "success"
|
|
31446
31914
|
});
|
|
31915
|
+
if (propagationError) {
|
|
31916
|
+
toast({
|
|
31917
|
+
title: "Settings saved, but agent propagation needs attention",
|
|
31918
|
+
body: getActionErrorMessage(
|
|
31919
|
+
propagationError,
|
|
31920
|
+
"GitHub Sync could not apply the selected agent token propagation updates."
|
|
31921
|
+
),
|
|
31922
|
+
tone: "error"
|
|
31923
|
+
});
|
|
31924
|
+
}
|
|
31447
31925
|
notifyGitHubSyncSettingsChanged();
|
|
31448
31926
|
try {
|
|
31449
31927
|
await settings.refresh();
|
|
@@ -31685,7 +32163,7 @@ function GitHubSyncSettingsPage() {
|
|
|
31685
32163
|
/* @__PURE__ */ jsx2("div", { className: "ghsync__permission-audit-list", children: /* @__PURE__ */ jsx2("div", { className: "ghsync__permission-audit-item", children: /* @__PURE__ */ jsx2("span", { children: tokenPermissionAuditData?.warnings[0] ?? "Add a mapped repository in this company so GitHub Sync can verify the token permissions it needs." }) }) })
|
|
31686
32164
|
] }) : null
|
|
31687
32165
|
] }),
|
|
31688
|
-
/* @__PURE__ */ jsxs2("section", { className: "ghsync__section", children: [
|
|
32166
|
+
boardAccessVisible ? /* @__PURE__ */ jsxs2("section", { className: "ghsync__section", children: [
|
|
31689
32167
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-head", children: [
|
|
31690
32168
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-copy", children: [
|
|
31691
32169
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-title-row", children: [
|
|
@@ -31699,7 +32177,7 @@ function GitHubSyncSettingsPage() {
|
|
|
31699
32177
|
hostContext.companyId ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__connected", children: [
|
|
31700
32178
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
31701
32179
|
/* @__PURE__ */ jsx2("strong", { children: boardAccessConfigured ? boardAccessIdentity ? `Connected as ${boardAccessIdentity}` : "Connected" : boardAccessRequired ? "Required" : boardAccessRequirement.status === "loading" ? "Checking requirement" : "Optional" }),
|
|
31702
|
-
/* @__PURE__ */ jsx2("span", { children: boardAccessConfigured ? "Used for Paperclip API calls." : boardAccessRequired ? "Required in authenticated deployments." : boardAccessRequirement.status === "loading" ? "Checking whether it is required." : "
|
|
32180
|
+
/* @__PURE__ */ jsx2("span", { children: boardAccessConfigured ? "Used for Paperclip API calls." : boardAccessRequired ? "Required in authenticated deployments." : boardAccessRequirement.status === "loading" ? "Checking whether it is required." : "Available here for local testing and only required when Paperclip API calls need sign-in." })
|
|
31703
32181
|
] }),
|
|
31704
32182
|
/* @__PURE__ */ jsx2(
|
|
31705
32183
|
"button",
|
|
@@ -31727,7 +32205,7 @@ function GitHubSyncSettingsPage() {
|
|
|
31727
32205
|
] }),
|
|
31728
32206
|
/* @__PURE__ */ jsx2("span", { className: "ghsync__badge ghsync__badge--neutral", children: "Unavailable" })
|
|
31729
32207
|
] })
|
|
31730
|
-
] }),
|
|
32208
|
+
] }) : null,
|
|
31731
32209
|
/* @__PURE__ */ jsxs2("section", { className: "ghsync__section", children: [
|
|
31732
32210
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-head", children: [
|
|
31733
32211
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-copy", children: [
|
|
@@ -31954,7 +32432,29 @@ function GitHubSyncSettingsPage() {
|
|
|
31954
32432
|
}
|
|
31955
32433
|
),
|
|
31956
32434
|
/* @__PURE__ */ jsx2("p", { className: "ghsync__hint", children: "Comma or newline separated." })
|
|
31957
|
-
] })
|
|
32435
|
+
] }),
|
|
32436
|
+
boardAccessVisible ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__field", children: [
|
|
32437
|
+
/* @__PURE__ */ jsx2("label", { htmlFor: "advanced-token-propagation", children: "Propagate GitHub token to agents" }),
|
|
32438
|
+
/* @__PURE__ */ jsx2(
|
|
32439
|
+
SettingsAgentMultiPicker,
|
|
32440
|
+
{
|
|
32441
|
+
id: "advanced-token-propagation",
|
|
32442
|
+
values: form.advancedSettings.githubTokenPropagationAgentIds ?? [],
|
|
32443
|
+
options: propagationAgentOptions,
|
|
32444
|
+
disabled: settingsMutationsLocked || tokenStatus !== "valid",
|
|
32445
|
+
onChange: (nextValues) => {
|
|
32446
|
+
setForm((current) => ({
|
|
32447
|
+
...current,
|
|
32448
|
+
advancedSettings: {
|
|
32449
|
+
...current.advancedSettings,
|
|
32450
|
+
...nextValues.length > 0 ? { githubTokenPropagationAgentIds: nextValues } : { githubTokenPropagationAgentIds: void 0 }
|
|
32451
|
+
}
|
|
32452
|
+
}));
|
|
32453
|
+
}
|
|
32454
|
+
}
|
|
32455
|
+
),
|
|
32456
|
+
/* @__PURE__ */ jsx2("p", { className: "ghsync__hint", children: tokenStatus === "valid" ? "Selected agents receive `GITHUB_TOKEN` from the saved GitHub secret when you save settings." : "Save a valid GitHub token before choosing agents to propagate it to." })
|
|
32457
|
+
] }) : null
|
|
31958
32458
|
] }) : null
|
|
31959
32459
|
] }),
|
|
31960
32460
|
/* @__PURE__ */ jsxs2("section", { className: "ghsync__section", children: [
|
|
@@ -32107,13 +32607,13 @@ function GitHubSyncSettingsPage() {
|
|
|
32107
32607
|
] }),
|
|
32108
32608
|
/* @__PURE__ */ jsx2("span", { children: !repositoriesUnlocked ? "Requires a token." : savedMappingCount > 0 ? hasCompanyContext ? `${savedMappingCount} saved.` : `${savedMappingCount} saved.` : hasCompanyContext ? "Add a repository." : "Select a company." })
|
|
32109
32609
|
] }),
|
|
32110
|
-
/* @__PURE__ */ jsxs2("div", { className: "ghsync__check", children: [
|
|
32610
|
+
boardAccessVisible ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__check", children: [
|
|
32111
32611
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__check-top", children: [
|
|
32112
32612
|
/* @__PURE__ */ jsx2("strong", { children: "Paperclip board access" }),
|
|
32113
32613
|
/* @__PURE__ */ jsx2("span", { className: `ghsync__badge ${getToneClass(boardAccessStatusTone)}`, children: boardAccessStatusLabel })
|
|
32114
32614
|
] }),
|
|
32115
32615
|
/* @__PURE__ */ jsx2("span", { children: boardAccessSummaryText })
|
|
32116
|
-
] }),
|
|
32616
|
+
] }) : null,
|
|
32117
32617
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__check", children: [
|
|
32118
32618
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__check-top", children: [
|
|
32119
32619
|
/* @__PURE__ */ jsx2("strong", { children: "Sync" }),
|
|
@@ -33123,6 +33623,8 @@ export {
|
|
|
33123
33623
|
GitHubSyncProjectPullRequestsSidebarItem,
|
|
33124
33624
|
GitHubSyncSettingsPage,
|
|
33125
33625
|
index_default as default,
|
|
33126
|
-
resolveOrCreateProject
|
|
33626
|
+
resolveOrCreateProject,
|
|
33627
|
+
resolveSavedTokenUiState,
|
|
33628
|
+
syncGitHubTokenPropagationForAgents
|
|
33127
33629
|
};
|
|
33128
33630
|
//# sourceMappingURL=index.js.map
|