paperclip-github-plugin 0.3.6 → 0.4.0
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 +15 -7
- package/dist/manifest.js +1 -1
- package/dist/ui/index.js +412 -25
- package/dist/ui/index.js.map +3 -3
- package/dist/worker.js +64 -5
- package/package.json +1 -1
package/dist/ui/index.js
CHANGED
|
@@ -26535,12 +26535,21 @@ function normalizeGitHubUsername(value) {
|
|
|
26535
26535
|
const trimmed = value.trim().replace(/^@+/, "").toLowerCase();
|
|
26536
26536
|
return trimmed ? trimmed : null;
|
|
26537
26537
|
}
|
|
26538
|
+
function normalizeOptionalText(value) {
|
|
26539
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
26540
|
+
}
|
|
26538
26541
|
function normalizeIgnoredIssueAuthorUsernames(value) {
|
|
26539
26542
|
const rawEntries = Array.isArray(value) ? value : typeof value === "string" ? value.split(/[\s,]+/g) : [];
|
|
26540
26543
|
return [...new Set(
|
|
26541
26544
|
rawEntries.map((entry) => typeof entry === "string" ? normalizeGitHubUsername(entry) : null).filter((entry) => Boolean(entry))
|
|
26542
26545
|
)];
|
|
26543
26546
|
}
|
|
26547
|
+
function normalizeAgentIds(value) {
|
|
26548
|
+
const rawEntries = Array.isArray(value) ? value : [];
|
|
26549
|
+
return [...new Set(
|
|
26550
|
+
rawEntries.map((entry) => typeof entry === "string" && entry.trim() ? entry.trim() : null).filter((entry) => Boolean(entry))
|
|
26551
|
+
)].sort((left, right) => left.localeCompare(right));
|
|
26552
|
+
}
|
|
26544
26553
|
function normalizeAdvancedSettings(value) {
|
|
26545
26554
|
if (!value || typeof value !== "object") {
|
|
26546
26555
|
return DEFAULT_ADVANCED_SETTINGS;
|
|
@@ -26550,7 +26559,8 @@ function normalizeAdvancedSettings(value) {
|
|
|
26550
26559
|
return {
|
|
26551
26560
|
...defaultAssigneeAgentId ? { defaultAssigneeAgentId } : {},
|
|
26552
26561
|
defaultStatus: normalizePaperclipIssueStatus(record.defaultStatus),
|
|
26553
|
-
ignoredIssueAuthorUsernames: "ignoredIssueAuthorUsernames" in record ? normalizeIgnoredIssueAuthorUsernames(record.ignoredIssueAuthorUsernames) : DEFAULT_ADVANCED_SETTINGS.ignoredIssueAuthorUsernames
|
|
26562
|
+
ignoredIssueAuthorUsernames: "ignoredIssueAuthorUsernames" in record ? normalizeIgnoredIssueAuthorUsernames(record.ignoredIssueAuthorUsernames) : DEFAULT_ADVANCED_SETTINGS.ignoredIssueAuthorUsernames,
|
|
26563
|
+
...normalizeAgentIds(record.githubTokenPropagationAgentIds).length > 0 ? { githubTokenPropagationAgentIds: normalizeAgentIds(record.githubTokenPropagationAgentIds) } : {}
|
|
26554
26564
|
};
|
|
26555
26565
|
}
|
|
26556
26566
|
function getComparableMappings(mappings) {
|
|
@@ -26567,7 +26577,8 @@ function getComparableAdvancedSettings(value) {
|
|
|
26567
26577
|
return {
|
|
26568
26578
|
...settings.defaultAssigneeAgentId ? { defaultAssigneeAgentId: settings.defaultAssigneeAgentId } : {},
|
|
26569
26579
|
defaultStatus: settings.defaultStatus,
|
|
26570
|
-
ignoredIssueAuthorUsernames: [...settings.ignoredIssueAuthorUsernames].sort((left, right) => left.localeCompare(right))
|
|
26580
|
+
ignoredIssueAuthorUsernames: [...settings.ignoredIssueAuthorUsernames].sort((left, right) => left.localeCompare(right)),
|
|
26581
|
+
...settings.githubTokenPropagationAgentIds?.length ? { githubTokenPropagationAgentIds: [...settings.githubTokenPropagationAgentIds].sort((left, right) => left.localeCompare(right)) } : {}
|
|
26571
26582
|
};
|
|
26572
26583
|
}
|
|
26573
26584
|
function formatAssigneeOptionLabel(option) {
|
|
@@ -26583,7 +26594,20 @@ function getAvailableAssigneeOptions(options, selectedAgentId) {
|
|
|
26583
26594
|
}
|
|
26584
26595
|
return normalizedOptions;
|
|
26585
26596
|
}
|
|
26586
|
-
function
|
|
26597
|
+
function getAvailablePropagationAgentOptions(options, selectedAgentIds) {
|
|
26598
|
+
const normalizedOptions = [...options ?? []];
|
|
26599
|
+
const selectedIds = normalizeAgentIds(selectedAgentIds);
|
|
26600
|
+
for (const selectedAgentId of selectedIds) {
|
|
26601
|
+
if (!normalizedOptions.some((option) => option.id === selectedAgentId)) {
|
|
26602
|
+
normalizedOptions.push({
|
|
26603
|
+
id: selectedAgentId,
|
|
26604
|
+
name: "Unavailable agent"
|
|
26605
|
+
});
|
|
26606
|
+
}
|
|
26607
|
+
}
|
|
26608
|
+
return normalizedOptions.sort((left, right) => left.name.localeCompare(right.name));
|
|
26609
|
+
}
|
|
26610
|
+
function formatAdvancedSettingsSummary(advancedSettings, availableAssignees, options) {
|
|
26587
26611
|
const assigneeLabel = advancedSettings.defaultAssigneeAgentId ? formatAssigneeOptionLabel(
|
|
26588
26612
|
availableAssignees.find((option) => option.id === advancedSettings.defaultAssigneeAgentId) ?? {
|
|
26589
26613
|
id: advancedSettings.defaultAssigneeAgentId,
|
|
@@ -26592,8 +26616,41 @@ function formatAdvancedSettingsSummary(advancedSettings, availableAssignees) {
|
|
|
26592
26616
|
) : "Unassigned";
|
|
26593
26617
|
const statusLabel = PAPERCLIP_STATUS_OPTIONS.find((option) => option.value === advancedSettings.defaultStatus)?.label ?? "Backlog";
|
|
26594
26618
|
const ignoredAuthorsLabel = advancedSettings.ignoredIssueAuthorUsernames.length > 0 ? advancedSettings.ignoredIssueAuthorUsernames.join(", ") : "none";
|
|
26619
|
+
if (options?.includePropagation) {
|
|
26620
|
+
const propagatedAgentsLabel = advancedSettings.githubTokenPropagationAgentIds?.length ? `${advancedSettings.githubTokenPropagationAgentIds.length} selected` : "none";
|
|
26621
|
+
return `Assignee: ${assigneeLabel} \xB7 Status: ${statusLabel} \xB7 Ignore: ${ignoredAuthorsLabel} \xB7 Propagate: ${propagatedAgentsLabel}`;
|
|
26622
|
+
}
|
|
26595
26623
|
return `Assignee: ${assigneeLabel} \xB7 Status: ${statusLabel} \xB7 Ignore: ${ignoredAuthorsLabel}`;
|
|
26596
26624
|
}
|
|
26625
|
+
function resolveSavedTokenUiState(params) {
|
|
26626
|
+
if (params.githubTokenConfigured) {
|
|
26627
|
+
return {
|
|
26628
|
+
showSavedTokenHint: true,
|
|
26629
|
+
showTokenEditor: false,
|
|
26630
|
+
tokenStatusOverride: "valid",
|
|
26631
|
+
validatedLogin: normalizeOptionalText(params.githubTokenLogin)
|
|
26632
|
+
};
|
|
26633
|
+
}
|
|
26634
|
+
return {
|
|
26635
|
+
showSavedTokenHint: false,
|
|
26636
|
+
showTokenEditor: true,
|
|
26637
|
+
tokenStatusOverride: null,
|
|
26638
|
+
validatedLogin: null
|
|
26639
|
+
};
|
|
26640
|
+
}
|
|
26641
|
+
function formatAgentMultiSelectionLabel(values, options) {
|
|
26642
|
+
if (values.length === 0) {
|
|
26643
|
+
return "No agents selected";
|
|
26644
|
+
}
|
|
26645
|
+
const labels = values.map((value) => options.find((option) => option.value === value)?.label ?? "Unavailable agent").filter((label) => label.trim().length > 0);
|
|
26646
|
+
if (labels.length === 0) {
|
|
26647
|
+
return "No agents selected";
|
|
26648
|
+
}
|
|
26649
|
+
if (labels.length <= 2) {
|
|
26650
|
+
return labels.join(", ");
|
|
26651
|
+
}
|
|
26652
|
+
return `${labels.length} agents selected`;
|
|
26653
|
+
}
|
|
26597
26654
|
function PickerChevronIcon() {
|
|
26598
26655
|
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
26656
|
}
|
|
@@ -26748,6 +26805,122 @@ function SettingsAssigneePicker(props) {
|
|
|
26748
26805
|
] }) : null
|
|
26749
26806
|
] });
|
|
26750
26807
|
}
|
|
26808
|
+
function SettingsAgentMultiPicker(props) {
|
|
26809
|
+
const { id, values, options, disabled, onChange } = props;
|
|
26810
|
+
const [open, setOpen] = useState2(false);
|
|
26811
|
+
const [query, setQuery] = useState2("");
|
|
26812
|
+
const rootRef = useRef(null);
|
|
26813
|
+
const searchInputRef = useRef(null);
|
|
26814
|
+
const selectedValues = normalizeAgentIds(values);
|
|
26815
|
+
const selectedValueSet = new Set(selectedValues);
|
|
26816
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
26817
|
+
const filteredOptions = normalizedQuery ? options.filter((option) => option.label.toLowerCase().includes(normalizedQuery)) : options;
|
|
26818
|
+
const selectedLabel = formatAgentMultiSelectionLabel(selectedValues, options);
|
|
26819
|
+
useEffect2(() => {
|
|
26820
|
+
if (!open) {
|
|
26821
|
+
setQuery("");
|
|
26822
|
+
return;
|
|
26823
|
+
}
|
|
26824
|
+
const handlePointerDown = (event) => {
|
|
26825
|
+
const target = event.target;
|
|
26826
|
+
if (target instanceof Node && rootRef.current?.contains(target)) {
|
|
26827
|
+
return;
|
|
26828
|
+
}
|
|
26829
|
+
setOpen(false);
|
|
26830
|
+
};
|
|
26831
|
+
const handleKeyDown = (event) => {
|
|
26832
|
+
if (event.key === "Escape") {
|
|
26833
|
+
setOpen(false);
|
|
26834
|
+
}
|
|
26835
|
+
};
|
|
26836
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
26837
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
26838
|
+
globalThis.setTimeout(() => {
|
|
26839
|
+
searchInputRef.current?.focus();
|
|
26840
|
+
searchInputRef.current?.select();
|
|
26841
|
+
}, 0);
|
|
26842
|
+
return () => {
|
|
26843
|
+
document.removeEventListener("pointerdown", handlePointerDown);
|
|
26844
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
26845
|
+
};
|
|
26846
|
+
}, [open]);
|
|
26847
|
+
useEffect2(() => {
|
|
26848
|
+
if (disabled && open) {
|
|
26849
|
+
setOpen(false);
|
|
26850
|
+
}
|
|
26851
|
+
}, [disabled, open]);
|
|
26852
|
+
return /* @__PURE__ */ jsxs2("div", { className: "ghsync__picker", ref: rootRef, children: [
|
|
26853
|
+
/* @__PURE__ */ jsxs2(
|
|
26854
|
+
"button",
|
|
26855
|
+
{
|
|
26856
|
+
id,
|
|
26857
|
+
type: "button",
|
|
26858
|
+
className: "ghsync__picker-trigger ghsync__picker-trigger--assignee",
|
|
26859
|
+
disabled,
|
|
26860
|
+
"aria-haspopup": "dialog",
|
|
26861
|
+
"aria-expanded": open,
|
|
26862
|
+
onClick: () => {
|
|
26863
|
+
if (disabled) {
|
|
26864
|
+
return;
|
|
26865
|
+
}
|
|
26866
|
+
setOpen((current) => !current);
|
|
26867
|
+
},
|
|
26868
|
+
children: [
|
|
26869
|
+
/* @__PURE__ */ jsxs2("span", { className: "ghsync__picker-trigger-main", children: [
|
|
26870
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__picker-agent-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(AgentIcon, {}) }),
|
|
26871
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__picker-trigger-label", children: selectedLabel })
|
|
26872
|
+
] }),
|
|
26873
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__picker-trigger-icon", children: /* @__PURE__ */ jsx2(PickerChevronIcon, {}) })
|
|
26874
|
+
]
|
|
26875
|
+
}
|
|
26876
|
+
),
|
|
26877
|
+
open ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__picker-panel ghsync__picker-panel--assignee", role: "dialog", "aria-label": "Choose agents", children: [
|
|
26878
|
+
/* @__PURE__ */ jsx2("div", { className: "ghsync__picker-search", children: /* @__PURE__ */ jsx2(
|
|
26879
|
+
"input",
|
|
26880
|
+
{
|
|
26881
|
+
ref: searchInputRef,
|
|
26882
|
+
type: "text",
|
|
26883
|
+
className: "ghsync__picker-search-input",
|
|
26884
|
+
placeholder: "Search agents...",
|
|
26885
|
+
value: query,
|
|
26886
|
+
onChange: (event) => {
|
|
26887
|
+
setQuery(event.currentTarget.value);
|
|
26888
|
+
},
|
|
26889
|
+
onKeyDown: (event) => {
|
|
26890
|
+
if (event.key === "Escape") {
|
|
26891
|
+
event.preventDefault();
|
|
26892
|
+
setOpen(false);
|
|
26893
|
+
}
|
|
26894
|
+
}
|
|
26895
|
+
}
|
|
26896
|
+
) }),
|
|
26897
|
+
/* @__PURE__ */ jsx2("div", { className: "ghsync__picker-list", role: "listbox", "aria-labelledby": id, "aria-multiselectable": "true", children: filteredOptions.length > 0 ? filteredOptions.map((option) => {
|
|
26898
|
+
const selected = selectedValueSet.has(option.value);
|
|
26899
|
+
return /* @__PURE__ */ jsxs2(
|
|
26900
|
+
"button",
|
|
26901
|
+
{
|
|
26902
|
+
type: "button",
|
|
26903
|
+
role: "option",
|
|
26904
|
+
"aria-selected": selected,
|
|
26905
|
+
className: `ghsync__picker-option${selected ? " ghsync__picker-option--selected" : ""}`,
|
|
26906
|
+
onClick: () => {
|
|
26907
|
+
const nextValues = selected ? selectedValues.filter((value) => value !== option.value) : normalizeAgentIds([...selectedValues, option.value]);
|
|
26908
|
+
onChange(nextValues);
|
|
26909
|
+
},
|
|
26910
|
+
children: [
|
|
26911
|
+
/* @__PURE__ */ jsxs2("span", { className: "ghsync__picker-trigger-main", children: [
|
|
26912
|
+
option.icon === "agent" ? /* @__PURE__ */ jsx2("span", { className: "ghsync__picker-agent-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(AgentIcon, {}) }) : null,
|
|
26913
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__picker-option-label", children: option.label })
|
|
26914
|
+
] }),
|
|
26915
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__picker-option-check", "aria-hidden": "true", children: selected ? /* @__PURE__ */ jsx2(PickerCheckIcon, {}) : null })
|
|
26916
|
+
]
|
|
26917
|
+
},
|
|
26918
|
+
option.value
|
|
26919
|
+
);
|
|
26920
|
+
}) : /* @__PURE__ */ jsx2("div", { className: "ghsync__picker-empty", children: "No agents match." }) })
|
|
26921
|
+
] }) : null
|
|
26922
|
+
] });
|
|
26923
|
+
}
|
|
26751
26924
|
function SettingsStatusPicker(props) {
|
|
26752
26925
|
const { id, value, options, disabled, onChange } = props;
|
|
26753
26926
|
const [open, setOpen] = useState2(false);
|
|
@@ -27678,6 +27851,117 @@ async function patchPluginConfig(pluginId, patch5) {
|
|
|
27678
27851
|
})
|
|
27679
27852
|
});
|
|
27680
27853
|
}
|
|
27854
|
+
var GITHUB_TOKEN_PROPAGATION_CONCURRENCY_LIMIT = 4;
|
|
27855
|
+
function normalizeAgentAdapterConfig(value) {
|
|
27856
|
+
return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
|
|
27857
|
+
}
|
|
27858
|
+
function normalizeAgentEnvBindings(value) {
|
|
27859
|
+
return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
|
|
27860
|
+
}
|
|
27861
|
+
function isMatchingSecretRefEnvBinding(value, secretId) {
|
|
27862
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
27863
|
+
return false;
|
|
27864
|
+
}
|
|
27865
|
+
const record = value;
|
|
27866
|
+
return record.type === "secret_ref" && record.secretId === secretId;
|
|
27867
|
+
}
|
|
27868
|
+
function getAgentPropagationPatch(params) {
|
|
27869
|
+
const adapterConfig = normalizeAgentAdapterConfig(params.adapterConfig);
|
|
27870
|
+
const currentEnv = normalizeAgentEnvBindings(adapterConfig.env);
|
|
27871
|
+
if (params.mode === "ensure") {
|
|
27872
|
+
const nextEnv2 = {
|
|
27873
|
+
...currentEnv,
|
|
27874
|
+
GITHUB_TOKEN: {
|
|
27875
|
+
type: "secret_ref",
|
|
27876
|
+
secretId: params.githubTokenSecretRef
|
|
27877
|
+
}
|
|
27878
|
+
};
|
|
27879
|
+
if (JSON.stringify(nextEnv2) === JSON.stringify(currentEnv)) {
|
|
27880
|
+
return null;
|
|
27881
|
+
}
|
|
27882
|
+
return {
|
|
27883
|
+
...adapterConfig,
|
|
27884
|
+
env: nextEnv2
|
|
27885
|
+
};
|
|
27886
|
+
}
|
|
27887
|
+
if (!isMatchingSecretRefEnvBinding(currentEnv.GITHUB_TOKEN, params.githubTokenSecretRef)) {
|
|
27888
|
+
return null;
|
|
27889
|
+
}
|
|
27890
|
+
const nextEnv = { ...currentEnv };
|
|
27891
|
+
delete nextEnv.GITHUB_TOKEN;
|
|
27892
|
+
const nextAdapterConfig = {
|
|
27893
|
+
...adapterConfig
|
|
27894
|
+
};
|
|
27895
|
+
if (Object.keys(nextEnv).length > 0) {
|
|
27896
|
+
nextAdapterConfig.env = nextEnv;
|
|
27897
|
+
} else {
|
|
27898
|
+
delete nextAdapterConfig.env;
|
|
27899
|
+
}
|
|
27900
|
+
return nextAdapterConfig;
|
|
27901
|
+
}
|
|
27902
|
+
async function runWithConcurrencyLimit(items, concurrencyLimit, worker) {
|
|
27903
|
+
if (items.length === 0) {
|
|
27904
|
+
return;
|
|
27905
|
+
}
|
|
27906
|
+
let nextIndex = 0;
|
|
27907
|
+
const runnerCount = Math.min(concurrencyLimit, items.length);
|
|
27908
|
+
await Promise.all(
|
|
27909
|
+
Array.from({ length: runnerCount }, async () => {
|
|
27910
|
+
while (nextIndex < items.length) {
|
|
27911
|
+
const currentIndex = nextIndex;
|
|
27912
|
+
nextIndex += 1;
|
|
27913
|
+
await worker(items[currentIndex]);
|
|
27914
|
+
}
|
|
27915
|
+
})
|
|
27916
|
+
);
|
|
27917
|
+
}
|
|
27918
|
+
async function applyGitHubTokenPropagationUpdate(params) {
|
|
27919
|
+
const agent = await fetchJson(`/api/agents/${params.agentId}`);
|
|
27920
|
+
const nextAdapterConfig = getAgentPropagationPatch({
|
|
27921
|
+
adapterConfig: agent?.adapterConfig,
|
|
27922
|
+
githubTokenSecretRef: params.githubTokenSecretRef,
|
|
27923
|
+
mode: params.mode
|
|
27924
|
+
});
|
|
27925
|
+
if (!nextAdapterConfig) {
|
|
27926
|
+
return;
|
|
27927
|
+
}
|
|
27928
|
+
await fetchJson(`/api/agents/${params.agentId}`, {
|
|
27929
|
+
method: "PATCH",
|
|
27930
|
+
body: JSON.stringify({
|
|
27931
|
+
adapterConfig: nextAdapterConfig
|
|
27932
|
+
})
|
|
27933
|
+
});
|
|
27934
|
+
}
|
|
27935
|
+
async function syncGitHubTokenPropagationForAgents(params) {
|
|
27936
|
+
const selectedAgentIds = normalizeAgentIds(params.selectedAgentIds);
|
|
27937
|
+
const selectedAgentIdSet = new Set(selectedAgentIds);
|
|
27938
|
+
const previousAgentIds = normalizeAgentIds(params.previousAgentIds);
|
|
27939
|
+
const failures = /* @__PURE__ */ new Set();
|
|
27940
|
+
const operations = [
|
|
27941
|
+
...selectedAgentIds.map((agentId) => ({ agentId, mode: "ensure" })),
|
|
27942
|
+
...previousAgentIds.filter((agentId) => !selectedAgentIdSet.has(agentId)).map((agentId) => ({ agentId, mode: "remove" }))
|
|
27943
|
+
];
|
|
27944
|
+
await runWithConcurrencyLimit(
|
|
27945
|
+
operations,
|
|
27946
|
+
GITHUB_TOKEN_PROPAGATION_CONCURRENCY_LIMIT,
|
|
27947
|
+
async (operation) => {
|
|
27948
|
+
try {
|
|
27949
|
+
await applyGitHubTokenPropagationUpdate({
|
|
27950
|
+
agentId: operation.agentId,
|
|
27951
|
+
githubTokenSecretRef: params.githubTokenSecretRef,
|
|
27952
|
+
mode: operation.mode
|
|
27953
|
+
});
|
|
27954
|
+
} catch {
|
|
27955
|
+
failures.add(operation.agentId);
|
|
27956
|
+
}
|
|
27957
|
+
}
|
|
27958
|
+
);
|
|
27959
|
+
if (failures.size > 0) {
|
|
27960
|
+
throw new Error(
|
|
27961
|
+
`GitHub token propagation could not update these agents: ${[...failures].join(", ")}.`
|
|
27962
|
+
);
|
|
27963
|
+
}
|
|
27964
|
+
}
|
|
27681
27965
|
function normalizeCliAuthPollIntervalMs(value) {
|
|
27682
27966
|
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
27683
27967
|
return CLI_AUTH_POLL_INTERVAL_FALLBACK_MS;
|
|
@@ -30778,6 +31062,11 @@ function GitHubSyncSettingsPage() {
|
|
|
30778
31062
|
if (!settings.data) {
|
|
30779
31063
|
return;
|
|
30780
31064
|
}
|
|
31065
|
+
const tokenUiState = resolveSavedTokenUiState({
|
|
31066
|
+
githubTokenConfigured: settings.data.githubTokenConfigured,
|
|
31067
|
+
githubTokenLogin: settings.data.githubTokenLogin
|
|
31068
|
+
});
|
|
31069
|
+
const savedBoardAccessIdentity = typeof settings.data.paperclipBoardAccessIdentity === "string" && settings.data.paperclipBoardAccessIdentity.trim() ? settings.data.paperclipBoardAccessIdentity.trim() : null;
|
|
30781
31070
|
const nextScheduleFrequencyMinutes = normalizeScheduleFrequencyMinutes(settings.data.scheduleFrequencyMinutes);
|
|
30782
31071
|
setForm({
|
|
30783
31072
|
mappings: settings.data.mappings ?? [],
|
|
@@ -30794,18 +31083,12 @@ function GitHubSyncSettingsPage() {
|
|
|
30794
31083
|
setScheduleFrequencyDraft(String(nextScheduleFrequencyMinutes));
|
|
30795
31084
|
setIgnoredAuthorsDraft(normalizeAdvancedSettings(settings.data.advancedSettings).ignoredIssueAuthorUsernames.join(", "));
|
|
30796
31085
|
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]);
|
|
31086
|
+
setValidatedLogin(tokenUiState.validatedLogin);
|
|
31087
|
+
setBoardAccessIdentity(settings.data.paperclipBoardAccessConfigured ? savedBoardAccessIdentity : null);
|
|
31088
|
+
setShowSavedTokenHint(tokenUiState.showSavedTokenHint);
|
|
31089
|
+
setShowTokenEditor(tokenUiState.showTokenEditor);
|
|
31090
|
+
setTokenStatusOverride(tokenUiState.tokenStatusOverride);
|
|
31091
|
+
}, [settings.data]);
|
|
30809
31092
|
useEffect2(() => {
|
|
30810
31093
|
const companyId = hostContext.companyId;
|
|
30811
31094
|
if (!companyId || tokenStatusOverride === "invalid") {
|
|
@@ -31028,6 +31311,10 @@ function GitHubSyncSettingsPage() {
|
|
|
31028
31311
|
(currentSettings?.availableAssignees?.length ? currentSettings.availableAssignees : null) ?? (form.availableAssignees?.length ? form.availableAssignees : null) ?? browserAvailableAssignees,
|
|
31029
31312
|
form.advancedSettings.defaultAssigneeAgentId
|
|
31030
31313
|
);
|
|
31314
|
+
const propagationAgents = getAvailablePropagationAgentOptions(
|
|
31315
|
+
(currentSettings?.availableAssignees?.length ? currentSettings.availableAssignees : null) ?? (form.availableAssignees?.length ? form.availableAssignees : null) ?? browserAvailableAssignees,
|
|
31316
|
+
form.advancedSettings.githubTokenPropagationAgentIds
|
|
31317
|
+
);
|
|
31031
31318
|
const savedMappingsSource = currentSettings ? currentSettings.mappings ?? [] : form.mappings;
|
|
31032
31319
|
const savedMappings = getComparableMappings(savedMappingsSource);
|
|
31033
31320
|
const draftMappings = getComparableMappings(form.mappings);
|
|
@@ -31069,7 +31356,7 @@ function GitHubSyncSettingsPage() {
|
|
|
31069
31356
|
const canConnectBoardAccess = hasCompanyContext && !settingsMutationsLocked && !connectingBoardAccess && !showInitialLoadingState;
|
|
31070
31357
|
const boardAccessStatusLabel = !hasCompanyContext ? "Unavailable" : boardAccessBannerLabel;
|
|
31071
31358
|
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.";
|
|
31359
|
+
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
31360
|
const showTokenForm = tokenStatus !== "valid" || showTokenEditor;
|
|
31074
31361
|
const lastUpdated = formatDate(form.updatedAt ?? currentSettings?.updatedAt, "Not saved yet");
|
|
31075
31362
|
const lastSync = formatDate(displaySyncState.checkedAt, "Never");
|
|
@@ -31095,7 +31382,9 @@ function GitHubSyncSettingsPage() {
|
|
|
31095
31382
|
const manualSyncScopePillClass = hasCompanyContext ? "ghsync__scope-pill ghsync__scope-pill--company" : "ghsync__scope-pill ghsync__scope-pill--mixed";
|
|
31096
31383
|
const manualSyncScopePillLabel = hasCompanyContext ? "This company" : "All companies";
|
|
31097
31384
|
const manualSyncButtonLabel = hasCompanyContext ? "Run sync for this company" : "Run sync across all companies";
|
|
31098
|
-
const advancedSettingsSummary = formatAdvancedSettingsSummary(form.advancedSettings, availableAssignees
|
|
31385
|
+
const advancedSettingsSummary = formatAdvancedSettingsSummary(form.advancedSettings, availableAssignees, {
|
|
31386
|
+
includePropagation: boardAccessRequired
|
|
31387
|
+
});
|
|
31099
31388
|
const assigneeSelectOptions = [
|
|
31100
31389
|
{ value: "", label: "Unassigned" },
|
|
31101
31390
|
...availableAssignees.map((option) => ({
|
|
@@ -31104,6 +31393,11 @@ function GitHubSyncSettingsPage() {
|
|
|
31104
31393
|
icon: "agent"
|
|
31105
31394
|
}))
|
|
31106
31395
|
];
|
|
31396
|
+
const propagationAgentOptions = propagationAgents.map((option) => ({
|
|
31397
|
+
value: option.id,
|
|
31398
|
+
label: formatAssigneeOptionLabel(option),
|
|
31399
|
+
icon: "agent"
|
|
31400
|
+
}));
|
|
31107
31401
|
const statusSelectOptions = PAPERCLIP_STATUS_OPTIONS.map((option) => ({
|
|
31108
31402
|
value: option.value,
|
|
31109
31403
|
label: option.label,
|
|
@@ -31234,6 +31528,33 @@ function GitHubSyncSettingsPage() {
|
|
|
31234
31528
|
};
|
|
31235
31529
|
});
|
|
31236
31530
|
}
|
|
31531
|
+
async function propagateGitHubTokenToSelectedAgents(options) {
|
|
31532
|
+
if (!boardAccessRequired) {
|
|
31533
|
+
return;
|
|
31534
|
+
}
|
|
31535
|
+
const selectedAgentIds = normalizeAgentIds(options.selectedAgentIds);
|
|
31536
|
+
const previousAgentIds = normalizeAgentIds(options.previousAgentIds);
|
|
31537
|
+
if (selectedAgentIds.length === 0 && previousAgentIds.length === 0) {
|
|
31538
|
+
return;
|
|
31539
|
+
}
|
|
31540
|
+
let githubTokenSecretRef = typeof options.githubTokenSecretRef === "string" && options.githubTokenSecretRef.trim() ? options.githubTokenSecretRef.trim() : void 0;
|
|
31541
|
+
if (!githubTokenSecretRef) {
|
|
31542
|
+
const pluginId = await resolveCurrentPluginId(pluginIdFromLocation);
|
|
31543
|
+
if (!pluginId) {
|
|
31544
|
+
throw new Error("Plugin id is required to propagate the GitHub token to selected agents.");
|
|
31545
|
+
}
|
|
31546
|
+
const currentConfigResponse = await fetchJson(`/api/plugins/${pluginId}/config`);
|
|
31547
|
+
githubTokenSecretRef = normalizePluginConfig(currentConfigResponse?.configJson).githubTokenRef;
|
|
31548
|
+
}
|
|
31549
|
+
if (!githubTokenSecretRef) {
|
|
31550
|
+
throw new Error("GitHub token propagation requires a GitHub token saved through this settings page.");
|
|
31551
|
+
}
|
|
31552
|
+
await syncGitHubTokenPropagationForAgents({
|
|
31553
|
+
githubTokenSecretRef,
|
|
31554
|
+
selectedAgentIds,
|
|
31555
|
+
previousAgentIds
|
|
31556
|
+
});
|
|
31557
|
+
}
|
|
31237
31558
|
async function handleSaveToken(event) {
|
|
31238
31559
|
event.preventDefault();
|
|
31239
31560
|
setSubmittingToken(true);
|
|
@@ -31277,8 +31598,20 @@ function GitHubSyncSettingsPage() {
|
|
|
31277
31598
|
});
|
|
31278
31599
|
await saveRegistration({
|
|
31279
31600
|
companyId,
|
|
31280
|
-
githubTokenRef: secret.id
|
|
31601
|
+
githubTokenRef: secret.id,
|
|
31602
|
+
githubTokenLogin: validation.login
|
|
31281
31603
|
});
|
|
31604
|
+
const selectedAgentIds = normalizeAgentIds(currentSettings?.advancedSettings?.githubTokenPropagationAgentIds);
|
|
31605
|
+
let propagationError = null;
|
|
31606
|
+
try {
|
|
31607
|
+
await propagateGitHubTokenToSelectedAgents({
|
|
31608
|
+
selectedAgentIds,
|
|
31609
|
+
previousAgentIds: selectedAgentIds,
|
|
31610
|
+
githubTokenSecretRef: secret.id
|
|
31611
|
+
});
|
|
31612
|
+
} catch (error) {
|
|
31613
|
+
propagationError = error;
|
|
31614
|
+
}
|
|
31282
31615
|
setForm((current) => ({
|
|
31283
31616
|
...current,
|
|
31284
31617
|
githubTokenConfigured: true
|
|
@@ -31293,6 +31626,16 @@ function GitHubSyncSettingsPage() {
|
|
|
31293
31626
|
body: "Token saved.",
|
|
31294
31627
|
tone: "success"
|
|
31295
31628
|
});
|
|
31629
|
+
if (propagationError) {
|
|
31630
|
+
toast({
|
|
31631
|
+
title: "GitHub token saved, but agent propagation needs attention",
|
|
31632
|
+
body: getActionErrorMessage(
|
|
31633
|
+
propagationError,
|
|
31634
|
+
"GitHub Sync could not update the selected agents with the saved token."
|
|
31635
|
+
),
|
|
31636
|
+
tone: "error"
|
|
31637
|
+
});
|
|
31638
|
+
}
|
|
31296
31639
|
notifyGitHubSyncSettingsChanged();
|
|
31297
31640
|
try {
|
|
31298
31641
|
await settings.refresh();
|
|
@@ -31348,7 +31691,8 @@ function GitHubSyncSettingsPage() {
|
|
|
31348
31691
|
});
|
|
31349
31692
|
await updateBoardAccess({
|
|
31350
31693
|
companyId,
|
|
31351
|
-
paperclipBoardApiTokenRef: secret.id
|
|
31694
|
+
paperclipBoardApiTokenRef: secret.id,
|
|
31695
|
+
paperclipBoardAccessIdentity: identity ?? ""
|
|
31352
31696
|
});
|
|
31353
31697
|
setBoardAccessIdentity(identity);
|
|
31354
31698
|
setForm((current) => ({
|
|
@@ -31428,6 +31772,15 @@ function GitHubSyncSettingsPage() {
|
|
|
31428
31772
|
scheduleFrequencyMinutes,
|
|
31429
31773
|
...trustedPaperclipApiBaseUrl ? { paperclipApiBaseUrl: trustedPaperclipApiBaseUrl } : {}
|
|
31430
31774
|
});
|
|
31775
|
+
let propagationError = null;
|
|
31776
|
+
try {
|
|
31777
|
+
await propagateGitHubTokenToSelectedAgents({
|
|
31778
|
+
selectedAgentIds: normalizeAgentIds(normalizeAdvancedSettings(result.advancedSettings).githubTokenPropagationAgentIds),
|
|
31779
|
+
previousAgentIds: normalizeAgentIds(currentSettings?.advancedSettings?.githubTokenPropagationAgentIds)
|
|
31780
|
+
});
|
|
31781
|
+
} catch (error) {
|
|
31782
|
+
propagationError = error;
|
|
31783
|
+
}
|
|
31431
31784
|
setForm((current) => ({
|
|
31432
31785
|
...current,
|
|
31433
31786
|
mappings: result.mappings.length > 0 ? result.mappings : [createEmptyMapping(0)],
|
|
@@ -31444,6 +31797,16 @@ function GitHubSyncSettingsPage() {
|
|
|
31444
31797
|
body: `Advanced defaults, mappings, and automatic sync are saved for ${currentCompanyName}.`,
|
|
31445
31798
|
tone: "success"
|
|
31446
31799
|
});
|
|
31800
|
+
if (propagationError) {
|
|
31801
|
+
toast({
|
|
31802
|
+
title: "Settings saved, but agent propagation needs attention",
|
|
31803
|
+
body: getActionErrorMessage(
|
|
31804
|
+
propagationError,
|
|
31805
|
+
"GitHub Sync could not apply the selected agent token propagation updates."
|
|
31806
|
+
),
|
|
31807
|
+
tone: "error"
|
|
31808
|
+
});
|
|
31809
|
+
}
|
|
31447
31810
|
notifyGitHubSyncSettingsChanged();
|
|
31448
31811
|
try {
|
|
31449
31812
|
await settings.refresh();
|
|
@@ -31685,7 +32048,7 @@ function GitHubSyncSettingsPage() {
|
|
|
31685
32048
|
/* @__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
32049
|
] }) : null
|
|
31687
32050
|
] }),
|
|
31688
|
-
/* @__PURE__ */ jsxs2("section", { className: "ghsync__section", children: [
|
|
32051
|
+
boardAccessRequired ? /* @__PURE__ */ jsxs2("section", { className: "ghsync__section", children: [
|
|
31689
32052
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-head", children: [
|
|
31690
32053
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-copy", children: [
|
|
31691
32054
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-title-row", children: [
|
|
@@ -31727,7 +32090,7 @@ function GitHubSyncSettingsPage() {
|
|
|
31727
32090
|
] }),
|
|
31728
32091
|
/* @__PURE__ */ jsx2("span", { className: "ghsync__badge ghsync__badge--neutral", children: "Unavailable" })
|
|
31729
32092
|
] })
|
|
31730
|
-
] }),
|
|
32093
|
+
] }) : null,
|
|
31731
32094
|
/* @__PURE__ */ jsxs2("section", { className: "ghsync__section", children: [
|
|
31732
32095
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-head", children: [
|
|
31733
32096
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-copy", children: [
|
|
@@ -31954,7 +32317,29 @@ function GitHubSyncSettingsPage() {
|
|
|
31954
32317
|
}
|
|
31955
32318
|
),
|
|
31956
32319
|
/* @__PURE__ */ jsx2("p", { className: "ghsync__hint", children: "Comma or newline separated." })
|
|
31957
|
-
] })
|
|
32320
|
+
] }),
|
|
32321
|
+
boardAccessRequired ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__field", children: [
|
|
32322
|
+
/* @__PURE__ */ jsx2("label", { htmlFor: "advanced-token-propagation", children: "Propagate GitHub token to agents" }),
|
|
32323
|
+
/* @__PURE__ */ jsx2(
|
|
32324
|
+
SettingsAgentMultiPicker,
|
|
32325
|
+
{
|
|
32326
|
+
id: "advanced-token-propagation",
|
|
32327
|
+
values: form.advancedSettings.githubTokenPropagationAgentIds ?? [],
|
|
32328
|
+
options: propagationAgentOptions,
|
|
32329
|
+
disabled: settingsMutationsLocked || tokenStatus !== "valid",
|
|
32330
|
+
onChange: (nextValues) => {
|
|
32331
|
+
setForm((current) => ({
|
|
32332
|
+
...current,
|
|
32333
|
+
advancedSettings: {
|
|
32334
|
+
...current.advancedSettings,
|
|
32335
|
+
...nextValues.length > 0 ? { githubTokenPropagationAgentIds: nextValues } : { githubTokenPropagationAgentIds: void 0 }
|
|
32336
|
+
}
|
|
32337
|
+
}));
|
|
32338
|
+
}
|
|
32339
|
+
}
|
|
32340
|
+
),
|
|
32341
|
+
/* @__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." })
|
|
32342
|
+
] }) : null
|
|
31958
32343
|
] }) : null
|
|
31959
32344
|
] }),
|
|
31960
32345
|
/* @__PURE__ */ jsxs2("section", { className: "ghsync__section", children: [
|
|
@@ -32107,13 +32492,13 @@ function GitHubSyncSettingsPage() {
|
|
|
32107
32492
|
] }),
|
|
32108
32493
|
/* @__PURE__ */ jsx2("span", { children: !repositoriesUnlocked ? "Requires a token." : savedMappingCount > 0 ? hasCompanyContext ? `${savedMappingCount} saved.` : `${savedMappingCount} saved.` : hasCompanyContext ? "Add a repository." : "Select a company." })
|
|
32109
32494
|
] }),
|
|
32110
|
-
/* @__PURE__ */ jsxs2("div", { className: "ghsync__check", children: [
|
|
32495
|
+
boardAccessRequired ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__check", children: [
|
|
32111
32496
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__check-top", children: [
|
|
32112
32497
|
/* @__PURE__ */ jsx2("strong", { children: "Paperclip board access" }),
|
|
32113
32498
|
/* @__PURE__ */ jsx2("span", { className: `ghsync__badge ${getToneClass(boardAccessStatusTone)}`, children: boardAccessStatusLabel })
|
|
32114
32499
|
] }),
|
|
32115
32500
|
/* @__PURE__ */ jsx2("span", { children: boardAccessSummaryText })
|
|
32116
|
-
] }),
|
|
32501
|
+
] }) : null,
|
|
32117
32502
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__check", children: [
|
|
32118
32503
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__check-top", children: [
|
|
32119
32504
|
/* @__PURE__ */ jsx2("strong", { children: "Sync" }),
|
|
@@ -33123,6 +33508,8 @@ export {
|
|
|
33123
33508
|
GitHubSyncProjectPullRequestsSidebarItem,
|
|
33124
33509
|
GitHubSyncSettingsPage,
|
|
33125
33510
|
index_default as default,
|
|
33126
|
-
resolveOrCreateProject
|
|
33511
|
+
resolveOrCreateProject,
|
|
33512
|
+
resolveSavedTokenUiState,
|
|
33513
|
+
syncGitHubTokenPropagationForAgents
|
|
33127
33514
|
};
|
|
33128
33515
|
//# sourceMappingURL=index.js.map
|