@inventec/dsh-copilot-auth 1.2.7 → 1.2.9
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 +39 -25
- package/lib/client.js +851 -273
- package/package.json +9 -2
- package/src/auth-flow.mjs +213 -0
- package/src/auth-host.mjs +192 -0
- package/src/client-http.mjs +80 -0
- package/src/host.mjs +357 -636
- package/src/model-update.mjs +118 -0
- package/src/refresh-flow.mjs +200 -86
- package/src/refresh-service.mjs +276 -0
- package/src/refresh-transaction.mjs +573 -0
- package/src/runtime-scope.mjs +25 -0
- package/src/shared.mjs +3 -0
- package/src/state.mjs +61 -60
package/lib/client.js
CHANGED
|
@@ -34,68 +34,250 @@ var import_react = require("react");
|
|
|
34
34
|
|
|
35
35
|
// src/shared.mjs
|
|
36
36
|
var ROUTE_PREFIX = "/copilot-auth";
|
|
37
|
+
var PROTOCOL_VERSION = 2;
|
|
37
38
|
var routes = () => ({
|
|
38
39
|
start: `${ROUTE_PREFIX}/start`,
|
|
39
40
|
state: `${ROUTE_PREFIX}/state`,
|
|
40
41
|
status: `${ROUTE_PREFIX}/status`,
|
|
41
42
|
logout: `${ROUTE_PREFIX}/logout`,
|
|
43
|
+
cancel: `${ROUTE_PREFIX}/cancel`,
|
|
42
44
|
refreshPreview: `${ROUTE_PREFIX}/refresh/preview`,
|
|
43
|
-
refreshApply: `${ROUTE_PREFIX}/refresh/apply
|
|
45
|
+
refreshApply: `${ROUTE_PREFIX}/refresh/apply`,
|
|
46
|
+
refreshRetire: `${ROUTE_PREFIX}/refresh/retire`
|
|
44
47
|
});
|
|
45
48
|
|
|
49
|
+
// src/client-http.mjs
|
|
50
|
+
var SAFE_ERROR_CODE = /^[A-Za-z][A-Za-z0-9 -]{0,79}$/;
|
|
51
|
+
var SAFE_CONTENT_TYPE = /^[\w./+-]{0,100}$/;
|
|
52
|
+
function sanitizeErrorCode(value) {
|
|
53
|
+
return typeof value === "string" && SAFE_ERROR_CODE.test(value) ? value : "http-error";
|
|
54
|
+
}
|
|
55
|
+
var SAFE_STRING = /^[A-Za-z0-9][A-Za-z0-9 -]{0,127}$/;
|
|
56
|
+
function deepSanitize(value) {
|
|
57
|
+
if (typeof value === "string") return SAFE_STRING.test(value) ? value : void 0;
|
|
58
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") return value;
|
|
59
|
+
if (Array.isArray(value)) return value.map(deepSanitize);
|
|
60
|
+
if (value && typeof value === "object") {
|
|
61
|
+
const out = {};
|
|
62
|
+
for (const [k, v] of Object.entries(value)) {
|
|
63
|
+
const s = deepSanitize(v);
|
|
64
|
+
if (s !== void 0) out[k] = s;
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
function sanitizeContentType(value) {
|
|
71
|
+
if (typeof value !== "string" || !SAFE_CONTENT_TYPE.test(value)) return void 0;
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
async function requestJson(fetchImpl, url, init = {}) {
|
|
75
|
+
let res;
|
|
76
|
+
try {
|
|
77
|
+
res = await fetchImpl(url, init);
|
|
78
|
+
} catch {
|
|
79
|
+
return { ok: false, httpStatus: null, body: void 0, error: { messageKey: "network-error", details: {} } };
|
|
80
|
+
}
|
|
81
|
+
const httpStatus = res.status;
|
|
82
|
+
let text = "";
|
|
83
|
+
try {
|
|
84
|
+
text = await res.text();
|
|
85
|
+
} catch {
|
|
86
|
+
text = "";
|
|
87
|
+
}
|
|
88
|
+
if (typeof text !== "string" || text.trim() === "") {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
httpStatus,
|
|
92
|
+
body: void 0,
|
|
93
|
+
error: { messageKey: httpStatus >= 500 ? "bad-gateway" : "bad-response", details: { httpStatus } }
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
let body;
|
|
97
|
+
try {
|
|
98
|
+
body = JSON.parse(text);
|
|
99
|
+
} catch {
|
|
100
|
+
const contentType = sanitizeContentType(res.headers?.get?.("content-type"));
|
|
101
|
+
const looksHtml = contentType?.includes("html") || /^\s*<(?:!doctype|html)/i.test(text);
|
|
102
|
+
const messageKey = httpStatus >= 500 || looksHtml ? "bad-gateway" : "bad-response";
|
|
103
|
+
const details2 = { httpStatus };
|
|
104
|
+
if (contentType !== void 0) details2.contentType = contentType;
|
|
105
|
+
return { ok: false, httpStatus, body: void 0, error: { messageKey, details: details2 } };
|
|
106
|
+
}
|
|
107
|
+
const ok = res.ok && body?.ok !== false;
|
|
108
|
+
if (ok) return { ok: true, httpStatus, body, error: void 0 };
|
|
109
|
+
const details = {};
|
|
110
|
+
if (!res.ok) details.httpStatus = httpStatus;
|
|
111
|
+
const errorCode = sanitizeErrorCode(body?.error);
|
|
112
|
+
if (errorCode !== void 0) details.errorCode = errorCode;
|
|
113
|
+
return { ok: false, httpStatus, body: deepSanitize(body), error: { messageKey: "http-error", details } };
|
|
114
|
+
}
|
|
115
|
+
|
|
46
116
|
// src/refresh-flow.mjs
|
|
47
|
-
var initial = Object.freeze({
|
|
117
|
+
var initial = Object.freeze({
|
|
118
|
+
name: "idle",
|
|
119
|
+
flags: { catalogMode: null, blockedReason: null, scopeAvailable: true, legacyStateDetected: false },
|
|
120
|
+
lastResult: null
|
|
121
|
+
});
|
|
122
|
+
var fromRefresh = (state, refresh) => ({
|
|
123
|
+
...state,
|
|
124
|
+
flags: {
|
|
125
|
+
catalogMode: refresh && "catalogMode" in refresh ? refresh.catalogMode : state.flags.catalogMode,
|
|
126
|
+
blockedReason: refresh && "blockedReason" in refresh ? refresh.blockedReason : state.flags.blockedReason,
|
|
127
|
+
scopeAvailable: refresh ? refresh.scopeAvailable !== false : state.flags.scopeAvailable,
|
|
128
|
+
legacyStateDetected: refresh?.legacyStateDetected === true
|
|
129
|
+
},
|
|
130
|
+
lastResult: refresh?.lastResult ?? null
|
|
131
|
+
});
|
|
132
|
+
var restartStates = /* @__PURE__ */ new Set(["pending-restart"]);
|
|
133
|
+
function refreshBlocked(flags) {
|
|
134
|
+
const mode = flags?.catalogMode;
|
|
135
|
+
return flags?.scopeAvailable === false || mode === "blocked" || mode === "unknown";
|
|
136
|
+
}
|
|
48
137
|
function reduce(state, event) {
|
|
49
138
|
switch (state.name) {
|
|
50
139
|
case "idle":
|
|
51
140
|
case "failed":
|
|
52
|
-
case "
|
|
141
|
+
case "result":
|
|
142
|
+
case "pendingRestart":
|
|
143
|
+
case "busy":
|
|
144
|
+
case "resultUnknown": {
|
|
53
145
|
if (event.type === "start") {
|
|
54
|
-
return [{
|
|
146
|
+
return [{
|
|
147
|
+
name: "previewing",
|
|
148
|
+
flags: state.flags ?? initial.flags,
|
|
149
|
+
operation: event.operation === "rebuild" ? "rebuild" : "supplement",
|
|
150
|
+
catalogSource: event.catalogSource,
|
|
151
|
+
stale: false
|
|
152
|
+
}, {
|
|
153
|
+
type: "preview",
|
|
154
|
+
operation: event.operation === "rebuild" ? "rebuild" : "supplement",
|
|
155
|
+
catalogSource: event.catalogSource
|
|
156
|
+
}];
|
|
157
|
+
}
|
|
158
|
+
if (event.type === "init" && state.name === "idle") return [state, { type: "status" }];
|
|
159
|
+
if (event.type === "check" && state.name === "resultUnknown") {
|
|
160
|
+
return [{ ...state, name: "checking", operationId: state.operationId }, { type: "statusQuery", operationId: state.operationId }];
|
|
161
|
+
}
|
|
162
|
+
if (event.type === "retire-request" && state.name === "result") {
|
|
163
|
+
return [{ name: "retireConfirm", result: state.result }, null];
|
|
164
|
+
}
|
|
165
|
+
if (event.type === "dismiss" && state.name === "failed") {
|
|
166
|
+
return [{ ...initial, flags: state.flags }, null];
|
|
55
167
|
}
|
|
56
|
-
if (state.name === "failed" && event.type === "dismiss") return [initial, null];
|
|
57
|
-
if (state.name === "idle" && event.type === "init") return [state, { type: "status" }];
|
|
58
168
|
if (event.type === "hydrate") {
|
|
59
169
|
const refresh = event.status?.refresh;
|
|
60
170
|
if (!event.status) return [state, null];
|
|
61
|
-
if (refresh?.lastError === "state-corrupt") return [{ name: "failed", error: "state-corrupt" }, null];
|
|
62
|
-
|
|
63
|
-
|
|
171
|
+
if (refresh?.lastError === "state-corrupt") return [{ ...state, name: "failed", error: "state-corrupt" }, null];
|
|
172
|
+
const base = fromRefresh({ ...initial, name: "idle" }, refresh);
|
|
173
|
+
if (restartStates.has(refresh?.lastResult?.status ?? "") || refresh?.pendingRestart === true) {
|
|
174
|
+
return [{ ...base, name: "pendingRestart", result: refresh.lastResult }, null];
|
|
64
175
|
}
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
176
|
+
const st = refresh?.lastResult?.status;
|
|
177
|
+
if (st && ["recovery-needed", "rollback-conflict", "conflict", "partial", "rolled-back", "intent-retired", "applied"].includes(st)) {
|
|
178
|
+
return [{ ...base, name: "result", result: refresh.lastResult }, null];
|
|
179
|
+
}
|
|
180
|
+
if (refresh?.activeOperation) return [{ ...base, name: "busy", active: refresh.activeOperation }, null];
|
|
181
|
+
return [base, null];
|
|
68
182
|
}
|
|
69
183
|
return [state, null];
|
|
70
184
|
}
|
|
71
185
|
case "previewing": {
|
|
72
186
|
if (event.type === "preview-ok") {
|
|
73
|
-
return [{ name: "confirming",
|
|
187
|
+
return [{ name: "confirming", flags: state.flags ?? initial.flags, preview: event.preview, staleNotice: state.stale === true }, null];
|
|
74
188
|
}
|
|
75
|
-
if (event.type === "preview-fail") return [{ name: "failed", error: event.error }, null];
|
|
189
|
+
if (event.type === "preview-fail") return [{ name: "failed", flags: state.flags ?? initial.flags, error: event.error }, null];
|
|
76
190
|
return [state, null];
|
|
77
191
|
}
|
|
78
192
|
case "confirming": {
|
|
193
|
+
const p = state.preview;
|
|
194
|
+
if (event.type === "select") {
|
|
195
|
+
return [{
|
|
196
|
+
name: "previewing",
|
|
197
|
+
flags: state.flags ?? initial.flags,
|
|
198
|
+
operation: p.operation,
|
|
199
|
+
catalogSource: p.catalogSource,
|
|
200
|
+
stale: false
|
|
201
|
+
}, {
|
|
202
|
+
type: "preview",
|
|
203
|
+
operation: p.operation,
|
|
204
|
+
catalogSource: p.catalogSource,
|
|
205
|
+
basePreviewId: p.previewId,
|
|
206
|
+
selectedIds: event.selectedIds ?? [],
|
|
207
|
+
confirmEmpty: event.confirmEmpty === true
|
|
208
|
+
}];
|
|
209
|
+
}
|
|
79
210
|
if (event.type === "start") {
|
|
80
|
-
return [{
|
|
211
|
+
return [{
|
|
212
|
+
name: "previewing",
|
|
213
|
+
operation: event.operation === "rebuild" ? "rebuild" : p.operation,
|
|
214
|
+
catalogSource: event.catalogSource,
|
|
215
|
+
stale: false
|
|
216
|
+
}, {
|
|
217
|
+
type: "preview",
|
|
218
|
+
operation: event.operation === "rebuild" ? "rebuild" : p.operation,
|
|
219
|
+
catalogSource: event.catalogSource
|
|
220
|
+
}];
|
|
81
221
|
}
|
|
82
222
|
if (event.type === "confirm") {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
];
|
|
223
|
+
const isRebuild = p.operation === "rebuild";
|
|
224
|
+
const emptyTarget = isRebuild && (p.diff?.targetView?.models ?? []).length === 0;
|
|
225
|
+
if (isRebuild && event.second !== true) return [state, null];
|
|
226
|
+
if (emptyTarget && event.empty !== true) return [state, null];
|
|
227
|
+
if (p.evidence?.stale === true) return [state, null];
|
|
228
|
+
return [{ name: "applying", flags: state.flags ?? initial.flags, preview: p }, { type: "apply", previewId: p.previewId, operationId: p.operationId }];
|
|
87
229
|
}
|
|
88
|
-
if (event.type === "cancel") return [initial, null];
|
|
230
|
+
if (event.type === "cancel") return [{ ...initial, flags: state.flags ?? initial.flags, lastResult: state.lastResult ?? null }, null];
|
|
89
231
|
return [state, null];
|
|
90
232
|
}
|
|
91
233
|
case "applying": {
|
|
92
234
|
if (event.type === "apply-ok") {
|
|
93
|
-
return event.
|
|
235
|
+
return restartStates.has(event.result?.status ?? "") ? [{ ...state, name: "pendingRestart", result: event.result }, null] : [{ ...state, name: "result", result: event.result }, null];
|
|
94
236
|
}
|
|
95
237
|
if (event.type === "apply-stale") {
|
|
96
|
-
return [{
|
|
238
|
+
return [{
|
|
239
|
+
name: "previewing",
|
|
240
|
+
flags: state.flags ?? initial.flags,
|
|
241
|
+
operation: state.preview.operation,
|
|
242
|
+
catalogSource: state.preview.catalogSource,
|
|
243
|
+
stale: true
|
|
244
|
+
}, { type: "preview", operation: state.preview.operation, catalogSource: state.preview.catalogSource }];
|
|
97
245
|
}
|
|
98
|
-
if (event.type === "apply-
|
|
246
|
+
if (event.type === "apply-busy") {
|
|
247
|
+
return [{ ...state, name: "checking" }, { type: "status" }];
|
|
248
|
+
}
|
|
249
|
+
if (event.type === "apply-unknown") {
|
|
250
|
+
return [{ ...state, name: "checking", operationId: state.preview.operationId }, { type: "statusQuery", operationId: state.preview.operationId }];
|
|
251
|
+
}
|
|
252
|
+
if (event.type === "apply-fail") return [{ ...state, name: "failed", error: event.error }, null];
|
|
253
|
+
return [state, null];
|
|
254
|
+
}
|
|
255
|
+
case "checking": {
|
|
256
|
+
if (event.type === "query-result") {
|
|
257
|
+
if (event.query === "active") return [{ ...state, name: "busy", active: event.active }, null];
|
|
258
|
+
if (event.query === "last") {
|
|
259
|
+
return restartStates.has(event.lastResult?.status ?? "") ? [{ ...state, name: "pendingRestart", result: event.lastResult }, null] : [{ ...state, name: "result", result: event.lastResult }, null];
|
|
260
|
+
}
|
|
261
|
+
return [{ ...state, name: "resultUnknown", operationId: state.operationId }, null];
|
|
262
|
+
}
|
|
263
|
+
if (event.type === "hydrate") {
|
|
264
|
+
const refresh = event.status?.refresh;
|
|
265
|
+
if (refresh?.activeOperation) return [{ ...state, name: "busy", active: refresh.activeOperation }, null];
|
|
266
|
+
if (refresh?.lastResult) return [{ ...state, name: "result", result: refresh.lastResult }, null];
|
|
267
|
+
return [{ ...state, name: "resultUnknown", operationId: state.operationId }, null];
|
|
268
|
+
}
|
|
269
|
+
return [state, null];
|
|
270
|
+
}
|
|
271
|
+
case "retireConfirm": {
|
|
272
|
+
if (event.type === "retire-confirm") {
|
|
273
|
+
return [{ name: "retiring", operationId: state.result?.operationId, result: state.result }, { type: "retire", operationId: state.result?.operationId }];
|
|
274
|
+
}
|
|
275
|
+
if (event.type === "cancel") return [{ name: "result", result: state.result }, null];
|
|
276
|
+
return [state, null];
|
|
277
|
+
}
|
|
278
|
+
case "retiring": {
|
|
279
|
+
if (event.type === "retire-ok") return [{ ...state, name: "checking" }, { type: "status" }];
|
|
280
|
+
if (event.type === "retire-fail") return [{ name: "result", result: state.result, retireError: event.error }, null];
|
|
99
281
|
return [state, null];
|
|
100
282
|
}
|
|
101
283
|
default:
|
|
@@ -104,52 +286,58 @@ function reduce(state, event) {
|
|
|
104
286
|
}
|
|
105
287
|
async function runEffect(effect, fetchImpl) {
|
|
106
288
|
const r = routes();
|
|
107
|
-
const post = (url, body) => fetchImpl
|
|
289
|
+
const post = (url, body) => requestJson(fetchImpl, url, {
|
|
108
290
|
method: "POST",
|
|
109
291
|
headers: { "content-type": "application/json" },
|
|
110
|
-
body: JSON.stringify(body)
|
|
292
|
+
body: JSON.stringify({ protocolVersion: PROTOCOL_VERSION, ...body })
|
|
111
293
|
});
|
|
112
294
|
if (effect.type === "preview") {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
295
|
+
const res = await post(r.refreshPreview, {
|
|
296
|
+
operation: effect.operation,
|
|
297
|
+
...effect.catalogSource ? { catalogSource: effect.catalogSource } : {},
|
|
298
|
+
...effect.basePreviewId ? { basePreviewId: effect.basePreviewId, selectedIds: effect.selectedIds ?? [] } : {},
|
|
299
|
+
...effect.confirmEmpty ? { confirmEmpty: true } : {}
|
|
300
|
+
});
|
|
301
|
+
if (res.ok) return { type: "preview-ok", preview: res.body };
|
|
302
|
+
return { type: "preview-fail", error: res.error?.details?.errorCode ?? res.error?.messageKey };
|
|
120
303
|
}
|
|
121
304
|
if (effect.type === "apply") {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return
|
|
130
|
-
type: "apply-ok",
|
|
131
|
-
restartRequired: body.restartRequired !== false,
|
|
132
|
-
mode: body.mode ?? null,
|
|
133
|
-
injected: Array.isArray(body.injected) ? body.injected.length : 0
|
|
134
|
-
} : { type: "apply-fail", error: body?.error ?? `HTTP ${res.status}` };
|
|
135
|
-
} catch (err) {
|
|
136
|
-
return { type: "apply-fail", error: String(err?.message ?? err) };
|
|
305
|
+
const res = await post(r.refreshApply, { previewId: effect.previewId, operationId: effect.operationId });
|
|
306
|
+
if (res.ok) return { type: "apply-ok", result: res.body?.result ?? { status: "unknown" } };
|
|
307
|
+
const code = res.error?.details?.errorCode ?? "";
|
|
308
|
+
const status = res.httpStatus;
|
|
309
|
+
if (status === null) return { type: "apply-unknown" };
|
|
310
|
+
if (status === 423 || code === "resource-busy") return { type: "apply-busy" };
|
|
311
|
+
if (status === 409 && ["preview-stale", "auth-changed", "preview-invalid"].includes(code)) {
|
|
312
|
+
return { type: "apply-stale", error: code };
|
|
137
313
|
}
|
|
314
|
+
return { type: "apply-fail", error: code || res.error?.messageKey };
|
|
315
|
+
}
|
|
316
|
+
if (effect.type === "retire") {
|
|
317
|
+
const res = await post(r.refreshRetire, { operationId: effect.operationId });
|
|
318
|
+
if (res.ok) return { type: "retire-ok", result: res.body?.result ?? null };
|
|
319
|
+
return { type: "retire-fail", error: res.error?.details?.errorCode ?? res.error?.messageKey };
|
|
138
320
|
}
|
|
139
321
|
if (effect.type === "status") {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
322
|
+
const res = await requestJson(fetchImpl, r.status, { method: "GET" });
|
|
323
|
+
if (res.ok) return { type: "hydrate", status: res.body };
|
|
324
|
+
return { type: "hydrate", status: null };
|
|
325
|
+
}
|
|
326
|
+
if (effect.type === "statusQuery") {
|
|
327
|
+
const res = await requestJson(fetchImpl, `${r.status}?operationId=${encodeURIComponent(effect.operationId ?? "")}`, { method: "GET" });
|
|
328
|
+
if (res.ok && res.body?.operation) {
|
|
329
|
+
return { type: "query-result", query: res.body.operation.query, active: res.body.operation.active, lastResult: res.body.operation.lastResult };
|
|
145
330
|
}
|
|
331
|
+
return { type: "query-result", query: "unknown" };
|
|
146
332
|
}
|
|
147
333
|
throw new Error(`unknown effect: ${effect.type}`);
|
|
148
334
|
}
|
|
149
335
|
async function advance(state, event, fetchImpl, onState) {
|
|
150
336
|
let [s, fx] = reduce(state, event);
|
|
151
337
|
onState?.(s);
|
|
338
|
+
let guard = 0;
|
|
152
339
|
while (fx) {
|
|
340
|
+
if (guard++ > 8) throw new Error("effect loop guard");
|
|
153
341
|
const resultEvent = await runEffect(fx, fetchImpl);
|
|
154
342
|
[s, fx] = reduce(s, resultEvent);
|
|
155
343
|
onState?.(s);
|
|
@@ -157,6 +345,192 @@ async function advance(state, event, fetchImpl, onState) {
|
|
|
157
345
|
return s;
|
|
158
346
|
}
|
|
159
347
|
|
|
348
|
+
// src/auth-flow.mjs
|
|
349
|
+
var POLL_INTERVAL_MS = 1e3;
|
|
350
|
+
var BACKOFF_STEPS_S = [1, 2, 4, 8, 15];
|
|
351
|
+
var AUTO_RETRY_LIMIT_MS = 6e4;
|
|
352
|
+
var LIVE_STATUSES = ["starting", "waiting", "finishing"];
|
|
353
|
+
var defaultClock = () => ({
|
|
354
|
+
now: () => Date.now(),
|
|
355
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
356
|
+
clearTimeout: (id) => clearTimeout(id)
|
|
357
|
+
});
|
|
358
|
+
function createAuthFlow({ fetchImpl, clock = defaultClock(), onState = () => {
|
|
359
|
+
} } = {}) {
|
|
360
|
+
let generation = 0;
|
|
361
|
+
let timer = null;
|
|
362
|
+
let failures = 0;
|
|
363
|
+
let backoffIdx = 0;
|
|
364
|
+
let failureWindowStart = null;
|
|
365
|
+
let last = { phase: "loading", connectivity: "online", shared: false };
|
|
366
|
+
const emit = (patch) => {
|
|
367
|
+
last = { ...last, ...patch };
|
|
368
|
+
onState({ ...last });
|
|
369
|
+
};
|
|
370
|
+
const stale = (gen) => gen !== generation;
|
|
371
|
+
const clearTimer = () => {
|
|
372
|
+
if (timer !== null) {
|
|
373
|
+
clock.clearTimeout(timer);
|
|
374
|
+
timer = null;
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
const schedule = (gen, delayMs, fn = () => pollTick(gen)) => {
|
|
378
|
+
if (stale(gen)) return;
|
|
379
|
+
clearTimer();
|
|
380
|
+
timer = clock.setTimeout(() => {
|
|
381
|
+
timer = null;
|
|
382
|
+
void fn();
|
|
383
|
+
}, delayMs);
|
|
384
|
+
};
|
|
385
|
+
function applySnapshot(gen, s) {
|
|
386
|
+
if (stale(gen)) return;
|
|
387
|
+
emit({ attempt: s, riskLatch: s?.riskLatch ?? null });
|
|
388
|
+
if (LIVE_STATUSES.includes(s?.status)) {
|
|
389
|
+
emit({ phase: "waiting" });
|
|
390
|
+
schedule(gen, POLL_INTERVAL_MS);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if (s?.status === "authorized") {
|
|
394
|
+
emit({ phase: "authorized", error: void 0 });
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (s?.status === "failed") {
|
|
398
|
+
emit({ phase: "failed", error: s?.error ?? "authorization-failed" });
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
if (s?.status === "withdrawal-pending-unverified" || s?.status === "timed-out-unverified") {
|
|
402
|
+
emit({ phase: "risk", riskKind: s.status });
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
emit({ phase: "idle" });
|
|
406
|
+
}
|
|
407
|
+
async function pollTick(gen) {
|
|
408
|
+
const r = await requestJson(fetchImpl, "/copilot-auth/state", { method: "GET" });
|
|
409
|
+
if (stale(gen)) return;
|
|
410
|
+
if (r.ok) {
|
|
411
|
+
failures = 0;
|
|
412
|
+
backoffIdx = 0;
|
|
413
|
+
failureWindowStart = null;
|
|
414
|
+
emit({ connectivity: "online" });
|
|
415
|
+
applySnapshot(gen, r.body);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
failures += 1;
|
|
419
|
+
if (failureWindowStart === null) failureWindowStart = clock.now();
|
|
420
|
+
const cumulative = clock.now() - failureWindowStart;
|
|
421
|
+
if (cumulative >= AUTO_RETRY_LIMIT_MS) {
|
|
422
|
+
emit({ connectivity: "manual" });
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
emit({ connectivity: "retrying" });
|
|
426
|
+
const delayS = BACKOFF_STEPS_S[Math.min(backoffIdx, BACKOFF_STEPS_S.length - 1)];
|
|
427
|
+
backoffIdx += 1;
|
|
428
|
+
schedule(gen, delayS * 1e3);
|
|
429
|
+
}
|
|
430
|
+
function beginPolling(gen) {
|
|
431
|
+
void pollTick(gen);
|
|
432
|
+
}
|
|
433
|
+
async function init() {
|
|
434
|
+
const gen = ++generation;
|
|
435
|
+
clearTimer();
|
|
436
|
+
failures = 0;
|
|
437
|
+
backoffIdx = 0;
|
|
438
|
+
failureWindowStart = null;
|
|
439
|
+
await initAttempt(gen);
|
|
440
|
+
}
|
|
441
|
+
async function initAttempt(gen) {
|
|
442
|
+
const status = await requestJson(fetchImpl, "/copilot-auth/status", { method: "GET" });
|
|
443
|
+
if (stale(gen)) return;
|
|
444
|
+
if (!status.ok) {
|
|
445
|
+
failures += 1;
|
|
446
|
+
if (failureWindowStart === null) failureWindowStart = clock.now();
|
|
447
|
+
const cumulative = clock.now() - failureWindowStart;
|
|
448
|
+
if (cumulative >= AUTO_RETRY_LIMIT_MS) {
|
|
449
|
+
emit({ phase: "idle", error: status.error?.messageKey, connectivity: "manual" });
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
emit({ phase: "loading", connectivity: "retrying", error: status.error?.messageKey });
|
|
453
|
+
const delayS = BACKOFF_STEPS_S[Math.min(backoffIdx, BACKOFF_STEPS_S.length - 1)];
|
|
454
|
+
backoffIdx += 1;
|
|
455
|
+
schedule(gen, delayS * 1e3, () => initAttempt(gen));
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
failures = 0;
|
|
459
|
+
backoffIdx = 0;
|
|
460
|
+
failureWindowStart = null;
|
|
461
|
+
emit({ connectivity: "online" });
|
|
462
|
+
const body = status.body ?? {};
|
|
463
|
+
if (body.refresh?.scopeAvailable === false) {
|
|
464
|
+
emit({ phase: "unavailable" });
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
emit({ status: body });
|
|
468
|
+
if (body.authorization?.riskLatch) {
|
|
469
|
+
emit({ riskLatch: body.authorization.riskLatch });
|
|
470
|
+
}
|
|
471
|
+
if (body.configured === true) {
|
|
472
|
+
emit({ phase: "authorized", error: void 0 });
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const r = await requestJson(fetchImpl, "/copilot-auth/state", { method: "GET" });
|
|
476
|
+
if (stale(gen)) return;
|
|
477
|
+
if (!r.ok) {
|
|
478
|
+
emit({ phase: "idle", error: r.error?.messageKey, connectivity: "manual" });
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
applySnapshot(gen, r.body);
|
|
482
|
+
}
|
|
483
|
+
async function start() {
|
|
484
|
+
const gen = ++generation;
|
|
485
|
+
clearTimer();
|
|
486
|
+
failures = 0;
|
|
487
|
+
backoffIdx = 0;
|
|
488
|
+
failureWindowStart = null;
|
|
489
|
+
emit({ phase: "waiting", shared: false, error: void 0, connectivity: "online" });
|
|
490
|
+
const r = await requestJson(fetchImpl, "/copilot-auth/start", { method: "POST" });
|
|
491
|
+
if (stale(gen)) return;
|
|
492
|
+
if (r.ok) {
|
|
493
|
+
beginPolling(gen);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
const errorCode = r.error?.details?.errorCode;
|
|
497
|
+
if (errorCode === "already-configured") {
|
|
498
|
+
emit({ phase: "authorized", error: void 0, shared: false });
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
if (r.httpStatus === 409) {
|
|
502
|
+
emit({ shared: true });
|
|
503
|
+
beginPolling(gen);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
if (errorCode === "auth-unsafe") {
|
|
507
|
+
emit({ phase: "risk", riskKind: "auth-unsafe" });
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (errorCode === "scope-unavailable" || r.httpStatus === 503) {
|
|
511
|
+
emit({ phase: "unavailable" });
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
emit({ phase: "failed", error: errorCode ?? r.error?.messageKey });
|
|
515
|
+
}
|
|
516
|
+
async function cancel() {
|
|
517
|
+
const r = await requestJson(fetchImpl, "/copilot-auth/cancel", { method: "POST" });
|
|
518
|
+
if (r.ok) {
|
|
519
|
+
emit({ withdrawalDelivery: r.body?.withdrawalDelivery ?? "unavailable" });
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
emit({ withdrawalDelivery: "failed", error: r.error?.details?.errorCode ?? r.error?.messageKey });
|
|
523
|
+
}
|
|
524
|
+
function refresh() {
|
|
525
|
+
void init();
|
|
526
|
+
}
|
|
527
|
+
function dispose() {
|
|
528
|
+
generation += 1;
|
|
529
|
+
clearTimer();
|
|
530
|
+
}
|
|
531
|
+
return { init, start, cancel, refresh, dispose };
|
|
532
|
+
}
|
|
533
|
+
|
|
160
534
|
// src/client.jsx
|
|
161
535
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
162
536
|
var name = "copilot-auth-ui";
|
|
@@ -164,107 +538,184 @@ var inject = ["slots", "locale"];
|
|
|
164
538
|
var DICTS = {
|
|
165
539
|
en: {
|
|
166
540
|
nav: "GHC Settings",
|
|
167
|
-
title: "GitHub Copilot
|
|
168
|
-
intro: "
|
|
541
|
+
title: "GitHub Copilot",
|
|
542
|
+
intro: "Authorize with a personal or organization account on github.com that has Copilot access. No API token is required.",
|
|
169
543
|
idle: "Not signed in",
|
|
170
|
-
|
|
544
|
+
waiting: "Waiting for you to authorize on GitHub",
|
|
171
545
|
authorized: "Signed in",
|
|
172
546
|
failed: "Failed",
|
|
173
547
|
loading: "\u2026",
|
|
174
548
|
login: "Sign in",
|
|
175
549
|
logout: "Sign out",
|
|
550
|
+
reauthorize: "Reauthorize",
|
|
551
|
+
withdrawAuth: "Request withdrawal",
|
|
552
|
+
withdrawal: "Withdrawal requested; the outcome remains unverified.",
|
|
553
|
+
withdrawalUnavailable: "The withdrawal request could not be sent to the host; the outcome remains unverified.",
|
|
554
|
+
authUnsafe: "Safe completion of the authorization flow is unconfirmed. Sign-out and a new authorization attempt are unavailable.",
|
|
555
|
+
attemptTimeout: "Authorization wait timed out; the outcome remains unverified. A new authorization attempt is unavailable. Check the status or verify it manually.",
|
|
556
|
+
attemptShared: "An authorization attempt is already running in this instance.",
|
|
557
|
+
unavailable: "This runtime lacks the capabilities needed to apply changes safely.",
|
|
558
|
+
connection: "Connection lost. The last confirmed status is shown.",
|
|
559
|
+
retryNow: "Check status",
|
|
560
|
+
copyFailed: "Copy failed. Select and copy the device code manually.",
|
|
561
|
+
riskBadge: "Outcome unverified",
|
|
176
562
|
codeHint: "Open the link below and enter this code to finish signing in:",
|
|
177
563
|
copy: "Copy",
|
|
178
564
|
copied: "Copied \u2713",
|
|
179
565
|
unknown: "Unknown error",
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
566
|
+
statusUnknown: "Status unknown",
|
|
567
|
+
errNetwork: "Network error: cannot reach the authorization service. Retrying automatically.",
|
|
568
|
+
errGateway: "Gateway error: the DSH service may be restarting. Retrying automatically.",
|
|
569
|
+
errBadResponse: "Unexpected response from the authorization service.",
|
|
570
|
+
errHttp: "The authorization request failed. Check status and retry.",
|
|
571
|
+
// ---- Model management (protocol v2, design §5) ----
|
|
572
|
+
supplement: "Add models",
|
|
573
|
+
rebuild: "Rebuild model list",
|
|
574
|
+
supplementTitle: "Add models",
|
|
575
|
+
rebuildTitle: "Rebuild model list",
|
|
576
|
+
candidates: "Models available to add",
|
|
577
|
+
selectAll: "Select all",
|
|
578
|
+
supplementRisk: "Existing models and customizations will be kept. Only selected models will be added.",
|
|
579
|
+
rebuildRisk: "This rebuilds Copilot model configuration from the verified account list and clears the model customizations below. Other provider settings remain unchanged.",
|
|
580
|
+
clearRisk: "This clears the Copilot model list and its model customizations. Confirm clearing separately.",
|
|
581
|
+
secondConfirm: "This is destructive. Click again to confirm.",
|
|
582
|
+
applyChanges: "Apply changes",
|
|
583
|
+
addedModels: "Models to add",
|
|
584
|
+
removedModels: "Models to be removed",
|
|
188
585
|
keptModels: "Kept",
|
|
586
|
+
removedAccount: "Not included in this account model list",
|
|
587
|
+
removedUnresolvable: "Not resolvable by the current catalog",
|
|
588
|
+
warnings: "Warnings",
|
|
189
589
|
skippedModels: "Upstream entries skipped by validation",
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
confirmRefresh: "Confirm refresh",
|
|
194
|
-
cancel: "Cancel",
|
|
195
|
-
refreshing: "Fetching preview\u2026",
|
|
196
|
-
applying: "Applying\u2026",
|
|
197
|
-
restartNeeded: "Catalog patched. Restart dsh web to finish syncing the model list.",
|
|
198
|
-
stalePreview: "Inputs changed \u2014 review the new diff",
|
|
199
|
-
overlayBtn: "Preview with bundled overlay",
|
|
200
|
-
stateCorrupt: "State file was corrupted and quarantined; auto self-heal is disabled \u2014 run a refresh to re-activate.",
|
|
201
|
-
srcLive: "Account models: live fetch",
|
|
202
|
-
srcCache: "Account models: credential cache (live fetch failed)",
|
|
590
|
+
srcLive: "Account models: live",
|
|
591
|
+
srcCache: "Account models: cached at {time}; add-only use",
|
|
592
|
+
srcStale: "The cache has no trusted timestamp, is expired, or belongs to changed authorization; reference only.",
|
|
203
593
|
srcLatest: "Catalog source: latest pi-ai from npm",
|
|
204
|
-
srcLocal: "Catalog source: local
|
|
594
|
+
srcLocal: "Catalog source: local (npm fetch failed)",
|
|
205
595
|
srcOverlay: "Catalog source: bundled overlay (offline bootstrap)",
|
|
596
|
+
overlayBtn: "Preview with bundled overlay",
|
|
597
|
+
previewStale: "Configuration or data changed. Preview and confirm again.",
|
|
206
598
|
none: "(none)",
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
599
|
+
applying: "Applying\u2026",
|
|
600
|
+
refreshing: "Fetching preview\u2026",
|
|
601
|
+
cancel: "Cancel",
|
|
602
|
+
applied: "Changes are active. No restart is needed.",
|
|
603
|
+
pendingRestart: "Changes are saved and require restarting this instance's service or application. Refreshing the page alone is not enough.",
|
|
604
|
+
conflict: "Configuration changed. To protect your edits, preview and confirm again.",
|
|
605
|
+
partial: "Changes were only partially applied. Review the current status and recovery guidance.",
|
|
606
|
+
rolledBack: "This operation's model configuration changes were rolled back. Catalog data may still have been added.",
|
|
607
|
+
rollbackConflict: "Newer configuration was detected and preserved. Automatic rollback did not complete.",
|
|
608
|
+
busy: "Another operation is using this resource. Please retry shortly.",
|
|
609
|
+
unknownResult: "Completion has not been confirmed. Check the current status before submitting again.",
|
|
610
|
+
recoveryNeeded: "A previous configuration intent is stale or conflicted. End it before applying new changes.",
|
|
611
|
+
retireBtn: "End previous configuration intent",
|
|
612
|
+
retireTitle: "End previous configuration intent",
|
|
613
|
+
retireConfirmText: "End the intent only; existing changes are not rolled back or undone.",
|
|
614
|
+
legacy: "Legacy shared recovery state was found. It will not be applied automatically; preview and confirm in this profile.",
|
|
615
|
+
techDetails: "Technical details",
|
|
616
|
+
stateCorrupt: "State file was corrupted and quarantined. Preview and confirm again.",
|
|
617
|
+
blockedReasons: {
|
|
618
|
+
"inject-unavailable": "The in-process catalog registry is unavailable in this installation.",
|
|
619
|
+
"install-unresolved": "The pi-ai installation could not be located."
|
|
620
|
+
}
|
|
212
621
|
},
|
|
213
622
|
zh: {
|
|
214
623
|
nav: "GHC\u8BBE\u7F6E",
|
|
215
|
-
title: "GitHub Copilot
|
|
216
|
-
intro: "\u4F7F\u7528\
|
|
624
|
+
title: "GitHub Copilot",
|
|
625
|
+
intro: "\u4F7F\u7528\u5177\u6709 Copilot \u6743\u9650\u7684 github.com \u4E2A\u4EBA\u6216\u7EC4\u7EC7\u8D26\u53F7\u6388\u6743\uFF0C\u65E0\u9700\u586B\u5199 API Token\u3002",
|
|
217
626
|
idle: "\u672A\u767B\u5F55",
|
|
218
|
-
|
|
627
|
+
waiting: "\u7B49\u5F85\u4F60\u5728 GitHub \u5B8C\u6210\u6388\u6743",
|
|
219
628
|
authorized: "\u5DF2\u767B\u5F55",
|
|
220
629
|
failed: "\u5931\u8D25",
|
|
221
630
|
loading: "\u2026",
|
|
222
|
-
login: "\u767B\u5F55",
|
|
223
|
-
logout: "\
|
|
631
|
+
login: "\u6388\u6743\u767B\u5F55",
|
|
632
|
+
logout: "\u9000\u51FA\u767B\u5F55",
|
|
633
|
+
reauthorize: "\u91CD\u65B0\u6388\u6743",
|
|
634
|
+
withdrawAuth: "\u8BF7\u6C42\u64A4\u56DE",
|
|
635
|
+
withdrawal: "\u64A4\u56DE\u8BF7\u6C42\u5DF2\u53D1\u9001\uFF0C\u7ED3\u679C\u4ECD\u5F85\u6838\u5B9E\u3002",
|
|
636
|
+
withdrawalUnavailable: "\u672A\u80FD\u5411\u5BBF\u4E3B\u53D1\u9001\u64A4\u56DE\u8BF7\u6C42\uFF0C\u7ED3\u679C\u4ECD\u5F85\u6838\u5B9E\u3002",
|
|
637
|
+
authUnsafe: "\u5C1A\u4E0D\u80FD\u786E\u8BA4\u6388\u6743\u6D41\u7A0B\u5DF2\u5B89\u5168\u7ED3\u675F\uFF0C\u6682\u4E0D\u80FD\u9000\u51FA\u6216\u53D1\u8D77\u65B0\u7684\u6388\u6743\u5C1D\u8BD5\u3002",
|
|
638
|
+
attemptTimeout: "\u7B49\u5F85\u6388\u6743\u8D85\u65F6\uFF0C\u7ED3\u679C\u4ECD\u5F85\u6838\u5B9E\u3002\u5F53\u524D\u4E0D\u80FD\u53D1\u8D77\u65B0\u7684\u6388\u6743\u5C1D\u8BD5\uFF0C\u8BF7\u67E5\u8BE2\u72B6\u6001\u6216\u4EBA\u5DE5\u6838\u5B9E\u3002",
|
|
639
|
+
attemptShared: "\u6B64\u5B9E\u4F8B\u5DF2\u6709\u6388\u6743\u6B63\u5728\u8FDB\u884C\u3002",
|
|
640
|
+
connection: "\u8FDE\u63A5\u5F02\u5E38\uFF0C\u663E\u793A\u7684\u662F\u6700\u540E\u786E\u8BA4\u7684\u72B6\u6001\u3002",
|
|
641
|
+
retryNow: "\u67E5\u8BE2\u72B6\u6001",
|
|
642
|
+
copyFailed: "\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u4E2D\u8BBE\u5907\u7801\u590D\u5236\u3002",
|
|
643
|
+
riskBadge: "\u7ED3\u679C\u5F85\u6838\u5B9E",
|
|
224
644
|
codeHint: "\u5728\u6D4F\u89C8\u5668\u6253\u5F00\u4E0B\u9762\u7684\u94FE\u63A5\uFF0C\u8F93\u5165\u8FD9\u4E32\u4EE3\u7801\u5B8C\u6210\u6388\u6743\uFF1A",
|
|
225
645
|
copy: "\u590D\u5236",
|
|
226
646
|
copied: "\u5DF2\u590D\u5236 \u2713",
|
|
227
647
|
unknown: "\u672A\u77E5\u9519\u8BEF",
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
648
|
+
statusUnknown: "\u72B6\u6001\u672A\u77E5",
|
|
649
|
+
errNetwork: "\u7F51\u7EDC\u5F02\u5E38\uFF1A\u65E0\u6CD5\u8FDE\u63A5\u6388\u6743\u670D\u52A1\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u8BD5\u3002",
|
|
650
|
+
errGateway: "\u7F51\u5173\u9519\u8BEF\uFF1ADSH \u670D\u52A1\u53EF\u80FD\u6B63\u5728\u91CD\u542F\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u8BD5\u3002",
|
|
651
|
+
errBadResponse: "\u6388\u6743\u670D\u52A1\u8FD4\u56DE\u5F02\u5E38\u54CD\u5E94\u3002",
|
|
652
|
+
errHttp: "\u6388\u6743\u8BF7\u6C42\u5931\u8D25\u3002\u8BF7\u67E5\u8BE2\u72B6\u6001\u540E\u91CD\u8BD5\u3002",
|
|
653
|
+
// ---- 模型管理(协议 v2,设计§5) ----
|
|
654
|
+
supplement: "\u8865\u5145\u6A21\u578B",
|
|
655
|
+
rebuild: "\u91CD\u5EFA\u6A21\u578B\u5217\u8868",
|
|
656
|
+
supplementTitle: "\u8865\u5145\u6A21\u578B",
|
|
657
|
+
rebuildTitle: "\u91CD\u5EFA\u6A21\u578B\u5217\u8868",
|
|
658
|
+
candidates: "\u53EF\u65B0\u589E\u7684\u6A21\u578B",
|
|
659
|
+
selectAll: "\u5168\u9009",
|
|
660
|
+
supplementRisk: "\u5C06\u4FDD\u7559\u73B0\u6709\u6A21\u578B\u53CA\u5B9A\u5236\uFF0C\u53EA\u6DFB\u52A0\u4F60\u52FE\u9009\u7684\u6A21\u578B\u3002",
|
|
661
|
+
rebuildRisk: "\u5C06\u6309\u672C\u6B21\u53EF\u4FE1\u8D26\u53F7\u5217\u8868\u91CD\u5EFA Copilot \u6A21\u578B\u914D\u7F6E\uFF0C\u5E76\u6E05\u9664\u4E0B\u5217\u6A21\u578B\u53C2\u6570\u4E0E\u8986\u76D6\u914D\u7F6E\u3002\u5176\u4ED6\u63D0\u4F9B\u65B9\u8BBE\u7F6E\u4E0D\u53D8\u3002",
|
|
662
|
+
clearRisk: "\u672C\u6B21\u5C06\u6E05\u7A7A Copilot \u6A21\u578B\u5217\u8868\u5E76\u6E05\u9664\u5176\u6A21\u578B\u5B9A\u5236\u3002\u8BF7\u5355\u72EC\u786E\u8BA4\u6E05\u7A7A\u3002",
|
|
663
|
+
secondConfirm: "\u6B64\u64CD\u4F5C\u5177\u6709\u7834\u574F\u6027\uFF0C\u8BF7\u518D\u6B21\u70B9\u51FB\u786E\u8BA4\u3002",
|
|
664
|
+
applyChanges: "\u5E94\u7528\u66F4\u6539",
|
|
665
|
+
addedModels: "\u5C06\u6DFB\u52A0\u7684\u6A21\u578B",
|
|
666
|
+
removedModels: "\u5C06\u79FB\u9664\u7684\u6A21\u578B",
|
|
236
667
|
keptModels: "\u4FDD\u7559",
|
|
668
|
+
removedAccount: "\u672A\u5305\u542B\u5728\u672C\u6B21\u8D26\u53F7\u6A21\u578B\u5217\u8868",
|
|
669
|
+
removedUnresolvable: "\u5F53\u524D\u76EE\u5F55\u65E0\u6CD5\u89E3\u6790",
|
|
670
|
+
warnings: "\u8B66\u544A",
|
|
237
671
|
skippedModels: "\u88AB\u6821\u9A8C\u8DF3\u8FC7\u7684\u4E0A\u6E38\u6761\u76EE",
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
confirmRefresh: "\u786E\u8BA4\u5237\u65B0",
|
|
242
|
-
cancel: "\u53D6\u6D88",
|
|
243
|
-
refreshing: "\u62C9\u53D6\u9884\u89C8\u4E2D\u2026",
|
|
244
|
-
applying: "\u5E94\u7528\u4E2D\u2026",
|
|
245
|
-
restartNeeded: "\u76EE\u5F55\u8865\u4E01\u5DF2\u5199\u5165\u3002\u91CD\u542F dsh web \u540E\u5B8C\u6210\u6A21\u578B\u5217\u8868\u540C\u6B65\u3002",
|
|
246
|
-
stalePreview: "\u6570\u636E\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u786E\u8BA4\u5DEE\u5F02",
|
|
247
|
-
overlayBtn: "\u6539\u7528\u5185\u7F6E\u8986\u76D6\u5C42\u9884\u89C8",
|
|
248
|
-
stateCorrupt: "\u72B6\u6001\u6587\u4EF6\u5DF2\u635F\u574F\u5E76\u88AB\u9694\u79BB\uFF1B\u81EA\u52A8\u81EA\u6108\u5DF2\u505C\u7528\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C\u4E00\u6B21\u5237\u65B0\u4EE5\u6FC0\u6D3B\u3002",
|
|
249
|
-
srcLive: "\u8D26\u53F7\u6A21\u578B\uFF1A\u73B0\u573A\u62C9\u53D6",
|
|
250
|
-
srcCache: "\u8D26\u53F7\u6A21\u578B\uFF1A\u51ED\u8BC1\u7F13\u5B58\uFF08\u73B0\u573A\u62C9\u53D6\u5931\u8D25\uFF09",
|
|
672
|
+
srcLive: "\u8D26\u53F7\u6A21\u578B\uFF1A\u5B9E\u65F6\u83B7\u53D6",
|
|
673
|
+
srcCache: "\u8D26\u53F7\u6A21\u578B\uFF1A\u7F13\u5B58\uFF0C\u83B7\u53D6\u4E8E {time}\uFF0C\u4EC5\u53EF\u7528\u4E8E\u8865\u5145",
|
|
674
|
+
srcStale: "\u7F13\u5B58\u7F3A\u5C11\u53EF\u4FE1\u65F6\u95F4\u3001\u5DF2\u8FC7\u671F\u6216\u6388\u6743\u5DF2\u53D8\u5316\uFF0C\u4EC5\u4F9B\u53C2\u8003\u3002",
|
|
251
675
|
srcLatest: "\u76EE\u5F55\u6765\u6E90\uFF1Anpm \u6700\u65B0 pi-ai",
|
|
252
|
-
srcLocal: "\u76EE\u5F55\u6765\u6E90\uFF1A\
|
|
676
|
+
srcLocal: "\u76EE\u5F55\u6765\u6E90\uFF1A\u672C\u5730\u76EE\u5F55\uFF08npm \u62C9\u53D6\u5931\u8D25\uFF09",
|
|
253
677
|
srcOverlay: "\u76EE\u5F55\u6765\u6E90\uFF1A\u5185\u7F6E\u8986\u76D6\u5C42\uFF08\u79BB\u7EBF bootstrap\uFF09",
|
|
678
|
+
overlayBtn: "\u6539\u7528\u5185\u7F6E\u76EE\u5F55\u6570\u636E\u9884\u89C8",
|
|
679
|
+
previewStale: "\u914D\u7F6E\u6216\u6570\u636E\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u9884\u89C8\u5E76\u786E\u8BA4\u3002",
|
|
254
680
|
none: "\uFF08\u65E0\uFF09",
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
681
|
+
applying: "\u5E94\u7528\u4E2D\u2026",
|
|
682
|
+
refreshing: "\u62C9\u53D6\u9884\u89C8\u4E2D\u2026",
|
|
683
|
+
cancel: "\u53D6\u6D88",
|
|
684
|
+
applied: "\u66F4\u6539\u5DF2\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u542F\u3002",
|
|
685
|
+
pendingRestart: "\u66F4\u6539\u5DF2\u4FDD\u5B58\uFF0C\u5F85\u91CD\u542F\u751F\u6548\u3002\u8BF7\u91CD\u542F\u8FD0\u884C\u6B64\u5B9E\u4F8B\u7684\u670D\u52A1\u6216\u5E94\u7528\uFF1B\u4EC5\u5237\u65B0\u9875\u9762\u4E0D\u4F1A\u751F\u6548\u3002",
|
|
686
|
+
conflict: "\u914D\u7F6E\u5DF2\u53D8\u5316\u3002\u4E3A\u4FDD\u62A4\u4F60\u7684\u4FEE\u6539\uFF0C\u8BF7\u91CD\u65B0\u9884\u89C8\u5E76\u786E\u8BA4\u3002",
|
|
687
|
+
partial: "\u66F4\u6539\u672A\u5B8C\u5168\u5E94\u7528\uFF0C\u8BF7\u67E5\u770B\u5F53\u524D\u72B6\u6001\u548C\u6062\u590D\u5EFA\u8BAE\u3002",
|
|
688
|
+
rolledBack: "\u672C\u6B21\u6A21\u578B\u914D\u7F6E\u66F4\u6539\u5DF2\u56DE\u6EDA\u3002\u76EE\u5F55\u6570\u636E\u53EF\u80FD\u4ECD\u5DF2\u8865\u5145\u3002",
|
|
689
|
+
rollbackConflict: "\u68C0\u6D4B\u5230\u66F4\u65B0\u7684\u914D\u7F6E\uFF0C\u5DF2\u4FDD\u7559\u4F60\u7684\u4FEE\u6539\uFF1B\u81EA\u52A8\u56DE\u6EDA\u672A\u5B8C\u6210\u3002",
|
|
690
|
+
busy: "\u53E6\u4E00\u4E2A\u64CD\u4F5C\u6B63\u5728\u5904\u7406\u6B64\u8D44\u6E90\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",
|
|
691
|
+
unknownResult: "\u5C1A\u672A\u786E\u8BA4\u64CD\u4F5C\u5B8C\u6210\u3002\u8BF7\u6838\u5B9E\u5F53\u524D\u72B6\u6001\uFF0C\u52FF\u91CD\u590D\u63D0\u4EA4\u3002",
|
|
692
|
+
recoveryNeeded: "\u5B58\u5728\u5DF2\u5931\u6548\u6216\u51B2\u7A81\u7684\u65E7\u914D\u7F6E\u610F\u56FE\uFF0C\u8BF7\u5148\u7ED3\u675F\u65E7\u610F\u56FE\u518D\u5E94\u7528\u65B0\u66F4\u6539\u3002",
|
|
693
|
+
retireBtn: "\u7ED3\u675F\u65E7\u914D\u7F6E\u610F\u56FE",
|
|
694
|
+
retireTitle: "\u7ED3\u675F\u65E7\u914D\u7F6E\u610F\u56FE",
|
|
695
|
+
retireConfirmText: "\u53EA\u7ED3\u675F\u65E7\u610F\u56FE\uFF0C\u4E0D\u56DE\u6EDA\u6216\u64A4\u9500\u5DF2\u53D1\u751F\u7684\u66F4\u6539\u3002",
|
|
696
|
+
legacy: "\u68C0\u6D4B\u5230\u65E7\u7684\u5171\u4EAB\u6062\u590D\u72B6\u6001\u3002\u4E0D\u4F1A\u81EA\u52A8\u5E94\u7528\uFF0C\u8BF7\u5728\u5F53\u524D profile \u91CD\u65B0\u9884\u89C8\u786E\u8BA4\u3002",
|
|
697
|
+
techDetails: "\u6280\u672F\u8BE6\u60C5",
|
|
698
|
+
stateCorrupt: "\u6062\u590D\u72B6\u6001\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u539F\u4EF6\u5DF2\u4FDD\u7559\u3002\u8BF7\u91CD\u65B0\u9884\u89C8\u786E\u8BA4\u3002",
|
|
699
|
+
unavailable: "\u5F53\u524D\u8FD0\u884C\u65F6\u7F3A\u5C11\u5B89\u5168\u5E94\u7528\u6240\u9700\u7684\u80FD\u529B\uFF0C\u6682\u4E0D\u80FD\u5E94\u7528\u66F4\u6539\u3002",
|
|
700
|
+
blockedReasons: {
|
|
701
|
+
"inject-unavailable": "\u5F53\u524D\u5B89\u88C5\u7684\u8FDB\u7A0B\u5185\u76EE\u5F55\u6CE8\u518C\u8868\u4E0D\u53EF\u7528\u3002",
|
|
702
|
+
"install-unresolved": "\u65E0\u6CD5\u5B9A\u4F4D pi-ai \u5B89\u88C5\u3002"
|
|
703
|
+
}
|
|
260
704
|
}
|
|
261
705
|
};
|
|
262
706
|
var NAV_TEXTS = Object.keys(DICTS).map((locale) => DICTS[locale].nav);
|
|
263
|
-
function
|
|
264
|
-
|
|
707
|
+
function blockedReasonText(t, flags) {
|
|
708
|
+
const reason = flags?.blockedReason;
|
|
709
|
+
if (reason && t("blockedReasons")?.[reason]) return t("blockedReasons")[reason];
|
|
710
|
+
return t("unavailable");
|
|
265
711
|
}
|
|
266
|
-
function
|
|
267
|
-
return
|
|
712
|
+
function httpErrorText(t, key) {
|
|
713
|
+
return {
|
|
714
|
+
"network-error": t("errNetwork"),
|
|
715
|
+
"bad-gateway": t("errGateway"),
|
|
716
|
+
"bad-response": t("errBadResponse"),
|
|
717
|
+
"http-error": t("errHttp")
|
|
718
|
+
}[key];
|
|
268
719
|
}
|
|
269
720
|
var COPILOT_ICON_SVG = '<svg aria-hidden="true" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" style="flex:none"><path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"/><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"/></svg>';
|
|
270
721
|
function enforceNavIcon(labelText) {
|
|
@@ -373,7 +824,7 @@ var styles = {
|
|
|
373
824
|
modalActions: { display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 4 },
|
|
374
825
|
mono: { fontFamily: "ui-monospace, monospace" }
|
|
375
826
|
};
|
|
376
|
-
var badgeColor = { idle: "#adb5bd",
|
|
827
|
+
var badgeColor = { idle: "#adb5bd", waiting: "#f59f00", authorized: "#37b24d", failed: "#e03131", loading: "#adb5bd", risk: "#f59f00", unavailable: "#adb5bd" };
|
|
377
828
|
function sampleThemeSurface() {
|
|
378
829
|
if (typeof document === "undefined") return { bg: "#fff", fg: "inherit" };
|
|
379
830
|
const cs = getComputedStyle(document.body);
|
|
@@ -381,108 +832,182 @@ function sampleThemeSurface() {
|
|
|
381
832
|
const bg = m ? `rgb(${m[1].split(",").slice(0, 3).join(",")})` : "#fff";
|
|
382
833
|
return { bg, fg: cs.color || "inherit" };
|
|
383
834
|
}
|
|
384
|
-
function RefreshModal({ t, flow, onConfirm, onCancel, onOverlay }) {
|
|
835
|
+
function RefreshModal({ t, flow, onSelect, onConfirm, onCancel, onOverlay }) {
|
|
385
836
|
const p = flow.preview;
|
|
837
|
+
const diff = p.diff ?? {};
|
|
838
|
+
const isRebuild = p.operation === "rebuild";
|
|
839
|
+
const emptyTarget = isRebuild && (diff.targetView?.models ?? []).length === 0;
|
|
840
|
+
const candidates = diff.candidates ?? [];
|
|
841
|
+
const selectedIds = new Set(diff.added ?? []);
|
|
842
|
+
const [stage, setStage] = (0, import_react.useState)(0);
|
|
843
|
+
const cancelRef = (0, import_react.useRef)(null);
|
|
386
844
|
const surface = (0, import_react.useRef)(null);
|
|
387
845
|
if (!surface.current) surface.current = sampleThemeSurface();
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
846
|
+
(0, import_react.useEffect)(() => {
|
|
847
|
+
setStage(0);
|
|
848
|
+
}, [p.previewId]);
|
|
849
|
+
(0, import_react.useEffect)(() => {
|
|
850
|
+
if (stage > 0) cancelRef.current?.focus();
|
|
851
|
+
}, [stage]);
|
|
852
|
+
const escCancel = (e) => {
|
|
853
|
+
if (e.key === "Escape") onCancel();
|
|
854
|
+
};
|
|
855
|
+
const confirmClick = () => {
|
|
856
|
+
if (p.evidence?.stale === true) return;
|
|
857
|
+
if (!isRebuild) {
|
|
858
|
+
onConfirm({ second: false, empty: false });
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
if (stage === 0) {
|
|
862
|
+
setStage(1);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
if (emptyTarget && stage === 1) {
|
|
866
|
+
setStage(2);
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
onConfirm({ second: true, empty: emptyTarget });
|
|
870
|
+
};
|
|
871
|
+
const sourceLine = [
|
|
872
|
+
p.evidence?.source === "live" ? t("srcLive") : p.evidence?.source === "cache" ? t("srcCache").replace("{time}", String(p.evidence?.fetchedAt ?? "")) : null,
|
|
873
|
+
p.catalogSource === "latest" ? t("srcLatest") : p.catalogSource === "overlay" ? t("srcOverlay") : t("srcLocal")
|
|
874
|
+
].filter(Boolean).join(" \xB7 ");
|
|
875
|
+
const list = (items, style, render) => items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { opacity: 0.6 }, children: t("none") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: styles.diffList, children: items.map((x, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { style: { ...style, ...styles.mono }, children: render ? render(x) : x }, x?.id ?? x ?? i)) });
|
|
876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.modalMask, role: "dialog", "aria-modal": "true", onKeyDown: escCancel, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...styles.modal, background: surface.current.bg, color: surface.current.fg }, children: [
|
|
877
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { style: styles.modalTitle, children: t(isRebuild ? "rebuildTitle" : "supplementTitle") }),
|
|
400
878
|
flow.staleNotice && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
401
879
|
"\u26A0 ",
|
|
402
|
-
t("
|
|
880
|
+
t("previewStale")
|
|
881
|
+
] }),
|
|
882
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.modalText, children: sourceLine }),
|
|
883
|
+
p.evidence?.stale === true && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
884
|
+
"\u26A0 ",
|
|
885
|
+
t("srcStale")
|
|
886
|
+
] }),
|
|
887
|
+
!isRebuild && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
888
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
|
|
889
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("candidates") }),
|
|
890
|
+
"\uFF08",
|
|
891
|
+
candidates.length,
|
|
892
|
+
"\uFF09",
|
|
893
|
+
candidates.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary, height: 24, marginLeft: 10, fontSize: 12 }, onClick: () => onSelect(candidates), children: t("selectAll") })
|
|
894
|
+
] }),
|
|
895
|
+
list(candidates, styles.added, (id) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
896
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "checkbox", checked: selectedIds.has(id), onChange: () => {
|
|
897
|
+
const next = new Set(selectedIds);
|
|
898
|
+
if (next.has(id)) next.delete(id);
|
|
899
|
+
else next.add(id);
|
|
900
|
+
onSelect([...next]);
|
|
901
|
+
} }),
|
|
902
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: id })
|
|
903
|
+
] })),
|
|
904
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
|
|
905
|
+
"\u26A0 ",
|
|
906
|
+
t("supplementRisk")
|
|
907
|
+
] })
|
|
403
908
|
] }),
|
|
404
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.modalText, children: sourceKeys.map((k) => t(k)).join(" \xB7 ") }),
|
|
405
909
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
|
|
406
910
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("addedModels") }),
|
|
407
911
|
"\uFF08",
|
|
408
|
-
|
|
912
|
+
(diff.added ?? []).length,
|
|
409
913
|
"\uFF09"
|
|
410
914
|
] }),
|
|
411
|
-
list(
|
|
915
|
+
list(diff.added ?? [], styles.added),
|
|
412
916
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
|
|
413
917
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("removedModels") }),
|
|
414
918
|
"\uFF08",
|
|
415
|
-
|
|
919
|
+
(diff.removed ?? []).length,
|
|
416
920
|
"\uFF09"
|
|
417
921
|
] }),
|
|
418
|
-
list(
|
|
922
|
+
list(diff.removed ?? [], styles.removed, (x) => `${x.id} \u2014 ${t(x.reason === "unresolvable" ? "removedUnresolvable" : "removedAccount")}`),
|
|
419
923
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
|
|
420
924
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("keptModels") }),
|
|
421
925
|
"\uFF08",
|
|
422
|
-
|
|
926
|
+
(diff.kept ?? []).length,
|
|
423
927
|
"\uFF09"
|
|
424
928
|
] }),
|
|
425
|
-
|
|
929
|
+
(diff.warnings ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
426
930
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.modalText, children: [
|
|
427
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("
|
|
931
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("warnings") }),
|
|
428
932
|
"\uFF08",
|
|
429
|
-
|
|
933
|
+
diff.warnings.length,
|
|
430
934
|
"\uFF09"
|
|
431
935
|
] }),
|
|
432
|
-
|
|
433
|
-
s.id,
|
|
434
|
-
" \u2014 ",
|
|
435
|
-
s.reason
|
|
436
|
-
] }, s.id)) })
|
|
936
|
+
list(diff.warnings, styles.skipped, (w) => `${w.id ?? ""} \u2014 ${w.reason ?? ""}`)
|
|
437
937
|
] }),
|
|
438
|
-
|
|
439
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.modalText, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("customReset") }) }),
|
|
440
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: styles.diffList, children: resets.map((x) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { style: styles.skipped, children: x }, x)) })
|
|
441
|
-
] }),
|
|
442
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
|
|
938
|
+
isRebuild && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
|
|
443
939
|
"\u26A0 ",
|
|
444
|
-
t("
|
|
940
|
+
t("rebuildRisk")
|
|
445
941
|
] }),
|
|
446
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
|
|
942
|
+
emptyTarget && stage >= 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
|
|
447
943
|
"\u26A0 ",
|
|
448
|
-
t("
|
|
944
|
+
t("clearRisk")
|
|
449
945
|
] }),
|
|
450
|
-
|
|
946
|
+
stage === 1 && !emptyTarget && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.risk, children: [
|
|
451
947
|
"\u26A0 ",
|
|
452
|
-
t("
|
|
948
|
+
t("secondConfirm")
|
|
453
949
|
] }),
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
950
|
+
(p.skipped ?? []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { style: styles.modalText, children: [
|
|
951
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("summary", { children: [
|
|
952
|
+
t("skippedModels"),
|
|
953
|
+
"\uFF08",
|
|
954
|
+
p.skipped.length,
|
|
955
|
+
"\uFF09"
|
|
956
|
+
] }),
|
|
957
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: styles.diffList, children: p.skipped.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: styles.skipped, children: [
|
|
958
|
+
s.id,
|
|
959
|
+
" \u2014 ",
|
|
960
|
+
s.reason
|
|
961
|
+
] }, s.id)) })
|
|
457
962
|
] }),
|
|
458
|
-
|
|
459
|
-
"
|
|
460
|
-
|
|
963
|
+
p.catalogError && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { style: styles.modalText, children: [
|
|
964
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: t("techDetails") }),
|
|
965
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...styles.mono, fontSize: 12 }, children: p.catalogError })
|
|
461
966
|
] }),
|
|
462
967
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.modalActions, children: [
|
|
463
968
|
p.catalogSource === "local" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary, marginRight: "auto" }, onClick: onOverlay, children: t("overlayBtn") }),
|
|
464
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary }, onClick: onCancel, children: t("cancel") }),
|
|
969
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ref: cancelRef, type: "button", style: { ...styles.button, ...styles.secondary }, onClick: onCancel, children: t("cancel") }),
|
|
465
970
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
466
971
|
"button",
|
|
467
972
|
{
|
|
468
973
|
type: "button",
|
|
469
|
-
style: { ...styles.button, ...styles.primary, ...
|
|
470
|
-
disabled:
|
|
471
|
-
onClick:
|
|
472
|
-
children: t("
|
|
974
|
+
style: { ...styles.button, ...styles.primary, ...p.evidence?.stale === true ? { opacity: 0.5, cursor: "not-allowed" } : null },
|
|
975
|
+
disabled: p.evidence?.stale === true,
|
|
976
|
+
onClick: confirmClick,
|
|
977
|
+
children: t("applyChanges")
|
|
473
978
|
}
|
|
474
979
|
)
|
|
475
980
|
] })
|
|
476
981
|
] }) });
|
|
477
982
|
}
|
|
983
|
+
function RetireDialog({ t, onConfirm, onCancel }) {
|
|
984
|
+
const cancelRef = (0, import_react.useRef)(null);
|
|
985
|
+
const surface = (0, import_react.useRef)(null);
|
|
986
|
+
if (!surface.current) surface.current = sampleThemeSurface();
|
|
987
|
+
(0, import_react.useEffect)(() => {
|
|
988
|
+
cancelRef.current?.focus();
|
|
989
|
+
}, []);
|
|
990
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.modalMask, role: "dialog", "aria-modal": "true", onKeyDown: (e) => {
|
|
991
|
+
if (e.key === "Escape") onCancel();
|
|
992
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...styles.modal, background: surface.current.bg, color: surface.current.fg, maxWidth: 420 }, children: [
|
|
993
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { style: styles.modalTitle, children: t("retireTitle") }),
|
|
994
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.modalText, children: t("retireConfirmText") }),
|
|
995
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.modalActions, children: [
|
|
996
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ref: cancelRef, type: "button", style: { ...styles.button, ...styles.secondary }, onClick: onCancel, children: t("cancel") }),
|
|
997
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.primary }, onClick: onConfirm, children: t("retireBtn") })
|
|
998
|
+
] })
|
|
999
|
+
] }) });
|
|
1000
|
+
}
|
|
478
1001
|
function CopilotSection({ t = (key) => DICTS.en[key] ?? key }) {
|
|
479
|
-
const [
|
|
480
|
-
const [notices, setNotices] = (0, import_react.useState)([]);
|
|
481
|
-
const [error, setError] = (0, import_react.useState)(void 0);
|
|
1002
|
+
const [auth, setAuth] = (0, import_react.useState)({ phase: "loading", connectivity: "online", shared: false });
|
|
482
1003
|
const [copied, setCopied] = (0, import_react.useState)(false);
|
|
483
|
-
const
|
|
1004
|
+
const [copyFail, setCopyFail] = (0, import_react.useState)(false);
|
|
484
1005
|
const [flow, setFlow] = (0, import_react.useState)(initial);
|
|
485
1006
|
const flowRef = (0, import_react.useRef)(flow);
|
|
1007
|
+
const authFlowRef = (0, import_react.useRef)(null);
|
|
1008
|
+
if (!authFlowRef.current && typeof fetch === "function") {
|
|
1009
|
+
authFlowRef.current = createAuthFlow({ fetchImpl: fetch, onState: (s) => setAuth(s) });
|
|
1010
|
+
}
|
|
486
1011
|
const drive = (event) => advance(flowRef.current, event, fetch, (next) => {
|
|
487
1012
|
flowRef.current = next;
|
|
488
1013
|
setFlow(next);
|
|
@@ -492,141 +1017,194 @@ function CopilotSection({ t = (key) => DICTS.en[key] ?? key }) {
|
|
|
492
1017
|
drive({ type: "init" });
|
|
493
1018
|
}, []);
|
|
494
1019
|
(0, import_react.useEffect)(() => {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
if (!alive) return;
|
|
498
|
-
if (d.configured) {
|
|
499
|
-
setPage("authorized");
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
fetch("/copilot-auth/state").then((r) => r.json()).then((s) => {
|
|
503
|
-
if (!alive) return;
|
|
504
|
-
setNotices(s.notices ?? []);
|
|
505
|
-
if (s.status === "failed") {
|
|
506
|
-
setPage("failed");
|
|
507
|
-
setError(s.error ?? t("unknown"));
|
|
508
|
-
} else if (s.status === "running") {
|
|
509
|
-
setPage("running");
|
|
510
|
-
poll();
|
|
511
|
-
} else {
|
|
512
|
-
setPage("idle");
|
|
513
|
-
}
|
|
514
|
-
}).catch(() => {
|
|
515
|
-
if (alive) setPage("idle");
|
|
516
|
-
});
|
|
517
|
-
}).catch(() => {
|
|
518
|
-
if (alive) setPage("idle");
|
|
519
|
-
});
|
|
520
|
-
return () => {
|
|
521
|
-
alive = false;
|
|
522
|
-
if (timer.current) clearInterval(timer.current);
|
|
523
|
-
};
|
|
1020
|
+
void authFlowRef.current?.init();
|
|
1021
|
+
return () => authFlowRef.current?.dispose();
|
|
524
1022
|
}, []);
|
|
525
|
-
const poll = () => {
|
|
526
|
-
if (timer.current) clearInterval(timer.current);
|
|
527
|
-
timer.current = setInterval(() => {
|
|
528
|
-
fetch("/copilot-auth/state").then((r) => r.json()).then((s) => {
|
|
529
|
-
setNotices(s.notices ?? []);
|
|
530
|
-
if (s.status !== "running") {
|
|
531
|
-
if (timer.current) clearInterval(timer.current);
|
|
532
|
-
timer.current = null;
|
|
533
|
-
if (s.status === "authorized") {
|
|
534
|
-
setPage("authorized");
|
|
535
|
-
} else {
|
|
536
|
-
setPage("failed");
|
|
537
|
-
setError(s.error ?? t("unknown"));
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
}).catch(() => {
|
|
541
|
-
});
|
|
542
|
-
}, 1e3);
|
|
543
|
-
};
|
|
544
1023
|
const login = () => {
|
|
545
1024
|
setCopied(false);
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
fetch("/copilot-auth/start", { method: "POST" }).catch(() => {
|
|
549
|
-
});
|
|
550
|
-
setPage("running");
|
|
551
|
-
poll();
|
|
1025
|
+
setCopyFail(false);
|
|
1026
|
+
void authFlowRef.current?.start();
|
|
552
1027
|
};
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
try {
|
|
559
|
-
await fetch("/copilot-auth/logout", { method: "POST" });
|
|
560
|
-
} catch {
|
|
561
|
-
}
|
|
562
|
-
setNotices([]);
|
|
563
|
-
setError(void 0);
|
|
564
|
-
setPage("idle");
|
|
1028
|
+
const withdraw = () => {
|
|
1029
|
+
void authFlowRef.current?.cancel();
|
|
1030
|
+
};
|
|
1031
|
+
const checkStatus = () => {
|
|
1032
|
+
void authFlowRef.current?.refresh();
|
|
565
1033
|
};
|
|
566
1034
|
const copyCode = async (code) => {
|
|
567
1035
|
try {
|
|
568
1036
|
await navigator.clipboard.writeText(code);
|
|
569
1037
|
setCopied(true);
|
|
1038
|
+
setCopyFail(false);
|
|
570
1039
|
setTimeout(() => setCopied(false), 2e3);
|
|
571
1040
|
} catch {
|
|
1041
|
+
setCopyFail(true);
|
|
572
1042
|
}
|
|
573
1043
|
};
|
|
574
|
-
const
|
|
575
|
-
const
|
|
1044
|
+
const phase = auth.phase;
|
|
1045
|
+
const attempt = auth.attempt;
|
|
1046
|
+
const notices = [...attempt?.notices ?? []].reverse();
|
|
1047
|
+
const codeNotice = typeof attempt?.code === "string" && attempt.code !== "" ? { code: attempt.code, url: attempt.url } : (() => {
|
|
1048
|
+
const n = notices.find((x) => x && typeof x.code === "string" && x.code !== "");
|
|
1049
|
+
return n ? { code: n.code, url: n.url } : null;
|
|
1050
|
+
})();
|
|
1051
|
+
const badgeText = phase === "risk" ? t("riskBadge") : phase === "loading" ? t("loading") : phase === "idle" && auth.error ? t("statusUnknown") : t(phase);
|
|
576
1052
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.section, children: [
|
|
577
1053
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: styles.title, children: t("title") }),
|
|
578
1054
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.intro, children: t("intro") }),
|
|
579
1055
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.badgeRow, children: [
|
|
580
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...styles.dot, background: badgeColor[
|
|
1056
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...styles.dot, background: badgeColor[phase] ?? "#adb5bd" } }),
|
|
581
1057
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.badge, children: badgeText })
|
|
582
1058
|
] }),
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.code, children: codeNotice.code }),
|
|
587
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary }, onClick: () => copyCode(codeNotice.code), children: copied ? t("copied") : t("copy") })
|
|
588
|
-
] }),
|
|
589
|
-
codeNotice.url && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { style: styles.link, href: codeNotice.url, target: "_blank", rel: "noreferrer", children: codeNotice.url })
|
|
1059
|
+
auth.connectivity !== "online" && phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
1060
|
+
"\u26A0 ",
|
|
1061
|
+
t("connection")
|
|
590
1062
|
] }),
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
594
|
-
|
|
595
|
-
"
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
}
|
|
603
|
-
|
|
1063
|
+
auth.connectivity === "manual" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary }, onClick: checkStatus, children: t("retryNow") }) }),
|
|
1064
|
+
phase === "waiting" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1065
|
+
auth.shared && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
1066
|
+
"\u24D8 ",
|
|
1067
|
+
t("attemptShared")
|
|
1068
|
+
] }),
|
|
1069
|
+
codeNotice && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.card, children: [
|
|
1070
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.codeHint, children: t("codeHint") }),
|
|
1071
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.codeRow, children: [
|
|
1072
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: styles.code, children: codeNotice.code }),
|
|
1073
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary }, onClick: () => copyCode(codeNotice.code), children: copied ? t("copied") : t("copy") })
|
|
1074
|
+
] }),
|
|
1075
|
+
codeNotice.url && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { style: styles.link, href: codeNotice.url, target: "_blank", rel: "noreferrer", children: codeNotice.url }),
|
|
1076
|
+
copyFail && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.error, children: t("copyFailed") })
|
|
1077
|
+
] }),
|
|
1078
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary }, onClick: withdraw, children: t("withdrawAuth") }) })
|
|
604
1079
|
] }),
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
1080
|
+
phase === "risk" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.card, children: [
|
|
1081
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
1082
|
+
"\u26A0 ",
|
|
1083
|
+
t("authUnsafe")
|
|
1084
|
+
] }),
|
|
1085
|
+
auth.riskKind === "withdrawal-pending-unverified" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.modalText, children: auth.withdrawalDelivery === "invoked" ? t("withdrawal") : t("withdrawalUnavailable") }),
|
|
1086
|
+
auth.riskKind === "timed-out-unverified" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.modalText, children: t("attemptTimeout") }),
|
|
1087
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary }, onClick: checkStatus, children: t("retryNow") }) })
|
|
608
1088
|
] }),
|
|
609
|
-
|
|
1089
|
+
phase === "unavailable" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
610
1090
|
"\u26A0 ",
|
|
611
|
-
t("
|
|
1091
|
+
t("unavailable")
|
|
612
1092
|
] }),
|
|
613
|
-
|
|
614
|
-
|
|
1093
|
+
phase === "failed" && attempt?.error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.error, children: attempt.error }),
|
|
1094
|
+
phase === "failed" && !attempt?.error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1095
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
1096
|
+
"\u26A0 ",
|
|
1097
|
+
httpErrorText(t, auth.error) ?? t("unknown")
|
|
1098
|
+
] }),
|
|
1099
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary }, onClick: checkStatus, children: t("retryNow") }) })
|
|
1100
|
+
] }),
|
|
1101
|
+
phase === "idle" && auth.error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
615
1102
|
"\u26A0 ",
|
|
616
|
-
t("
|
|
1103
|
+
httpErrorText(t, auth.error) ?? t("unknown")
|
|
1104
|
+
] }),
|
|
1105
|
+
phase === "authorized" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.card, children: [
|
|
1106
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" }, children: [
|
|
1107
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary, opacity: 0.5, cursor: "not-allowed" }, disabled: true, title: t("authUnsafe"), children: t("logout") }),
|
|
1108
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary, opacity: 0.5, cursor: "not-allowed" }, disabled: true, title: t("authUnsafe"), children: t("reauthorize") }),
|
|
1109
|
+
["previewing", "applying", "checking", "retiring"].includes(flow.name) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.primary, opacity: 0.5 }, disabled: true, children: flow.name === "applying" ? t("applying") : t("refreshing") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1110
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1111
|
+
"button",
|
|
1112
|
+
{
|
|
1113
|
+
type: "button",
|
|
1114
|
+
style: { ...styles.button, ...styles.primary, ...refreshBlocked(flow.flags) ? { opacity: 0.5, cursor: "not-allowed" } : null },
|
|
1115
|
+
disabled: refreshBlocked(flow.flags),
|
|
1116
|
+
onClick: () => drive({ type: "start", operation: "supplement" }),
|
|
1117
|
+
children: t("supplement")
|
|
1118
|
+
}
|
|
1119
|
+
),
|
|
1120
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1121
|
+
"button",
|
|
1122
|
+
{
|
|
1123
|
+
type: "button",
|
|
1124
|
+
style: { ...styles.button, ...styles.primary, ...refreshBlocked(flow.flags) ? { opacity: 0.5, cursor: "not-allowed" } : null },
|
|
1125
|
+
disabled: refreshBlocked(flow.flags),
|
|
1126
|
+
onClick: () => drive({ type: "start", operation: "rebuild" }),
|
|
1127
|
+
children: t("rebuild")
|
|
1128
|
+
}
|
|
1129
|
+
)
|
|
1130
|
+
] })
|
|
1131
|
+
] }),
|
|
1132
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
1133
|
+
"\u24D8 ",
|
|
1134
|
+
t("authUnsafe")
|
|
1135
|
+
] }),
|
|
1136
|
+
refreshBlocked(flow.flags) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
1137
|
+
"\u26A0 ",
|
|
1138
|
+
blockedReasonText(t, flow.flags)
|
|
1139
|
+
] }),
|
|
1140
|
+
flow.flags?.legacyStateDetected && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
1141
|
+
"\u24D8 ",
|
|
1142
|
+
t("legacy")
|
|
1143
|
+
] }),
|
|
1144
|
+
flow.name === "pendingRestart" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
1145
|
+
"\u26A0 ",
|
|
1146
|
+
t("pendingRestart")
|
|
1147
|
+
] }),
|
|
1148
|
+
flow.name === "busy" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.banner, children: [
|
|
1149
|
+
"\u24D8 ",
|
|
1150
|
+
t("busy")
|
|
1151
|
+
] }),
|
|
1152
|
+
flow.name === "resultUnknown" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1153
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: styles.error, children: [
|
|
1154
|
+
"\u26A0 ",
|
|
1155
|
+
t("unknownResult")
|
|
1156
|
+
] }),
|
|
1157
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary }, onClick: () => drive({ type: "check" }), children: t("retryNow") }) })
|
|
1158
|
+
] }),
|
|
1159
|
+
flow.name === "result" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1160
|
+
(() => {
|
|
1161
|
+
const st = flow.result?.status;
|
|
1162
|
+
const key = {
|
|
1163
|
+
applied: "applied",
|
|
1164
|
+
conflict: "conflict",
|
|
1165
|
+
partial: "partial",
|
|
1166
|
+
"rolled-back": "rolledBack",
|
|
1167
|
+
"rollback-conflict": "rollbackConflict",
|
|
1168
|
+
"recovery-needed": "recoveryNeeded",
|
|
1169
|
+
"intent-retired": "recoveryNeeded"
|
|
1170
|
+
}[st];
|
|
1171
|
+
return key ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: st === "applied" ? styles.banner : styles.error, children: [
|
|
1172
|
+
st === "applied" ? "\u2713" : "\u26A0",
|
|
1173
|
+
" ",
|
|
1174
|
+
t(key)
|
|
1175
|
+
] }) : null;
|
|
1176
|
+
})(),
|
|
1177
|
+
["recovery-needed", "rollback-conflict", "intent-retired"].includes(flow.result?.status) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.secondary }, onClick: () => drive({ type: "retire-request" }), children: t("retireBtn") }) }),
|
|
1178
|
+
(flow.result?.error || flow.result?.changes) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { style: styles.modalText, children: [
|
|
1179
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: t("techDetails") }),
|
|
1180
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { ...styles.mono, fontSize: 12 }, children: [
|
|
1181
|
+
flow.result?.error ?? "",
|
|
1182
|
+
flow.result?.changes ? ` ${JSON.stringify(flow.result.changes)}` : ""
|
|
1183
|
+
] })
|
|
1184
|
+
] })
|
|
1185
|
+
] }),
|
|
1186
|
+
flow.name === "failed" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.error, children: flow.error === "state-corrupt" ? t("stateCorrupt") : flow.error })
|
|
617
1187
|
] }),
|
|
618
|
-
page === "authorized" && flow.name === "failed" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.error, children: flow.error === "state-corrupt" ? t("stateCorrupt") : flow.error === "catalog-not-writable" ? t("notWritable") : flow.error === "registry-inject-failed" || flow.error === "registry-not-effective" ? t("registryFailed") : flow.error }),
|
|
619
1188
|
flow.name === "confirming" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
620
1189
|
RefreshModal,
|
|
621
1190
|
{
|
|
622
1191
|
t,
|
|
623
1192
|
flow,
|
|
624
|
-
|
|
1193
|
+
onSelect: (selectedIds) => drive({ type: "select", selectedIds }),
|
|
1194
|
+
onConfirm: (opts) => drive({ type: "confirm", ...opts }),
|
|
625
1195
|
onCancel: () => drive({ type: "cancel" }),
|
|
626
|
-
onOverlay: () => drive({ type: "start",
|
|
1196
|
+
onOverlay: () => drive({ type: "start", catalogSource: "overlay" })
|
|
1197
|
+
}
|
|
1198
|
+
),
|
|
1199
|
+
flow.name === "retireConfirm" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1200
|
+
RetireDialog,
|
|
1201
|
+
{
|
|
1202
|
+
t,
|
|
1203
|
+
onConfirm: () => drive({ type: "retire-confirm" }),
|
|
1204
|
+
onCancel: () => drive({ type: "cancel" })
|
|
627
1205
|
}
|
|
628
1206
|
),
|
|
629
|
-
(
|
|
1207
|
+
(phase === "idle" || phase === "failed") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...styles.button, ...styles.primary }, onClick: login, children: t("login") }) })
|
|
630
1208
|
] });
|
|
631
1209
|
}
|
|
632
1210
|
function apply(ctx) {
|