paperclip-github-plugin 0.2.2 → 0.2.3
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 +4 -2
- package/dist/manifest.js +1 -1
- package/dist/ui/index.js +385 -45
- package/dist/ui/index.js.map +2 -2
- package/dist/worker.js +281 -32
- package/package.json +1 -1
package/dist/ui/index.js
CHANGED
|
@@ -680,12 +680,18 @@ function getActiveRateLimitPause(syncState, referenceTimeMs = Date.now()) {
|
|
|
680
680
|
...syncState.errorDetails.rateLimitResource ? { resource: syncState.errorDetails.rateLimitResource } : {}
|
|
681
681
|
};
|
|
682
682
|
}
|
|
683
|
+
function isSyncCancellationRequested(syncState) {
|
|
684
|
+
return syncState.status === "running" && Boolean(syncState.cancelRequestedAt?.trim());
|
|
685
|
+
}
|
|
683
686
|
function getSyncToastTitle(syncState) {
|
|
684
687
|
if (getActiveRateLimitPause(syncState)) {
|
|
685
688
|
return "GitHub sync is paused";
|
|
686
689
|
}
|
|
690
|
+
if (syncState.status === "cancelled") {
|
|
691
|
+
return "GitHub sync was cancelled";
|
|
692
|
+
}
|
|
687
693
|
if (syncState.status === "running") {
|
|
688
|
-
return "GitHub sync is running";
|
|
694
|
+
return isSyncCancellationRequested(syncState) ? "GitHub sync is stopping" : "GitHub sync is running";
|
|
689
695
|
}
|
|
690
696
|
return syncState.status === "error" ? "GitHub sync needs attention" : "GitHub sync finished";
|
|
691
697
|
}
|
|
@@ -694,7 +700,7 @@ function getSyncToastBody(syncState) {
|
|
|
694
700
|
return syncState.message.trim();
|
|
695
701
|
}
|
|
696
702
|
if (syncState.status === "running") {
|
|
697
|
-
return "GitHub sync is running in the background.";
|
|
703
|
+
return isSyncCancellationRequested(syncState) ? "Cancellation requested. GitHub sync will stop after the current step finishes." : "GitHub sync is running in the background.";
|
|
698
704
|
}
|
|
699
705
|
return "GitHub sync completed.";
|
|
700
706
|
}
|
|
@@ -702,7 +708,7 @@ function getSyncToastTone(syncState) {
|
|
|
702
708
|
if (getActiveRateLimitPause(syncState)) {
|
|
703
709
|
return "info";
|
|
704
710
|
}
|
|
705
|
-
if (syncState.status === "running") {
|
|
711
|
+
if (syncState.status === "running" || syncState.status === "cancelled") {
|
|
706
712
|
return "info";
|
|
707
713
|
}
|
|
708
714
|
return syncState.status === "error" ? "error" : "success";
|
|
@@ -833,6 +839,10 @@ var SHARED_PROGRESS_STYLES = `
|
|
|
833
839
|
align-items: stretch;
|
|
834
840
|
flex-direction: column;
|
|
835
841
|
}
|
|
842
|
+
|
|
843
|
+
.ghsync-diagnostics__layout--split {
|
|
844
|
+
grid-template-columns: 1fr;
|
|
845
|
+
}
|
|
836
846
|
}
|
|
837
847
|
`;
|
|
838
848
|
var PAGE_STYLES = `
|
|
@@ -1060,6 +1070,79 @@ var PAGE_STYLES = `
|
|
|
1060
1070
|
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
|
1061
1071
|
}
|
|
1062
1072
|
|
|
1073
|
+
.ghsync-diagnostics__layout {
|
|
1074
|
+
display: grid;
|
|
1075
|
+
gap: 10px;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
.ghsync-diagnostics__layout--split {
|
|
1079
|
+
grid-template-columns: minmax(220px, 300px) minmax(0, 1fr);
|
|
1080
|
+
align-items: start;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
.ghsync-diagnostics__detail,
|
|
1084
|
+
.ghsync-diagnostics__failures {
|
|
1085
|
+
display: grid;
|
|
1086
|
+
gap: 10px;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
.ghsync-diagnostics__failures {
|
|
1090
|
+
max-height: 420px;
|
|
1091
|
+
overflow: auto;
|
|
1092
|
+
margin: 0;
|
|
1093
|
+
padding: 0;
|
|
1094
|
+
list-style: none;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
.ghsync-diagnostics__failure {
|
|
1098
|
+
display: grid;
|
|
1099
|
+
gap: 6px;
|
|
1100
|
+
width: 100%;
|
|
1101
|
+
padding: 12px;
|
|
1102
|
+
border-radius: 10px;
|
|
1103
|
+
border: 1px solid var(--ghsync-dangerBorder);
|
|
1104
|
+
background: var(--ghsync-surfaceAlt);
|
|
1105
|
+
text-align: left;
|
|
1106
|
+
transition: border-color 160ms ease, background 160ms ease, transform 160ms ease;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
.ghsync-diagnostics__failure-item {
|
|
1110
|
+
list-style: none;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
.ghsync-diagnostics__failure:hover {
|
|
1114
|
+
border-color: var(--ghsync-dangerText);
|
|
1115
|
+
transform: translateY(-1px);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
.ghsync-diagnostics__failure--active {
|
|
1119
|
+
border-color: var(--ghsync-dangerText);
|
|
1120
|
+
background: color-mix(in srgb, var(--ghsync-dangerBg) 35%, var(--ghsync-surfaceAlt));
|
|
1121
|
+
box-shadow: 0 0 0 1px color-mix(in srgb, var(--ghsync-dangerText) 22%, transparent);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
.ghsync-diagnostics__failure-title {
|
|
1125
|
+
color: var(--ghsync-title);
|
|
1126
|
+
font-size: 13px;
|
|
1127
|
+
line-height: 1.4;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
.ghsync-diagnostics__failure-meta {
|
|
1131
|
+
color: var(--ghsync-muted);
|
|
1132
|
+
font-size: 11px;
|
|
1133
|
+
line-height: 1.4;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
.ghsync-diagnostics__failure-preview {
|
|
1137
|
+
color: var(--ghsync-text);
|
|
1138
|
+
font-size: 12px;
|
|
1139
|
+
line-height: 1.5;
|
|
1140
|
+
display: -webkit-box;
|
|
1141
|
+
-webkit-box-orient: vertical;
|
|
1142
|
+
-webkit-line-clamp: 3;
|
|
1143
|
+
overflow: hidden;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1063
1146
|
.ghsync-diagnostics__item,
|
|
1064
1147
|
.ghsync-diagnostics__block {
|
|
1065
1148
|
display: grid;
|
|
@@ -2033,6 +2116,72 @@ var WIDGET_STYLES = `
|
|
|
2033
2116
|
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
|
2034
2117
|
}
|
|
2035
2118
|
|
|
2119
|
+
.ghsync-diagnostics__layout {
|
|
2120
|
+
display: grid;
|
|
2121
|
+
gap: 10px;
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
.ghsync-diagnostics__layout--split {
|
|
2125
|
+
grid-template-columns: minmax(200px, 240px) minmax(0, 1fr);
|
|
2126
|
+
align-items: start;
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
.ghsync-diagnostics__detail,
|
|
2130
|
+
.ghsync-diagnostics__failures {
|
|
2131
|
+
display: grid;
|
|
2132
|
+
gap: 10px;
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
.ghsync-diagnostics__failures {
|
|
2136
|
+
max-height: 320px;
|
|
2137
|
+
overflow: auto;
|
|
2138
|
+
margin: 0;
|
|
2139
|
+
padding: 0;
|
|
2140
|
+
list-style: none;
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
.ghsync-diagnostics__failure {
|
|
2144
|
+
display: grid;
|
|
2145
|
+
gap: 6px;
|
|
2146
|
+
width: 100%;
|
|
2147
|
+
padding: 12px;
|
|
2148
|
+
border-radius: 10px;
|
|
2149
|
+
border: 1px solid var(--ghsync-dangerBorder);
|
|
2150
|
+
background: var(--ghsync-surfaceAlt);
|
|
2151
|
+
text-align: left;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
.ghsync-diagnostics__failure-item {
|
|
2155
|
+
list-style: none;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
.ghsync-diagnostics__failure--active {
|
|
2159
|
+
border-color: var(--ghsync-dangerText);
|
|
2160
|
+
background: color-mix(in srgb, var(--ghsync-dangerBg) 35%, var(--ghsync-surfaceAlt));
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
.ghsync-diagnostics__failure-title {
|
|
2164
|
+
color: var(--ghsync-title);
|
|
2165
|
+
font-size: 12px;
|
|
2166
|
+
line-height: 1.4;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
.ghsync-diagnostics__failure-meta {
|
|
2170
|
+
color: var(--ghsync-muted);
|
|
2171
|
+
font-size: 11px;
|
|
2172
|
+
line-height: 1.4;
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
.ghsync-diagnostics__failure-preview {
|
|
2176
|
+
color: var(--ghsync-text);
|
|
2177
|
+
font-size: 12px;
|
|
2178
|
+
line-height: 1.5;
|
|
2179
|
+
display: -webkit-box;
|
|
2180
|
+
-webkit-box-orient: vertical;
|
|
2181
|
+
-webkit-line-clamp: 3;
|
|
2182
|
+
overflow: hidden;
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2036
2185
|
.ghsync-diagnostics__item,
|
|
2037
2186
|
.ghsync-diagnostics__block {
|
|
2038
2187
|
display: grid;
|
|
@@ -2173,6 +2322,10 @@ var WIDGET_STYLES = `
|
|
|
2173
2322
|
.ghsync-widget__link {
|
|
2174
2323
|
flex: 1 1 auto;
|
|
2175
2324
|
}
|
|
2325
|
+
|
|
2326
|
+
.ghsync-diagnostics__layout--split {
|
|
2327
|
+
grid-template-columns: 1fr;
|
|
2328
|
+
}
|
|
2176
2329
|
}
|
|
2177
2330
|
|
|
2178
2331
|
${SHARED_PROGRESS_STYLES}
|
|
@@ -3079,7 +3232,10 @@ function getSyncStatus(syncState, runningSync, syncUnlocked) {
|
|
|
3079
3232
|
return { label: "Locked", tone: "neutral" };
|
|
3080
3233
|
}
|
|
3081
3234
|
if (runningSync || syncState.status === "running") {
|
|
3082
|
-
return {
|
|
3235
|
+
return {
|
|
3236
|
+
label: isSyncCancellationRequested(syncState) ? "Cancelling" : "Running",
|
|
3237
|
+
tone: "info"
|
|
3238
|
+
};
|
|
3083
3239
|
}
|
|
3084
3240
|
if (getActiveRateLimitPause(syncState)) {
|
|
3085
3241
|
return { label: "Paused", tone: "warning" };
|
|
@@ -3090,6 +3246,9 @@ function getSyncStatus(syncState, runningSync, syncUnlocked) {
|
|
|
3090
3246
|
if (syncState.status === "success") {
|
|
3091
3247
|
return { label: "Ready", tone: "success" };
|
|
3092
3248
|
}
|
|
3249
|
+
if (syncState.status === "cancelled") {
|
|
3250
|
+
return { label: "Cancelled", tone: "neutral" };
|
|
3251
|
+
}
|
|
3093
3252
|
return { label: "Ready", tone: "info" };
|
|
3094
3253
|
}
|
|
3095
3254
|
function getToneClass(tone) {
|
|
@@ -3360,10 +3519,10 @@ function getDashboardSummary(params) {
|
|
|
3360
3519
|
if (params.runningSync || params.syncState.status === "running") {
|
|
3361
3520
|
const progress = getRunningSyncProgressModel(params.syncState);
|
|
3362
3521
|
return {
|
|
3363
|
-
label: "Syncing",
|
|
3522
|
+
label: isSyncCancellationRequested(params.syncState) ? "Cancelling" : "Syncing",
|
|
3364
3523
|
tone: "info",
|
|
3365
|
-
title: progress?.title ?? "Sync in progress",
|
|
3366
|
-
body: progress?.description ?? "GitHub issues are being checked right now. This card refreshes automatically until the run finishes."
|
|
3524
|
+
title: isSyncCancellationRequested(params.syncState) ? "Stopping the current sync" : progress?.title ?? "Sync in progress",
|
|
3525
|
+
body: isSyncCancellationRequested(params.syncState) ? "GitHub Sync will stop after the current repository or issue step finishes." : progress?.description ?? "GitHub issues are being checked right now. This card refreshes automatically until the run finishes."
|
|
3367
3526
|
};
|
|
3368
3527
|
}
|
|
3369
3528
|
if (activeRateLimitPause) {
|
|
@@ -3382,6 +3541,14 @@ function getDashboardSummary(params) {
|
|
|
3382
3541
|
body: params.syncState.message ?? "Open settings to review the latest GitHub sync issue."
|
|
3383
3542
|
};
|
|
3384
3543
|
}
|
|
3544
|
+
if (params.syncState.status === "cancelled") {
|
|
3545
|
+
return {
|
|
3546
|
+
label: "Cancelled",
|
|
3547
|
+
tone: "neutral",
|
|
3548
|
+
title: "Sync cancelled",
|
|
3549
|
+
body: params.syncState.message ?? "The last GitHub sync was cancelled before it finished."
|
|
3550
|
+
};
|
|
3551
|
+
}
|
|
3385
3552
|
if (params.syncState.checkedAt) {
|
|
3386
3553
|
return {
|
|
3387
3554
|
label: "Ready",
|
|
@@ -3491,16 +3658,28 @@ function formatSyncFailureRepository(repositoryUrl) {
|
|
|
3491
3658
|
}
|
|
3492
3659
|
return repositoryUrl.trim();
|
|
3493
3660
|
}
|
|
3494
|
-
function
|
|
3661
|
+
function getSyncFailureLogEntries(syncState) {
|
|
3662
|
+
if (syncState.recentFailures?.length) {
|
|
3663
|
+
return syncState.recentFailures.filter((entry) => typeof entry.message === "string" && entry.message.trim());
|
|
3664
|
+
}
|
|
3495
3665
|
if (syncState.status !== "error") {
|
|
3496
|
-
return
|
|
3666
|
+
return [];
|
|
3497
3667
|
}
|
|
3668
|
+
return [
|
|
3669
|
+
{
|
|
3670
|
+
message: syncState.message?.trim() || "GitHub sync failed.",
|
|
3671
|
+
occurredAt: syncState.checkedAt,
|
|
3672
|
+
...syncState.errorDetails ?? {}
|
|
3673
|
+
}
|
|
3674
|
+
];
|
|
3675
|
+
}
|
|
3676
|
+
function getSyncDiagnostics(entry) {
|
|
3498
3677
|
const rows = [];
|
|
3499
|
-
const repositoryLabel = formatSyncFailureRepository(
|
|
3500
|
-
const phaseLabel = formatSyncFailurePhase(
|
|
3501
|
-
const issueNumber =
|
|
3502
|
-
const rateLimitResetAt =
|
|
3503
|
-
const rateLimitResourceLabel = getGitHubRateLimitResourceLabel(
|
|
3678
|
+
const repositoryLabel = formatSyncFailureRepository(entry.repositoryUrl);
|
|
3679
|
+
const phaseLabel = formatSyncFailurePhase(entry.phase);
|
|
3680
|
+
const issueNumber = entry.githubIssueNumber;
|
|
3681
|
+
const rateLimitResetAt = entry.rateLimitResetAt;
|
|
3682
|
+
const rateLimitResourceLabel = getGitHubRateLimitResourceLabel(entry.rateLimitResource);
|
|
3504
3683
|
if (repositoryLabel) {
|
|
3505
3684
|
rows.push({
|
|
3506
3685
|
label: "Repository",
|
|
@@ -3531,12 +3710,19 @@ function getSyncDiagnostics(syncState) {
|
|
|
3531
3710
|
value: formatDate(rateLimitResetAt, rateLimitResetAt)
|
|
3532
3711
|
});
|
|
3533
3712
|
}
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3713
|
+
if (entry.occurredAt) {
|
|
3714
|
+
rows.push({
|
|
3715
|
+
label: "Captured",
|
|
3716
|
+
value: formatDate(entry.occurredAt, entry.occurredAt)
|
|
3717
|
+
});
|
|
3718
|
+
}
|
|
3719
|
+
const rawMessage = entry.rawMessage && entry.rawMessage !== entry.message ? entry.rawMessage : void 0;
|
|
3720
|
+
const suggestedAction = entry.suggestedAction;
|
|
3721
|
+
if (!entry.message && rows.length === 0 && !rawMessage && !suggestedAction) {
|
|
3537
3722
|
return null;
|
|
3538
3723
|
}
|
|
3539
3724
|
return {
|
|
3725
|
+
message: entry.message,
|
|
3540
3726
|
rows,
|
|
3541
3727
|
...rawMessage ? { rawMessage } : {},
|
|
3542
3728
|
...suggestedAction ? { suggestedAction } : {}
|
|
@@ -3590,31 +3776,76 @@ function SyncProgressPanel(props) {
|
|
|
3590
3776
|
);
|
|
3591
3777
|
}
|
|
3592
3778
|
function SyncDiagnosticsPanel(props) {
|
|
3593
|
-
const
|
|
3779
|
+
const failureEntries = getSyncFailureLogEntries(props.syncState);
|
|
3780
|
+
const latestFailureIndex = Math.max(failureEntries.length - 1, 0);
|
|
3781
|
+
const [selectedFailureIndex, setSelectedFailureIndex] = useState(latestFailureIndex);
|
|
3782
|
+
const selectedFailure = failureEntries[Math.min(selectedFailureIndex, latestFailureIndex)];
|
|
3783
|
+
const diagnostics = selectedFailure ? getSyncDiagnostics(selectedFailure) : null;
|
|
3594
3784
|
const requestError = props.requestError?.trim() ? props.requestError.trim() : null;
|
|
3785
|
+
const canSelectFailures = !props.compact && failureEntries.length > 1;
|
|
3786
|
+
const savedFailureCount = props.syncState.erroredIssuesCount ?? failureEntries.length;
|
|
3787
|
+
useEffect(() => {
|
|
3788
|
+
setSelectedFailureIndex(latestFailureIndex);
|
|
3789
|
+
}, [latestFailureIndex, props.syncState.checkedAt, props.syncState.status]);
|
|
3595
3790
|
if (!diagnostics && !requestError) {
|
|
3596
3791
|
return null;
|
|
3597
3792
|
}
|
|
3598
3793
|
return /* @__PURE__ */ jsxs("section", { className: `ghsync-diagnostics${props.compact ? " ghsync-diagnostics--compact" : ""}`, children: [
|
|
3599
3794
|
/* @__PURE__ */ jsxs("div", { className: "ghsync-diagnostics__header", children: [
|
|
3600
3795
|
/* @__PURE__ */ jsx("strong", { children: diagnostics ? "Troubleshooting details" : "Sync request failed" }),
|
|
3601
|
-
/* @__PURE__ */ jsx("span", { children: diagnostics ? "GitHub Sync saved this snapshot from the latest failed run." : "The sync request failed before the worker returned a saved result." })
|
|
3796
|
+
/* @__PURE__ */ jsx("span", { children: diagnostics ? canSelectFailures ? savedFailureCount > failureEntries.length ? `GitHub Sync saved the latest ${failureEntries.length} of ${savedFailureCount} failures from the latest run. Select one to inspect.` : `GitHub Sync saved ${failureEntries.length} failure${failureEntries.length === 1 ? "" : "s"} from the latest run. Select one to inspect.` : "GitHub Sync saved this snapshot from the latest failed run." : "The sync request failed before the worker returned a saved result." })
|
|
3602
3797
|
] }),
|
|
3603
3798
|
requestError ? /* @__PURE__ */ jsxs("div", { className: "ghsync-diagnostics__block", children: [
|
|
3604
3799
|
/* @__PURE__ */ jsx("span", { className: "ghsync-diagnostics__label", children: "Request error" }),
|
|
3605
3800
|
/* @__PURE__ */ jsx("div", { className: "ghsync-diagnostics__value ghsync-diagnostics__value--code", children: requestError })
|
|
3606
3801
|
] }) : null,
|
|
3607
|
-
diagnostics
|
|
3608
|
-
/* @__PURE__ */ jsx("
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3802
|
+
diagnostics ? /* @__PURE__ */ jsxs("div", { className: `ghsync-diagnostics__layout${canSelectFailures ? " ghsync-diagnostics__layout--split" : ""}`, children: [
|
|
3803
|
+
canSelectFailures ? /* @__PURE__ */ jsx("ul", { className: "ghsync-diagnostics__failures", "aria-label": "Latest sync failures", children: failureEntries.map((failure, index) => {
|
|
3804
|
+
const repositoryLabel = formatSyncFailureRepository(failure.repositoryUrl);
|
|
3805
|
+
const issueLabel = failure.githubIssueNumber !== void 0 ? `Issue #${failure.githubIssueNumber}` : null;
|
|
3806
|
+
const phaseLabel = formatSyncFailurePhase(failure.phase);
|
|
3807
|
+
const title = [repositoryLabel, issueLabel].filter((value) => Boolean(value)).join(" \xB7 ");
|
|
3808
|
+
const meta = [phaseLabel, failure.occurredAt ? formatDate(failure.occurredAt, failure.occurredAt) : null].filter((value) => Boolean(value)).join(" \xB7 ");
|
|
3809
|
+
return /* @__PURE__ */ jsx(
|
|
3810
|
+
"li",
|
|
3811
|
+
{
|
|
3812
|
+
className: "ghsync-diagnostics__failure-item",
|
|
3813
|
+
children: /* @__PURE__ */ jsxs(
|
|
3814
|
+
"button",
|
|
3815
|
+
{
|
|
3816
|
+
type: "button",
|
|
3817
|
+
className: `ghsync-diagnostics__failure${index === selectedFailureIndex ? " ghsync-diagnostics__failure--active" : ""}`,
|
|
3818
|
+
"aria-pressed": index === selectedFailureIndex,
|
|
3819
|
+
onClick: () => setSelectedFailureIndex(index),
|
|
3820
|
+
children: [
|
|
3821
|
+
/* @__PURE__ */ jsx("strong", { className: "ghsync-diagnostics__failure-title", children: title || `Failure ${index + 1}` }),
|
|
3822
|
+
meta ? /* @__PURE__ */ jsx("span", { className: "ghsync-diagnostics__failure-meta", children: meta }) : null,
|
|
3823
|
+
/* @__PURE__ */ jsx("span", { className: "ghsync-diagnostics__failure-preview", children: failure.message })
|
|
3824
|
+
]
|
|
3825
|
+
}
|
|
3826
|
+
)
|
|
3827
|
+
},
|
|
3828
|
+
`${failure.occurredAt ?? "unknown"}-${failure.githubIssueNumber ?? "no-issue"}-${index}`
|
|
3829
|
+
);
|
|
3830
|
+
}) }) : null,
|
|
3831
|
+
/* @__PURE__ */ jsxs("div", { className: "ghsync-diagnostics__detail", children: [
|
|
3832
|
+
/* @__PURE__ */ jsxs("div", { className: "ghsync-diagnostics__block", children: [
|
|
3833
|
+
/* @__PURE__ */ jsx("span", { className: "ghsync-diagnostics__label", children: "Summary" }),
|
|
3834
|
+
/* @__PURE__ */ jsx("div", { className: "ghsync-diagnostics__value", children: diagnostics.message })
|
|
3835
|
+
] }),
|
|
3836
|
+
diagnostics.rows.length ? /* @__PURE__ */ jsx("div", { className: "ghsync-diagnostics__grid", children: diagnostics.rows.map((row) => /* @__PURE__ */ jsxs("div", { className: "ghsync-diagnostics__item", children: [
|
|
3837
|
+
/* @__PURE__ */ jsx("span", { className: "ghsync-diagnostics__label", children: row.label }),
|
|
3838
|
+
/* @__PURE__ */ jsx("strong", { className: "ghsync-diagnostics__value", children: row.value })
|
|
3839
|
+
] }, row.label)) }) : null,
|
|
3840
|
+
diagnostics.rawMessage ? /* @__PURE__ */ jsxs("div", { className: "ghsync-diagnostics__block", children: [
|
|
3841
|
+
/* @__PURE__ */ jsx("span", { className: "ghsync-diagnostics__label", children: "Raw error" }),
|
|
3842
|
+
/* @__PURE__ */ jsx("div", { className: "ghsync-diagnostics__value ghsync-diagnostics__value--code", children: diagnostics.rawMessage })
|
|
3843
|
+
] }) : null,
|
|
3844
|
+
diagnostics.suggestedAction ? /* @__PURE__ */ jsxs("div", { className: "ghsync-diagnostics__block", children: [
|
|
3845
|
+
/* @__PURE__ */ jsx("span", { className: "ghsync-diagnostics__label", children: "Next step" }),
|
|
3846
|
+
/* @__PURE__ */ jsx("div", { className: "ghsync-diagnostics__value", children: diagnostics.suggestedAction })
|
|
3847
|
+
] }) : null
|
|
3848
|
+
] })
|
|
3618
3849
|
] }) : null
|
|
3619
3850
|
] });
|
|
3620
3851
|
}
|
|
@@ -3630,11 +3861,13 @@ function GitHubSyncSettingsPage() {
|
|
|
3630
3861
|
const updateBoardAccess = usePluginAction("settings.updateBoardAccess");
|
|
3631
3862
|
const validateToken = usePluginAction("settings.validateToken");
|
|
3632
3863
|
const runSyncNow = usePluginAction("sync.runNow");
|
|
3864
|
+
const cancelSync = usePluginAction("sync.cancel");
|
|
3633
3865
|
const [form, setForm] = useState(EMPTY_SETTINGS);
|
|
3634
3866
|
const [submittingToken, setSubmittingToken] = useState(false);
|
|
3635
3867
|
const [connectingBoardAccess, setConnectingBoardAccess] = useState(false);
|
|
3636
3868
|
const [submittingSetup, setSubmittingSetup] = useState(false);
|
|
3637
3869
|
const [runningSync, setRunningSync] = useState(false);
|
|
3870
|
+
const [cancellingSync, setCancellingSync] = useState(false);
|
|
3638
3871
|
const [manualSyncRequestError, setManualSyncRequestError] = useState(null);
|
|
3639
3872
|
const [scheduleFrequencyDraft, setScheduleFrequencyDraft] = useState(String(DEFAULT_SCHEDULE_FREQUENCY_MINUTES));
|
|
3640
3873
|
const [ignoredAuthorsDraft, setIgnoredAuthorsDraft] = useState(DEFAULT_ADVANCED_SETTINGS.ignoredIssueAuthorUsernames.join(", "));
|
|
@@ -3897,6 +4130,10 @@ function GitHubSyncSettingsPage() {
|
|
|
3897
4130
|
hasMappings: savedMappingCount > 0,
|
|
3898
4131
|
hasBoardAccess: boardAccessReady
|
|
3899
4132
|
});
|
|
4133
|
+
const syncPersistedRunning = displaySyncState.status === "running";
|
|
4134
|
+
const syncStartPending = runningSync && !syncPersistedRunning;
|
|
4135
|
+
const syncInFlight = syncStartPending || syncPersistedRunning;
|
|
4136
|
+
const cancellationRequested = syncPersistedRunning && (cancellingSync || isSyncCancellationRequested(displaySyncState));
|
|
3900
4137
|
const mappingsDirty = JSON.stringify(draftMappings) !== JSON.stringify(savedMappings);
|
|
3901
4138
|
const advancedSettingsDirty = JSON.stringify(draftAdvancedSettings) !== JSON.stringify(savedAdvancedSettings);
|
|
3902
4139
|
const scheduleFrequencyError = getScheduleFrequencyError(scheduleFrequencyDraft);
|
|
@@ -3904,7 +4141,6 @@ function GitHubSyncSettingsPage() {
|
|
|
3904
4141
|
const savedScheduleFrequencyMinutes = normalizeScheduleFrequencyMinutes(currentSettings?.scheduleFrequencyMinutes);
|
|
3905
4142
|
const scheduleDirty = scheduleFrequencyError === null && scheduleFrequencyMinutes !== savedScheduleFrequencyMinutes;
|
|
3906
4143
|
const mappings = form.mappings.length > 0 ? form.mappings : [createEmptyMapping(0)];
|
|
3907
|
-
const syncInFlight = runningSync || displaySyncState.status === "running";
|
|
3908
4144
|
const settingsMutationsLocked = syncInFlight;
|
|
3909
4145
|
const settingsMutationsLockReason = settingsMutationsLocked ? "Settings are temporarily locked while a sync is running to avoid overwriting local edits." : null;
|
|
3910
4146
|
const syncStatus = getSyncStatus(displaySyncState, runningSync, syncUnlocked);
|
|
@@ -3926,10 +4162,11 @@ function GitHubSyncSettingsPage() {
|
|
|
3926
4162
|
savedMappingCount
|
|
3927
4163
|
});
|
|
3928
4164
|
const syncSectionDescription = "";
|
|
3929
|
-
const syncSummaryPrimaryText = syncProgress?.title ?? displaySyncState.message ?? (syncUnlocked ? "Ready to sync." : syncSetupMessage);
|
|
4165
|
+
const syncSummaryPrimaryText = (cancellationRequested ? "Cancellation requested." : void 0) ?? syncProgress?.title ?? displaySyncState.message ?? (syncUnlocked ? "Ready to sync." : syncSetupMessage);
|
|
3930
4166
|
const manualSyncScopeSummary = hasCompanyContext ? `Manual sync: ${currentCompanyName}` : "Manual sync: all companies";
|
|
3931
4167
|
const syncSummarySecondaryText = syncProgress ? [
|
|
3932
4168
|
manualSyncScopeSummary,
|
|
4169
|
+
cancellationRequested ? "Stopping after the current step" : null,
|
|
3933
4170
|
syncProgress.issueProgressLabel,
|
|
3934
4171
|
syncProgress.currentIssueLabel ?? syncProgress.repositoryPosition,
|
|
3935
4172
|
`Auto-sync: ${scheduleDescription}`
|
|
@@ -4298,6 +4535,46 @@ function GitHubSyncSettingsPage() {
|
|
|
4298
4535
|
setRunningSync(false);
|
|
4299
4536
|
}
|
|
4300
4537
|
}
|
|
4538
|
+
async function handleCancelSync() {
|
|
4539
|
+
if (!syncPersistedRunning) {
|
|
4540
|
+
return;
|
|
4541
|
+
}
|
|
4542
|
+
setCancellingSync(true);
|
|
4543
|
+
setManualSyncRequestError(null);
|
|
4544
|
+
try {
|
|
4545
|
+
const result = await cancelSync();
|
|
4546
|
+
setForm((current) => ({
|
|
4547
|
+
...current,
|
|
4548
|
+
syncState: result.syncState
|
|
4549
|
+
}));
|
|
4550
|
+
toast({
|
|
4551
|
+
title: getSyncToastTitle(result.syncState),
|
|
4552
|
+
body: getSyncToastBody(result.syncState),
|
|
4553
|
+
tone: getSyncToastTone(result.syncState)
|
|
4554
|
+
});
|
|
4555
|
+
armSyncCompletionToast(result.syncState);
|
|
4556
|
+
try {
|
|
4557
|
+
await settings.refresh();
|
|
4558
|
+
} catch {
|
|
4559
|
+
return;
|
|
4560
|
+
}
|
|
4561
|
+
} catch (error) {
|
|
4562
|
+
const message = error instanceof Error ? error.message : "Unable to cancel sync.";
|
|
4563
|
+
setManualSyncRequestError(message);
|
|
4564
|
+
toast({
|
|
4565
|
+
title: "Unable to cancel GitHub sync",
|
|
4566
|
+
body: message,
|
|
4567
|
+
tone: "error"
|
|
4568
|
+
});
|
|
4569
|
+
try {
|
|
4570
|
+
await settings.refresh();
|
|
4571
|
+
} catch {
|
|
4572
|
+
return;
|
|
4573
|
+
}
|
|
4574
|
+
} finally {
|
|
4575
|
+
setCancellingSync(false);
|
|
4576
|
+
}
|
|
4577
|
+
}
|
|
4301
4578
|
return /* @__PURE__ */ jsxs("div", { className: "ghsync", style: themeVars, children: [
|
|
4302
4579
|
/* @__PURE__ */ jsx("style", { children: PAGE_STYLES }),
|
|
4303
4580
|
/* @__PURE__ */ jsxs("section", { className: "ghsync__header", children: [
|
|
@@ -4752,10 +5029,10 @@ function GitHubSyncSettingsPage() {
|
|
|
4752
5029
|
"button",
|
|
4753
5030
|
{
|
|
4754
5031
|
type: "button",
|
|
4755
|
-
className: getPluginActionClassName({ variant: "primary" }),
|
|
4756
|
-
onClick: handleRunSyncNow,
|
|
4757
|
-
disabled:
|
|
4758
|
-
children:
|
|
5032
|
+
className: getPluginActionClassName({ variant: syncPersistedRunning ? "danger" : "primary" }),
|
|
5033
|
+
onClick: syncPersistedRunning ? handleCancelSync : handleRunSyncNow,
|
|
5034
|
+
disabled: showInitialLoadingState || syncStartPending || (syncPersistedRunning ? cancellationRequested : false),
|
|
5035
|
+
children: syncPersistedRunning ? cancellationRequested ? "Cancelling\u2026" : "Cancel sync" : syncStartPending ? "Running\u2026" : manualSyncButtonLabel
|
|
4759
5036
|
}
|
|
4760
5037
|
)
|
|
4761
5038
|
] })
|
|
@@ -4841,7 +5118,9 @@ function GitHubSyncDashboardWidget() {
|
|
|
4841
5118
|
hostContext.companyId ? { companyId: hostContext.companyId } : {}
|
|
4842
5119
|
);
|
|
4843
5120
|
const runSyncNow = usePluginAction("sync.runNow");
|
|
5121
|
+
const cancelSync = usePluginAction("sync.cancel");
|
|
4844
5122
|
const [runningSync, setRunningSync] = useState(false);
|
|
5123
|
+
const [cancellingSync, setCancellingSync] = useState(false);
|
|
4845
5124
|
const [manualSyncRequestError, setManualSyncRequestError] = useState(null);
|
|
4846
5125
|
const [settingsHref, setSettingsHref] = useState(SETTINGS_INDEX_HREF2);
|
|
4847
5126
|
const [cachedSettings, setCachedSettings] = useState(null);
|
|
@@ -4872,7 +5151,10 @@ function GitHubSyncDashboardWidget() {
|
|
|
4872
5151
|
hasBoardAccess: boardAccessReady
|
|
4873
5152
|
});
|
|
4874
5153
|
const syncUnlocked = syncSetupIssue === null;
|
|
4875
|
-
const
|
|
5154
|
+
const syncPersistedRunning = displaySyncState.status === "running";
|
|
5155
|
+
const syncStartPending = runningSync && !syncPersistedRunning;
|
|
5156
|
+
const syncInFlight = syncStartPending || syncPersistedRunning;
|
|
5157
|
+
const cancellationRequested = syncPersistedRunning && (cancellingSync || isSyncCancellationRequested(displaySyncState));
|
|
4876
5158
|
const scheduleFrequencyMinutes = normalizeScheduleFrequencyMinutes(current.scheduleFrequencyMinutes);
|
|
4877
5159
|
const scheduleDescription = formatScheduleFrequency(scheduleFrequencyMinutes);
|
|
4878
5160
|
const summary = getDashboardSummary({
|
|
@@ -4972,6 +5254,34 @@ function GitHubSyncDashboardWidget() {
|
|
|
4972
5254
|
setRunningSync(false);
|
|
4973
5255
|
}
|
|
4974
5256
|
}
|
|
5257
|
+
async function handleCancelSync() {
|
|
5258
|
+
if (!syncPersistedRunning) {
|
|
5259
|
+
return;
|
|
5260
|
+
}
|
|
5261
|
+
setCancellingSync(true);
|
|
5262
|
+
setManualSyncRequestError(null);
|
|
5263
|
+
try {
|
|
5264
|
+
const result = await cancelSync();
|
|
5265
|
+
const nextSyncState = result.syncState ?? EMPTY_SETTINGS.syncState;
|
|
5266
|
+
toast({
|
|
5267
|
+
title: getSyncToastTitle(nextSyncState),
|
|
5268
|
+
body: getSyncToastBody(nextSyncState),
|
|
5269
|
+
tone: getSyncToastTone(nextSyncState)
|
|
5270
|
+
});
|
|
5271
|
+
armSyncCompletionToast(nextSyncState);
|
|
5272
|
+
await settings.refresh();
|
|
5273
|
+
} catch (error) {
|
|
5274
|
+
const message = error instanceof Error ? error.message : "Unable to cancel GitHub sync.";
|
|
5275
|
+
setManualSyncRequestError(message);
|
|
5276
|
+
toast({
|
|
5277
|
+
title: "Unable to cancel GitHub sync",
|
|
5278
|
+
body: message,
|
|
5279
|
+
tone: "error"
|
|
5280
|
+
});
|
|
5281
|
+
} finally {
|
|
5282
|
+
setCancellingSync(false);
|
|
5283
|
+
}
|
|
5284
|
+
}
|
|
4975
5285
|
return /* @__PURE__ */ jsxs("section", { className: "ghsync-widget", style: themeVars, children: [
|
|
4976
5286
|
/* @__PURE__ */ jsx("style", { children: WIDGET_STYLES }),
|
|
4977
5287
|
/* @__PURE__ */ jsxs("div", { className: "ghsync-widget__card", children: [
|
|
@@ -5054,10 +5364,10 @@ function GitHubSyncDashboardWidget() {
|
|
|
5054
5364
|
"button",
|
|
5055
5365
|
{
|
|
5056
5366
|
type: "button",
|
|
5057
|
-
className: getPluginActionClassName({ variant: "primary" }),
|
|
5058
|
-
onClick: handleRunSync,
|
|
5059
|
-
disabled:
|
|
5060
|
-
children:
|
|
5367
|
+
className: getPluginActionClassName({ variant: syncPersistedRunning ? "danger" : "primary" }),
|
|
5368
|
+
onClick: syncPersistedRunning ? handleCancelSync : handleRunSync,
|
|
5369
|
+
disabled: showInitialLoadingState || syncStartPending || (syncPersistedRunning ? cancellationRequested : false),
|
|
5370
|
+
children: syncPersistedRunning ? cancellationRequested ? "Cancelling\u2026" : "Cancel sync" : syncStartPending ? "Running\u2026" : "Run sync now"
|
|
5061
5371
|
}
|
|
5062
5372
|
) : null
|
|
5063
5373
|
] }) })
|
|
@@ -5085,6 +5395,7 @@ function GitHubMarkIcon(props) {
|
|
|
5085
5395
|
function GitHubSyncToolbarButtonSurface(props) {
|
|
5086
5396
|
const toast = usePluginToast();
|
|
5087
5397
|
const runSyncNow = usePluginAction("sync.runNow");
|
|
5398
|
+
const cancelSync = usePluginAction("sync.cancel");
|
|
5088
5399
|
const pluginIdFromLocation = getPluginIdFromLocation();
|
|
5089
5400
|
const surfaceRef = useRef(null);
|
|
5090
5401
|
const resolvedIssue = useResolvedIssueId({
|
|
@@ -5104,6 +5415,7 @@ function GitHubSyncToolbarButtonSurface(props) {
|
|
|
5104
5415
|
props.companyId ? { companyId: props.companyId } : {}
|
|
5105
5416
|
);
|
|
5106
5417
|
const [runningSync, setRunningSync] = useState(false);
|
|
5418
|
+
const [cancellingSync, setCancellingSync] = useState(false);
|
|
5107
5419
|
const themeMode = useResolvedThemeMode();
|
|
5108
5420
|
const boardAccessRequirement = usePaperclipBoardAccessRequirement();
|
|
5109
5421
|
const theme = themeMode === "light" ? LIGHT_PALETTE : DARK_PALETTE;
|
|
@@ -5123,7 +5435,10 @@ function GitHubSyncToolbarButtonSurface(props) {
|
|
|
5123
5435
|
const effectiveCanRun = state.canRun && !boardAccessSetupIssue;
|
|
5124
5436
|
const effectiveMessage = boardAccessSetupIssue ? getSyncSetupMessage(boardAccessSetupIssue, hasCompanyContext) : state.message;
|
|
5125
5437
|
const effectiveLabel = boardAccessSetupIssue ? "Board access required" : state.label;
|
|
5126
|
-
const
|
|
5438
|
+
const syncPersistedRunning = state.syncState.status === "running";
|
|
5439
|
+
const syncStartPending = runningSync && !syncPersistedRunning;
|
|
5440
|
+
const syncInFlight = syncStartPending || syncPersistedRunning;
|
|
5441
|
+
const cancellationRequested = syncPersistedRunning && (cancellingSync || isSyncCancellationRequested(state.syncState));
|
|
5127
5442
|
const armSyncCompletionToast = useSyncCompletionToast(state.syncState, toast);
|
|
5128
5443
|
useEffect(() => {
|
|
5129
5444
|
if (state.syncState.status !== "running") {
|
|
@@ -5228,6 +5543,31 @@ function GitHubSyncToolbarButtonSurface(props) {
|
|
|
5228
5543
|
setRunningSync(false);
|
|
5229
5544
|
}
|
|
5230
5545
|
}
|
|
5546
|
+
async function handleCancelSync() {
|
|
5547
|
+
if (!syncPersistedRunning) {
|
|
5548
|
+
return;
|
|
5549
|
+
}
|
|
5550
|
+
try {
|
|
5551
|
+
setCancellingSync(true);
|
|
5552
|
+
const result = await cancelSync();
|
|
5553
|
+
const nextSyncState = result.syncState ?? EMPTY_SETTINGS.syncState;
|
|
5554
|
+
toast({
|
|
5555
|
+
title: getSyncToastTitle(nextSyncState),
|
|
5556
|
+
body: getSyncToastBody(nextSyncState),
|
|
5557
|
+
tone: getSyncToastTone(nextSyncState)
|
|
5558
|
+
});
|
|
5559
|
+
armSyncCompletionToast(nextSyncState);
|
|
5560
|
+
toolbarState.refresh();
|
|
5561
|
+
} catch (error) {
|
|
5562
|
+
toast({
|
|
5563
|
+
title: "Unable to cancel GitHub sync",
|
|
5564
|
+
body: error instanceof Error ? error.message : "Unable to cancel GitHub sync.",
|
|
5565
|
+
tone: "error"
|
|
5566
|
+
});
|
|
5567
|
+
} finally {
|
|
5568
|
+
setCancellingSync(false);
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5231
5571
|
return /* @__PURE__ */ jsxs(
|
|
5232
5572
|
"div",
|
|
5233
5573
|
{
|
|
@@ -5245,11 +5585,11 @@ function GitHubSyncToolbarButtonSurface(props) {
|
|
|
5245
5585
|
"data-variant": "outline",
|
|
5246
5586
|
"data-size": "sm",
|
|
5247
5587
|
className: props.entityType ? HOST_ENTITY_BUTTON_CLASSNAME : HOST_GLOBAL_BUTTON_CLASSNAME,
|
|
5248
|
-
disabled:
|
|
5249
|
-
onClick: handleRunSync,
|
|
5588
|
+
disabled: toolbarState.loading || syncStartPending || (syncPersistedRunning ? cancellationRequested : !effectiveCanRun),
|
|
5589
|
+
onClick: syncPersistedRunning ? handleCancelSync : handleRunSync,
|
|
5250
5590
|
children: [
|
|
5251
5591
|
/* @__PURE__ */ jsx(GitHubMarkIcon, { className: "mr-1.5 h-3.5 w-3.5" }),
|
|
5252
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
5592
|
+
/* @__PURE__ */ jsx("span", { children: syncPersistedRunning ? cancellationRequested ? "Cancelling\u2026" : "Cancel sync" : syncStartPending ? "Syncing\u2026" : effectiveLabel })
|
|
5253
5593
|
]
|
|
5254
5594
|
}
|
|
5255
5595
|
)
|