@songsid/agend 2.3.2-beta.1 → 2.3.2-beta.11
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/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/agent-cli.js +69 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +11 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-whats-new.js +3 -0
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/antigravity-usage-scan.d.ts +58 -0
- package/dist/antigravity-usage-scan.js +257 -0
- package/dist/antigravity-usage-scan.js.map +1 -0
- package/dist/antigravity-usage-worker.d.ts +1 -0
- package/dist/antigravity-usage-worker.js +10 -0
- package/dist/antigravity-usage-worker.js.map +1 -0
- package/dist/auth-api.js +4 -0
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/kiro-classic-archive.d.ts +52 -0
- package/dist/backend/kiro-classic-archive.js +444 -0
- package/dist/backend/kiro-classic-archive.js.map +1 -0
- package/dist/backend/kiro-identity.d.ts +83 -0
- package/dist/backend/kiro-identity.js +144 -0
- package/dist/backend/kiro-identity.js.map +1 -1
- package/dist/backend/kiro-migration-verify.d.ts +10 -0
- package/dist/backend/kiro-migration-verify.js +52 -0
- package/dist/backend/kiro-migration-verify.js.map +1 -0
- package/dist/backend/kiro-retired-model.d.ts +62 -0
- package/dist/backend/kiro-retired-model.js +160 -0
- package/dist/backend/kiro-retired-model.js.map +1 -0
- package/dist/backend/kiro-v2-store-worker.js +21 -1
- package/dist/backend/kiro-v2-store-worker.js.map +1 -1
- package/dist/backend/kiro-v2-store.d.ts +8 -0
- package/dist/backend/kiro-v2-store.js.map +1 -1
- package/dist/backend/kiro.d.ts +169 -2
- package/dist/backend/kiro.js +703 -28
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +108 -0
- package/dist/backend/types.js +9 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-signin-guide.d.ts +1 -0
- package/dist/backend-signin-guide.js +9 -0
- package/dist/backend-signin-guide.js.map +1 -0
- package/dist/backend-signin-pending.d.ts +10 -0
- package/dist/backend-signin-pending.js +44 -0
- package/dist/backend-signin-pending.js.map +1 -0
- package/dist/browser-backend-signins.d.ts +56 -0
- package/dist/browser-backend-signins.js +189 -0
- package/dist/browser-backend-signins.js.map +1 -0
- package/dist/cache-ledger.d.ts +38 -2
- package/dist/cache-ledger.js +133 -8
- package/dist/cache-ledger.js.map +1 -1
- package/dist/cache-prices.d.ts +2 -1
- package/dist/cache-prices.js +5 -2
- package/dist/cache-prices.js.map +1 -1
- package/dist/cache-service.d.ts +68 -0
- package/dist/cache-service.js +355 -13
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +11 -0
- package/dist/channel/adapters/discord.js +71 -14
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/ipc-timeouts.js +3 -0
- package/dist/channel/ipc-timeouts.js.map +1 -1
- package/dist/channel/mcp-tools.js +41 -2
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/tool-router.js +2 -1
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +11 -0
- package/dist/classic-channel-manager.js +39 -1
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +54 -2
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.d.ts +7 -1
- package/dist/config-validator.js +55 -10
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.js +33 -1
- package/dist/config.js.map +1 -1
- package/dist/cpu-quota.d.ts +23 -0
- package/dist/cpu-quota.js +86 -0
- package/dist/cpu-quota.js.map +1 -0
- package/dist/daemon.d.ts +68 -0
- package/dist/daemon.js +448 -26
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard-permissions.d.ts +31 -6
- package/dist/dashboard-permissions.js +84 -9
- package/dist/dashboard-permissions.js.map +1 -1
- package/dist/doctor.js +2 -1
- package/dist/doctor.js.map +1 -1
- package/dist/fleet-control-audit.d.ts +1 -1
- package/dist/fleet-control-audit.js +3 -0
- package/dist/fleet-control-audit.js.map +1 -1
- package/dist/fleet-manager.d.ts +133 -2
- package/dist/fleet-manager.js +905 -94
- package/dist/fleet-manager.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +9 -0
- package/dist/forged-envelope-scan.js +30 -5
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +5 -2
- package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +24 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +49 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +49 -1
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +47 -9
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +54 -11
- package/dist/instance-config-impact.js +10 -5
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +23 -0
- package/dist/instance-lifecycle.js +62 -12
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/kiro-db-reader.d.ts +5 -0
- package/dist/kiro-db-reader.js +18 -0
- package/dist/kiro-db-reader.js.map +1 -1
- package/dist/kiro-engine-status.d.ts +2 -0
- package/dist/kiro-engine-status.js +9 -0
- package/dist/kiro-engine-status.js.map +1 -1
- package/dist/kiro-migrate.d.ts +60 -0
- package/dist/kiro-migrate.js +160 -0
- package/dist/kiro-migrate.js.map +1 -0
- package/dist/kiro-session-proof.d.ts +41 -0
- package/dist/kiro-session-proof.js +89 -0
- package/dist/kiro-session-proof.js.map +1 -0
- package/dist/kiro-transcript-lane.d.ts +2 -0
- package/dist/kiro-transcript-lane.js.map +1 -1
- package/dist/kiro-transcript-worker.js +1 -0
- package/dist/kiro-transcript-worker.js.map +1 -1
- package/dist/kiro-tui-forensic.d.ts +12 -0
- package/dist/kiro-tui-forensic.js +110 -0
- package/dist/kiro-tui-forensic.js.map +1 -0
- package/dist/kiro-usage-run.d.ts +7 -0
- package/dist/kiro-usage-run.js +39 -0
- package/dist/kiro-usage-run.js.map +1 -0
- package/dist/kiro-usage-scan.d.ts +49 -0
- package/dist/kiro-usage-scan.js +223 -0
- package/dist/kiro-usage-scan.js.map +1 -0
- package/dist/kiro-usage-worker.d.ts +1 -0
- package/dist/kiro-usage-worker.js +10 -0
- package/dist/kiro-usage-worker.js.map +1 -0
- package/dist/kiro-usage.d.ts +58 -0
- package/dist/kiro-usage.js +310 -0
- package/dist/kiro-usage.js.map +1 -0
- package/dist/locale.js +230 -8
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +1 -1
- package/dist/log-service.js.map +1 -1
- package/dist/login-url.d.ts +4 -0
- package/dist/login-url.js +22 -0
- package/dist/login-url.js.map +1 -0
- package/dist/needs-you-hub.d.ts +2 -1
- package/dist/needs-you-hub.js +1 -1
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +10 -2
- package/dist/needs-you.js +10 -2
- package/dist/needs-you.js.map +1 -1
- package/dist/notice-delivery.d.ts +16 -0
- package/dist/notice-delivery.js +35 -0
- package/dist/notice-delivery.js.map +1 -0
- package/dist/office-share-page.d.ts +16 -0
- package/dist/office-share-page.js +85 -0
- package/dist/office-share-page.js.map +1 -0
- package/dist/office-share-service.d.ts +91 -0
- package/dist/office-share-service.js +176 -0
- package/dist/office-share-service.js.map +1 -0
- package/dist/office-share.d.ts +268 -0
- package/dist/office-share.js +574 -0
- package/dist/office-share.js.map +1 -0
- package/dist/opencode-usage-scan.d.ts +28 -0
- package/dist/opencode-usage-scan.js +92 -0
- package/dist/opencode-usage-scan.js.map +1 -0
- package/dist/opencode-usage-worker.d.ts +1 -0
- package/dist/opencode-usage-worker.js +10 -0
- package/dist/opencode-usage-worker.js.map +1 -0
- package/dist/outbound-handlers.js +22 -2
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +65 -2
- package/dist/outbound-schemas.js +56 -2
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +7 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart-api.js +13 -2
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.js +2 -1
- package/dist/quickstart.js.map +1 -1
- package/dist/remote-card-answer.d.ts +83 -0
- package/dist/remote-card-answer.js +208 -0
- package/dist/remote-card-answer.js.map +1 -0
- package/dist/remote-card-prompt.d.ts +38 -0
- package/dist/remote-card-prompt.js +86 -0
- package/dist/remote-card-prompt.js.map +1 -0
- package/dist/reply-triggers.d.ts +2 -0
- package/dist/reply-triggers.js +3 -0
- package/dist/reply-triggers.js.map +1 -0
- package/dist/settings-api.d.ts +2 -0
- package/dist/settings-api.js +41 -16
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +20 -14
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +7 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-instance-patch.js +4 -1
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +55 -6
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-host.d.ts +9 -0
- package/dist/setup-host.js +127 -6
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-signin-assets.d.ts +2 -0
- package/dist/setup-signin-assets.js +6 -0
- package/dist/setup-signin-assets.js.map +1 -0
- package/dist/setup-wizard.js +2 -0
- package/dist/setup-wizard.js.map +1 -1
- package/dist/structured-signin-transport.d.ts +8 -0
- package/dist/structured-signin-transport.js +79 -0
- package/dist/structured-signin-transport.js.map +1 -0
- package/dist/structured-signin.d.ts +131 -0
- package/dist/structured-signin.js +388 -0
- package/dist/structured-signin.js.map +1 -0
- package/dist/tool-permissions.js +29 -0
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.js +6 -2
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-sources.d.ts +27 -2
- package/dist/transcript-sources.js +104 -40
- package/dist/transcript-sources.js.map +1 -1
- package/dist/turn-reply-guard.d.ts +1 -1
- package/dist/turn-reply-guard.js +1 -1
- package/dist/turn-reply-guard.js.map +1 -1
- package/dist/types.d.ts +33 -8
- package/dist/ui/backend-signin.js +63 -10
- package/dist/ui/chat-store.js +3 -2
- package/dist/ui/chat-strings.js +4 -4
- package/dist/ui/fleet-office-editor.js +68 -11
- package/dist/ui/fleet-office-layout.js +110 -35
- package/dist/ui/fleet-office-model.js +6 -3
- package/dist/ui/fleet-office-overview.js +167 -0
- package/dist/ui/fleet-office-pack.d.ts +13 -3
- package/dist/ui/fleet-office-pack.js +214 -24
- package/dist/ui/fleet-office-skin.js +98 -23
- package/dist/ui/fleet-office-store.js +82 -5
- package/dist/ui/fleet-office-view.js +5 -4
- package/dist/ui/fleet-office-zones.js +232 -21
- package/dist/ui/fleet-office.js +549 -186
- package/dist/ui/fleet-usage.js +19 -15
- package/dist/ui/office-share-dialog.js +145 -0
- package/dist/ui/office-share-page.js +164 -0
- package/dist/ui/panel-chat.js +22 -3
- package/dist/ui/panel-log.js +4 -4
- package/dist/ui/panel-needs.js +5 -5
- package/dist/ui/panel-settings.js +38 -12
- package/dist/ui/settings-dialogs.js +8 -1
- package/dist/ui/settings-guests.js +17 -7
- package/dist/ui/settings-model.js +22 -6
- package/dist/ui/settings-registry.js +4 -0
- package/dist/ui/settings-strings.js +18 -2
- package/dist/ui/shared/app-i18n.js +4 -2
- package/dist/ui/shared/app-shell.js +14 -6
- package/dist/ui/shared/app-stream.js +2 -1
- package/dist/ui/shared/app.css +85 -4
- package/dist/ui/shared/office/cozy.png +0 -0
- package/dist/ui/shared/side-panel.js +95 -0
- package/dist/ui/structured-signin.js +115 -0
- package/dist/usage-report.d.ts +20 -0
- package/dist/usage-report.js +54 -17
- package/dist/usage-report.js.map +1 -1
- package/dist/usage-rollup.d.ts +9 -1
- package/dist/usage-rollup.js +20 -4
- package/dist/usage-rollup.js.map +1 -1
- package/dist/web-api.d.ts +23 -1
- package/dist/web-api.js +292 -3
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +1 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-backend-login.d.ts +1 -7
- package/dist/web-backend-login.js +2 -24
- package/dist/web-backend-login.js.map +1 -1
- package/dist/web-office-acts.d.ts +173 -0
- package/dist/web-office-acts.js +285 -0
- package/dist/web-office-acts.js.map +1 -0
- package/dist/web-office-pack-read.d.ts +35 -0
- package/dist/web-office-pack-read.js +252 -0
- package/dist/web-office-pack-read.js.map +1 -0
- package/dist/web-office-pack-tools.d.ts +232 -0
- package/dist/web-office-pack-tools.js +754 -0
- package/dist/web-office-pack-tools.js.map +1 -0
- package/dist/web-office-skins.d.ts +71 -6
- package/dist/web-office-skins.js +321 -35
- package/dist/web-office-skins.js.map +1 -1
- package/dist/web-office-store.d.ts +5 -2
- package/dist/web-office-store.js +69 -10
- package/dist/web-office-store.js.map +1 -1
- package/dist/web-settings-patch.d.ts +2 -1
- package/dist/web-settings-patch.js +4 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/working-recovery.d.ts +2 -2
- package/dist/working-recovery.js +43 -8
- package/dist/working-recovery.js.map +1 -1
- package/dist/working-state-journal.d.ts +2 -0
- package/dist/working-state-journal.js +16 -1
- package/dist/working-state-journal.js.map +1 -1
- package/package.json +3 -2
- package/templates/windows-shortcuts.ps1 +155 -140
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
// session that started a sign-in gets its terminal link, access code and device code; every other admin page only that
|
|
6
6
|
// one runs, on which device, and may cancel it. The stream's `backend_login` event carries nothing — it only says to
|
|
7
7
|
// read again. Starting is two steps, as in chat: check (the server keeps what it found) and start (with its id).
|
|
8
|
-
import { html, useEffect, useState } from "/assets/app-html.js";
|
|
8
|
+
import { html, useEffect, useState, useRef } from "/assets/app-html.js";
|
|
9
9
|
import { t, register } from "/assets/app-i18n.js";
|
|
10
10
|
import { appStore, createStore, useStore } from "/assets/app-store.js";
|
|
11
11
|
import { closeDialog, shellStore, showDialog } from "/assets/app-shell.js";
|
|
12
12
|
import { Dialog } from "/assets/ui-dialog.js";
|
|
13
13
|
import { toast } from "/assets/ui-toast.js";
|
|
14
|
+
import { mountStructuredSignIns } from "./structured-signin.js";
|
|
14
15
|
|
|
15
16
|
register("signin", {
|
|
16
17
|
en: {
|
|
@@ -49,6 +50,8 @@ register("signin", {
|
|
|
49
50
|
notOffered: "A public link is not offered for this sign-in.",
|
|
50
51
|
failed: "That did not work.",
|
|
51
52
|
listTitle: "Sign-ins",
|
|
53
|
+
browserRunning: "Signing in to {0} on this machine",
|
|
54
|
+
consoleFallback: "Use console fallback",
|
|
52
55
|
listHint: "Each backend's login on this machine, and each credential profile an agent uses.",
|
|
53
56
|
stUsable: "signed in",
|
|
54
57
|
stNotSignedIn: "not signed in",
|
|
@@ -98,6 +101,8 @@ register("signin", {
|
|
|
98
101
|
notOffered: "這次登入不提供公開連結。",
|
|
99
102
|
failed: "沒有成功。",
|
|
100
103
|
listTitle: "登入",
|
|
104
|
+
browserRunning: "正在這台機器登入 {0}",
|
|
105
|
+
consoleFallback: "改用主控台備援",
|
|
101
106
|
listHint: "這台機器上每個 backend 的登入,以及代理使用的每個憑證設定檔。",
|
|
102
107
|
stUsable: "已登入",
|
|
103
108
|
stNotSignedIn: "未登入",
|
|
@@ -116,7 +121,7 @@ const tn = (k, ...v) => t(`signin.${k}`, ...v);
|
|
|
116
121
|
const shownOf = (backend, profile) => (profile ? tn("profile", backend, profile) : backend);
|
|
117
122
|
|
|
118
123
|
/** What this page knows: the current sign-in as this session may see it, and Settings' list. */
|
|
119
|
-
export const signInStore = createStore({ loaded: false, login: null, targets: [] });
|
|
124
|
+
export const signInStore = createStore({ loaded: false, login: null, targets: [], structured: null });
|
|
120
125
|
|
|
121
126
|
let reading = null, again = false;
|
|
122
127
|
/**
|
|
@@ -125,9 +130,13 @@ let reading = null, again = false;
|
|
|
125
130
|
*/
|
|
126
131
|
export function refreshSignIn() {
|
|
127
132
|
if (reading) { again = true; return reading; }
|
|
128
|
-
reading =
|
|
129
|
-
.then(
|
|
130
|
-
|
|
133
|
+
reading = Promise.all([
|
|
134
|
+
fetch("/ui/backend-login", { cache: "no-store" }).then(r => r.ok ? r.json() : null).catch(() => null),
|
|
135
|
+
fetch("/ui/browser-backend-signins", { cache: "no-store" }).then(r => r.ok ? r.json() : null).catch(() => null),
|
|
136
|
+
]).then(([b, structured]) => {
|
|
137
|
+
if (b) signInStore.set({ loaded: true, login: b.login || null, targets: Array.isArray(b.targets) ? b.targets : [] });
|
|
138
|
+
signInStore.set({ structured: structured && Array.isArray(structured.selected) && Array.isArray(structured.pending) ? structured : null }); return b;
|
|
139
|
+
})
|
|
131
140
|
.catch(() => null)
|
|
132
141
|
.finally(() => { reading = null; if (again) { again = false; void refreshSignIn(); } });
|
|
133
142
|
return reading;
|
|
@@ -140,13 +149,25 @@ export function installSignIn() {
|
|
|
140
149
|
installed = true;
|
|
141
150
|
const on = appStore.get().streamOn;
|
|
142
151
|
if (typeof on === "function") on("backend_login", () => { void refreshSignIn(); });
|
|
143
|
-
void refreshSignIn()
|
|
152
|
+
void refreshSignIn().then(() => {
|
|
153
|
+
// A navigation hint from the installer, never authority to start a CLI or cancel another writer.
|
|
154
|
+
const backends = installerSignInBackends(typeof location === "undefined" ? "" : location.search);
|
|
155
|
+
if (backends && signInStore.get().structured) showDialog(BrowserSignInDialog, { backends });
|
|
156
|
+
});
|
|
144
157
|
shellStore.set({ banner: SignInLine });
|
|
145
158
|
}
|
|
146
159
|
|
|
160
|
+
export function installerSignInBackends(search) {
|
|
161
|
+
const csv = new URLSearchParams(search).get("backend_signins");
|
|
162
|
+
if (!csv || csv.length > 100) return null;
|
|
163
|
+
const ids = csv.split(",");
|
|
164
|
+
return ids.length <= 4 && ids.every(b => ["kiro-cli", "claude-code", "codex", "antigravity"].includes(b)) ? [...new Set(ids)] : null;
|
|
165
|
+
}
|
|
166
|
+
|
|
147
167
|
/** Open the dialog for one login (a backend's default one, or a credential profile). */
|
|
148
168
|
export function openSignIn({ backend, profile }) {
|
|
149
|
-
|
|
169
|
+
if (!profile && ["kiro-cli", "claude-code", "codex"].includes(backend)) showDialog(BrowserSignInDialog, { backend });
|
|
170
|
+
else showDialog(SignInDialog, { backend, ...(profile ? { profile } : {}) });
|
|
150
171
|
}
|
|
151
172
|
|
|
152
173
|
/** Open the dialog on the running sign-in (its starter's view, or the cancel-only one). */
|
|
@@ -191,6 +212,32 @@ function Running({ login }) {
|
|
|
191
212
|
</div>`;
|
|
192
213
|
}
|
|
193
214
|
|
|
215
|
+
/** The same closed controls as first setup. Profile-specific logins retain their existing flow. */
|
|
216
|
+
export function BrowserSignInDialog({ backend, backends, onClose }) {
|
|
217
|
+
const root = useRef(null), close = onClose || closeDialog;
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
let cards, last = "";
|
|
220
|
+
cards = mountStructuredSignIns(root.current, { endpoint: "/ui/browser-backend-signins", changed: next => {
|
|
221
|
+
if (backends) { if (backends.some(b => !next.selected.includes(b))) void cards.addBackends(backends); }
|
|
222
|
+
else if (!next.selected.includes(backend)) void cards.addBackend(backend);
|
|
223
|
+
const signature = JSON.stringify([next.login, next.pending]);
|
|
224
|
+
if (signature !== last) { last = signature; void refreshSignIn(); }
|
|
225
|
+
} });
|
|
226
|
+
return () => cards.dispose();
|
|
227
|
+
}, [backend, backends]);
|
|
228
|
+
const fallback = async (chosen = backend) => {
|
|
229
|
+
const result = await post("/ui/browser-backend-signins", { operation: "cancel" });
|
|
230
|
+
if (!result.ok) { toast(tn("failed")); return; }
|
|
231
|
+
showDialog(SignInDialog, { backend: chosen });
|
|
232
|
+
};
|
|
233
|
+
return html`<${Dialog} title=${backends ? tn("listTitle") : tn("title", backend)} onClose=${close}>
|
|
234
|
+
<div ref=${root}></div>
|
|
235
|
+
${backends ? backends.filter(b => b !== "antigravity").map(b => html`<button type="button" class="btn" onClick=${() => fallback(b)}>${b} · ${tn("consoleFallback")}</button>`) : null}
|
|
236
|
+
<div class="s-actions">${backend ? html`<button type="button" class="btn" onClick=${() => fallback(backend)}>${tn("consoleFallback")}</button>` : null}
|
|
237
|
+
<button type="button" class="btn" onClick=${close}>${tn("close")}</button></div>
|
|
238
|
+
</${Dialog}>`;
|
|
239
|
+
}
|
|
240
|
+
|
|
194
241
|
export function SignInDialog({ backend, profile, resume = false, onClose }) {
|
|
195
242
|
const s = useStore(signInStore);
|
|
196
243
|
const [step, setStep] = useState(resume ? { kind: "login" } : { kind: "checking" });
|
|
@@ -265,7 +312,12 @@ export function SignInDialog({ backend, profile, resume = false, onClose }) {
|
|
|
265
312
|
|
|
266
313
|
/** The line every admin page shows while a sign-in runs (the shell's banner slot). */
|
|
267
314
|
export function SignInLine() {
|
|
268
|
-
const { login } = useStore(signInStore);
|
|
315
|
+
const { login, structured } = useStore(signInStore);
|
|
316
|
+
const active = structured?.login;
|
|
317
|
+
if ((!login || login.phase !== "running") && active && active.phase !== "done" && !(active.phase === "failed" && active.reason)) {
|
|
318
|
+
return html`<div data-trust="status" class="conn op-line signin-line" role="status"><span>${tn("browserRunning", active.backend)}</span>
|
|
319
|
+
<button type="button" class="btn btn-sm" onClick=${() => openSignIn({ backend: active.backend })}>${tn("open")}</button></div>`;
|
|
320
|
+
}
|
|
269
321
|
if (!login || login.phase !== "running") return null;
|
|
270
322
|
return html`<div data-trust="status" class="conn op-line signin-line" role="status">
|
|
271
323
|
<span>${tn("running", shownOf(login.backend, login.profile), login.startedOn)}</span>
|
|
@@ -276,13 +328,14 @@ const STATE_KEY = { usable: "stUsable", not_signed_in: "stNotSignedIn", not_inst
|
|
|
276
328
|
|
|
277
329
|
/** Settings → Agents: each login on this machine, with Sign in where the dashboard can do it. */
|
|
278
330
|
export function SignInList() {
|
|
279
|
-
const { targets, loaded, login } = useStore(signInStore);
|
|
331
|
+
const { targets, loaded, login, structured } = useStore(signInStore);
|
|
280
332
|
// Not over the temporary public link: only the dashboard reached directly signs a backend in, and the link does not
|
|
281
333
|
// serve this read (it was a 404 in the console there, found by smoke-1939-authorize-defaults).
|
|
282
334
|
const offered = signInOffered();
|
|
283
335
|
useEffect(() => { if (offered) void refreshSignIn(); }, []);
|
|
284
336
|
if (!offered || !loaded || !targets.length) return null;
|
|
285
|
-
const
|
|
337
|
+
const active = structured?.login;
|
|
338
|
+
const running = (login && login.phase === "running") || (active && active.phase !== "done" && !(active.phase === "failed" && active.reason));
|
|
286
339
|
return html`<section class="s-group signin-list" aria-label=${tn("listTitle")}>
|
|
287
340
|
<div class="list-head"><span>${tn("listTitle")}</span></div>
|
|
288
341
|
<p class="sub">${tn("listHint")}</p>
|
package/dist/ui/chat-store.js
CHANGED
|
@@ -208,11 +208,12 @@ export function createChatStore(deps) {
|
|
|
208
208
|
deps.setTimeout(() => { if (s.prompts[d.nonce] === p) { delete s.prompts[d.nonce]; changed(p.instance); } }, 60000);
|
|
209
209
|
changed(p.instance);
|
|
210
210
|
}
|
|
211
|
-
|
|
211
|
+
/** `text`: #2675 — the typed answer, for an action the prompt shows a text box for. */
|
|
212
|
+
async function answerPrompt(p, action, text) {
|
|
212
213
|
if (p.busy || p.resolved) return;
|
|
213
214
|
p.busy = true; changed(p.instance);
|
|
214
215
|
let r;
|
|
215
|
-
try { r = await api("POST", "/ui/prompt", { instance: p.instance, nonce: p.nonce, action }); }
|
|
216
|
+
try { r = await api("POST", "/ui/prompt", { instance: p.instance, nonce: p.nonce, action, ...(text !== undefined ? { text } : {}) }); }
|
|
216
217
|
catch (err) { r = { error: err && err.message ? err.message : t("chat.disconnected") }; }
|
|
217
218
|
if (r && r.answered) return; // the outcome arrives as prompt_resolved
|
|
218
219
|
const latest = s.prompts[p.nonce];
|
package/dist/ui/chat-strings.js
CHANGED
|
@@ -111,12 +111,12 @@ register("chat", {
|
|
|
111
111
|
clicked: "Clicked:", clickShow: "Show the message these buttons were on",
|
|
112
112
|
copy: "Copy", copyMessage: "Copy this reply", copied: "Copied", copyFailed: "Copy failed", wrap: "Wrap", showAll: "Show all {0} lines", showMore: "Show more", showLess: "Show less", jumpLatest: "Latest", newBelow: "{0} new",
|
|
113
113
|
disconnected: "disconnected", tick_queued: "Waiting behind another message", tick_processing: "Handed to the agent", tick_delivered: "The agent has it", tick_failed: "Not delivered", tick_cancelled: "Dropped by Stop", reactedBy: "{0} reacted",
|
|
114
|
-
promptAnswering: "Answering…", promptGone: "This prompt is no longer open", promptFor: "{0}: {1}",
|
|
114
|
+
promptAnswering: "Answering…", promptGone: "This prompt is no longer open", promptTextPlaceholder: "Your answer", promptTextSend: "Send answer", promptFor: "{0}: {1}",
|
|
115
115
|
working: "{0} is working…", stuck: "{0} looks stuck", stopReply: "Stop reply", stopReplyTitle: "Stop the current reply (like Esc) and drop the messages still waiting. The instance keeps running.", stopSent: "Stopped",
|
|
116
116
|
file_empty: "empty file", file_too_large: "over {0} MB", file_too_large_public: "over {0} MB — the most the public link carries in one upload", file_too_many: "at most {0} files per message", file_too_much: "the files together would be over {0} MB", removeFile: "Remove", putBack: "Put back",
|
|
117
117
|
noMessages: "Type a task below.",
|
|
118
118
|
pick: "Choose an agent to start chatting.", noAgents: "Create an agent to start chatting.", newAgent: "New agent", notFound: "No instance called “{0}”", notFoundHint: "It may have been deleted or renamed.", backToList: "Choose an agent",
|
|
119
|
-
details: "Instance details", start: "Start instance", stopInstance: "Stop instance", restart: "Restart instance", delete: "Delete instance…",
|
|
119
|
+
details: "Instance details", fullWidth: "Full width", start: "Start instance", stopInstance: "Stop instance", restart: "Restart instance", delete: "Delete instance…",
|
|
120
120
|
started: "{0} started", stoppedInst: "{0} stopped", restarted: "{0} restarted", instanceDeleted: "{0} was deleted",
|
|
121
121
|
deleteTitle: "Delete {0}?", deleteHelp: "This removes the instance from the fleet and stops it. Its working directory is kept. Type “delete {0}” to confirm.", deleteGo: "Delete", cancel: "Cancel",
|
|
122
122
|
loadFailed: "Failed to load", tour: "Chat tour", tourBtnTitle: "Show the chat tour on an agent's chat", tourNoAgent: "Choose an agent before opening the chat tour.",
|
|
@@ -250,12 +250,12 @@ register("chat", {
|
|
|
250
250
|
clicked: "點選了:", clickShow: "顯示這些按鈕所在的訊息",
|
|
251
251
|
copy: "複製", copyMessage: "複製這則回覆", copied: "已複製", copyFailed: "複製失敗", wrap: "換行", showAll: "展開全部 {0} 行", showMore: "顯示更多", showLess: "收合", jumpLatest: "最新", newBelow: "{0} 則新訊息",
|
|
252
252
|
disconnected: "已斷線", tick_queued: "排在前一則訊息之後", tick_processing: "已交給 agent", tick_delivered: "agent 已收到", tick_failed: "未送達", tick_cancelled: "已被中止取消", reactedBy: "{0} 的回應",
|
|
253
|
-
promptAnswering: "回覆中…", promptGone: "這個提示已經結束", promptFor: "{0}:{1}",
|
|
253
|
+
promptAnswering: "回覆中…", promptGone: "這個提示已經結束", promptTextPlaceholder: "你的回答", promptTextSend: "送出回答", promptFor: "{0}:{1}",
|
|
254
254
|
working: "{0} 處理中…", stuck: "{0} 似乎卡住了", stopReply: "中止回覆", stopReplyTitle: "中止目前的回覆(同 Esc),並取消還在排隊的訊息。instance 會繼續運行。", stopSent: "已中止",
|
|
255
255
|
file_empty: "空檔案", file_too_large: "超過 {0} MB", file_too_large_public: "超過 {0} MB,這是公開連結單次上傳的上限", file_too_many: "每則訊息最多 {0} 個檔案", file_too_much: "檔案合計會超過 {0} MB", removeFile: "移除", putBack: "放回輸入框",
|
|
256
256
|
noMessages: "直接在下方輸入任務。",
|
|
257
257
|
pick: "選一個 Agent 開始聊天。", noAgents: "先建立一個 Agent,再開始聊天。", newAgent: "新增 Agent", notFound: "沒有叫「{0}」的 instance", notFoundHint: "它可能已被刪除或改名。", backToList: "選擇 Agent",
|
|
258
|
-
details: "Instance 詳細資料", start: "啟動 instance", stopInstance: "停止 instance", restart: "重新啟動 instance", delete: "刪除 instance…",
|
|
258
|
+
details: "Instance 詳細資料", fullWidth: "全寬", start: "啟動 instance", stopInstance: "停止 instance", restart: "重新啟動 instance", delete: "刪除 instance…",
|
|
259
259
|
started: "{0} 已啟動", stoppedInst: "{0} 已停止", restarted: "{0} 已重新啟動", instanceDeleted: "{0} 已刪除",
|
|
260
260
|
deleteTitle: "要刪除 {0} 嗎?", deleteHelp: "這會把 instance 從 fleet 移除並停止它,工作目錄會保留。請輸入「delete {0}」確認。", deleteGo: "刪除", cancel: "取消",
|
|
261
261
|
loadFailed: "載入失敗", tour: "聊天導覽", tourBtnTitle: "在 Agent 的聊天上開啟聊天導覽", tourNoAgent: "請先選一個 Agent,再開啟聊天導覽。",
|
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
// (PUT /ui/offices; a change made meanwhile is a 409: read again, nothing overwritten). A stored office's layout (seats,
|
|
5
5
|
// paths) and its layout overrides (Edit layout, fleet-office-layout.js) are kept as they are. Skin packs (#2513): the
|
|
6
6
|
// packs the host keeps are styles to choose; an admin uploads one here (its manifest.json and its PNGs, picked together
|
|
7
|
-
// or as a folder — sent at once, checked by the host, which keeps it whole) or deletes one
|
|
7
|
+
// or as a folder — sent at once, checked by the host, which keeps it whole) or deletes one; #2692: which agents may change
|
|
8
|
+
// packs, whether their changes need the admin's yes, those waiting for it, and the newest log entries. Never offered to a guest,
|
|
8
9
|
// the public link or a read-only session (the host refuses them too).
|
|
9
|
-
import { html, useMemo, useState } from "/assets/app-html.js";
|
|
10
|
+
import { html, useEffect, useMemo, useState } from "/assets/app-html.js";
|
|
10
11
|
import { t, register } from "/assets/app-i18n.js";
|
|
11
|
-
import {
|
|
12
|
+
import { SidePanel } from "/assets/side-panel.js";
|
|
12
13
|
import { toast } from "/assets/ui-toast.js";
|
|
13
14
|
import { nodeText } from "./fleet-org.js";
|
|
15
|
+
import { BUILT_IN_SKINS } from "./fleet-office-skin.js";
|
|
14
16
|
|
|
15
17
|
register("orge", {
|
|
16
18
|
en: {
|
|
@@ -28,6 +30,11 @@ register("orge", {
|
|
|
28
30
|
packsNone: "No skin packs yet.", upload: "Upload a skin pack", uploadFolder: "Upload a folder", uploading: "Uploading…", uploaded: "Skin pack “{0}” uploaded.",
|
|
29
31
|
uploadFailed: "The skin pack was not uploaded: {0}", noManifest: "no manifest.json among the files", badManifest: "manifest.json is not JSON",
|
|
30
32
|
removePack: "Delete {0}", removedPack: "Skin pack “{0}” deleted.", removeFailed: "The skin pack was not deleted ({0}).",
|
|
33
|
+
agentsTitle: "Agents changing packs", agentsLead: "Agents with Office skin packs switched on (Settings → agent) may check, upload, replace, delete and restore packs. Each change is logged and told to you in General.",
|
|
34
|
+
agentsNone: "No agent may change packs.", agentsAllowed: "May change packs: {0}", approval: "Their changes",
|
|
35
|
+
approvalApply: "Apply at once", approvalApprove: "Need my yes", pendingNone: "Nothing waits for your yes.",
|
|
36
|
+
approve: "Approve", reject: "Reject", decided: "Done: {0}", decideFailed: "Not done: {0}", recent: "Recent changes", refresh: "Refresh",
|
|
37
|
+
act_upload: "upload", act_delete: "delete", act_restore: "restore", act_style: "office style",
|
|
31
38
|
},
|
|
32
39
|
"zh-TW": {
|
|
33
40
|
edit: "編輯辦公室", title: "辦公室", lead: "這個 fleet 的每個人在辦公室檢視中都會看到這些辦公室。沒有選任何成員的辦公室會顯示全部。",
|
|
@@ -44,11 +51,16 @@ register("orge", {
|
|
|
44
51
|
packsNone: "還沒有外觀包。", upload: "上傳外觀包", uploadFolder: "上傳資料夾", uploading: "上傳中…", uploaded: "已上傳外觀包「{0}」。",
|
|
45
52
|
uploadFailed: "外觀包沒有上傳:{0}", noManifest: "檔案中沒有 manifest.json", badManifest: "manifest.json 不是 JSON",
|
|
46
53
|
removePack: "刪除 {0}", removedPack: "已刪除外觀包「{0}」。", removeFailed: "外觀包沒有刪除({0})。",
|
|
54
|
+
agentsTitle: "會改外觀包的 agent", agentsLead: "開啟「辦公室外觀包」的 agent(設定 → agent)可以檢查、上傳、取代、刪除與還原外觀包。每次變更都會記錄,並在 General 通知你。",
|
|
55
|
+
agentsNone: "沒有 agent 能改外觀包。", agentsAllowed: "可以改外觀包:{0}", approval: "它們的變更",
|
|
56
|
+
approvalApply: "直接套用", approvalApprove: "要我核准", pendingNone: "沒有等你核准的變更。",
|
|
57
|
+
approve: "核准", reject: "拒絕", decided: "完成:{0}", decideFailed: "沒有完成:{0}", recent: "最近的變更", refresh: "重新整理",
|
|
58
|
+
act_upload: "上傳", act_delete: "刪除", act_restore: "還原", act_style: "辦公室風格",
|
|
47
59
|
},
|
|
48
60
|
});
|
|
49
61
|
const te = (k, ...v) => t(`orge.${k}`, ...v);
|
|
50
62
|
export const MAX_OFFICES = 20;
|
|
51
|
-
const STYLES =
|
|
63
|
+
const STYLES = BUILT_IN_SKINS;
|
|
52
64
|
|
|
53
65
|
/** A file's bytes as base64 (in slices: a large picture never goes through one huge string call). */
|
|
54
66
|
export function base64Of(bytes) {
|
|
@@ -113,6 +125,46 @@ function Packs({ packs, store }) {
|
|
|
113
125
|
</fieldset>`;
|
|
114
126
|
}
|
|
115
127
|
|
|
128
|
+
/**
|
|
129
|
+
* #2692: the agents that may change packs, the fleet's approval mode, the changes waiting for an admin's yes (approve /
|
|
130
|
+
* reject; judged again by the host on a yes) and the newest log entries. Read on opening, after each action, and when
|
|
131
|
+
* the packs change.
|
|
132
|
+
*/
|
|
133
|
+
function PackAgents({ store, packs }) {
|
|
134
|
+
const [d, setD] = useState(null);
|
|
135
|
+
const [busy, setBusy] = useState(false);
|
|
136
|
+
const [msg, setMsg] = useState("");
|
|
137
|
+
const load = async () => { const c = await store.packChanges(); if (c) setD(c); };
|
|
138
|
+
useEffect(() => { void load(); }, [packs.map((p) => `${p.id}:${p.sha}`).join(",")]);
|
|
139
|
+
if (!d) return null;
|
|
140
|
+
const mode = async (approval) => {
|
|
141
|
+
setBusy(true); setMsg("");
|
|
142
|
+
try { const r = await store.setPackApproval(approval); if (r.ok && r.changes) setD(r.changes); else setMsg(te("decideFailed", r.error)); } finally { setBusy(false); }
|
|
143
|
+
};
|
|
144
|
+
const decide = async (id, decision) => {
|
|
145
|
+
setBusy(true); setMsg("");
|
|
146
|
+
try { const r = await store.decidePackChange(id, decision); setMsg(r.ok ? te("decided", r.text) : te("decideFailed", r.detail || r.error)); await load(); } finally { setBusy(false); }
|
|
147
|
+
};
|
|
148
|
+
const what = (v) => `${te(`act_${v.action}`)} ${v.action === "style" ? `${v.office} → ${v.style}` : v.packs.map((p) => p.name !== p.id ? `${p.name} (${p.id})` : p.id).join(", ")}`;
|
|
149
|
+
return html`<fieldset class="oe-packs oe-form oe-pack-agents" disabled=${busy}>
|
|
150
|
+
<legend class="oe-label">${te("agentsTitle")}</legend>
|
|
151
|
+
<p class="note">${te("agentsLead")}</p>
|
|
152
|
+
<p class="note" id="oePackAgents">${d.agents.length ? te("agentsAllowed", d.agents.join(", ")) : te("agentsNone")}</p>
|
|
153
|
+
<label class="oe-field"><span class="oe-label">${te("approval")}</span>
|
|
154
|
+
<select class="tb-select oe-pack-approval" value=${d.approval} onChange=${(e) => mode(e.target.value)}>
|
|
155
|
+
<option value="approve">${te("approvalApprove")}</option><option value="apply">${te("approvalApply")}</option></select></label>
|
|
156
|
+
${d.pending.length ? html`<ul class="oe-pack-list">${d.pending.map((v) => html`<li key=${v.id} class="oe-pack oe-pack-pending" data-change=${v.id}>
|
|
157
|
+
<span>${v.instance}: ${what(v)}</span>
|
|
158
|
+
<button type="button" class="btn btn-sm btn-primary oe-pack-approve" onClick=${() => decide(v.id, "approve")}>${te("approve")}</button>
|
|
159
|
+
<button type="button" class="btn btn-sm oe-pack-reject" onClick=${() => decide(v.id, "reject")}>${te("reject")}</button></li>`)}</ul>`
|
|
160
|
+
: html`<p class="note">${te("pendingNone")}</p>`}
|
|
161
|
+
${d.log.length ? html`<details class="oe-pack-log"><summary>${te("recent")}</summary><ul class="oe-pack-list">${d.log.slice(0, 10).map((e, i) => html`<li key=${i} class="oe-pack muted">
|
|
162
|
+
<span class="mono">${e.at.slice(0, 16).replace("T", " ")}</span> <span>${e.by}: ${e.action} ${e.pack}${e.outcome ? ` — ${e.outcome}` : ""}${e.approved_by ? ` (${e.approved_by})` : ""}</span></li>`)}</ul></details>` : null}
|
|
163
|
+
<button type="button" class="btn btn-sm oe-pack-refresh" onClick=${() => { void load(); }}>${te("refresh")}</button>
|
|
164
|
+
${msg ? html`<p class="note oe-pack-msg" role="status">${msg}</p>` : null}
|
|
165
|
+
</fieldset>`;
|
|
166
|
+
}
|
|
167
|
+
|
|
116
168
|
/** A new office's id: unique among `taken`, the store's pattern ([A-Za-z0-9_-], never "auto"). */
|
|
117
169
|
export function newOfficeId(taken, rand = Math.random) {
|
|
118
170
|
for (;;) {
|
|
@@ -147,8 +199,11 @@ export function OfficeEditor({ offices, rev, view, store, packs = [], ask = () =
|
|
|
147
199
|
// the rev under an older draft (a save would then overwrite what it never showed). After a 409 the person chooses
|
|
148
200
|
// (#2431): keep their edits (on the newer rev: Save then replaces what was saved meanwhile, knowingly) or load the
|
|
149
201
|
// newer list — never their draft thrown away unasked.
|
|
150
|
-
|
|
202
|
+
// `saved`: the list the draft is measured against (as read, or the newer one loaded) — the draft holds changes when
|
|
203
|
+
// it differs (#2585: leaving the page beside the docked editor then asks first).
|
|
204
|
+
const [base, setBase] = useState(() => ({ rev, saved: JSON.stringify(offices), draft: offices.map((o) => ({ ...o, members: [...o.members] })) }));
|
|
151
205
|
const draft = base.draft;
|
|
206
|
+
const dirty = JSON.stringify(draft) !== base.saved;
|
|
152
207
|
const setDraft = (next) => setBase((b) => ({ ...b, draft: typeof next === "function" ? next(b.draft) : next }));
|
|
153
208
|
const [open, setOpen] = useState(null); // the office whose members are shown
|
|
154
209
|
const [busy, setBusy] = useState(false);
|
|
@@ -157,14 +212,14 @@ export function OfficeEditor({ offices, rev, view, store, packs = [], ask = () =
|
|
|
157
212
|
const copy = (list) => list.map((o) => ({ ...o, members: [...o.members] }));
|
|
158
213
|
// The choice takes the snapshot in force when it is made: the stream may have read a newer one since the 409 (#2449).
|
|
159
214
|
const inForce = () => current() || conflict;
|
|
160
|
-
const keepMine = () => { const now = inForce(); setBase((b) => ({ rev: now.rev, draft: b.draft })); setConflict(null); setMsg(te("keptMine")); };
|
|
161
|
-
const loadTheirs = () => { const now = inForce(); setBase({ rev: now.rev, draft: copy(now.offices) }); setOpen(null); setConflict(null); setMsg(""); };
|
|
215
|
+
const keepMine = () => { const now = inForce(); setBase((b) => ({ rev: now.rev, saved: JSON.stringify(now.offices), draft: b.draft })); setConflict(null); setMsg(te("keptMine")); };
|
|
216
|
+
const loadTheirs = () => { const now = inForce(); setBase({ rev: now.rev, saved: JSON.stringify(now.offices), draft: copy(now.offices) }); setOpen(null); setConflict(null); setMsg(""); };
|
|
162
217
|
const everyone = useMemo(() => { const m = new Map(); for (const n of [...view.top, ...view.teams.flatMap((tm) => tm.nodes), ...view.rest.nodes]) if (!m.has(n.name)) m.set(n.name, n); return [...m.values()]; }, [view]);
|
|
163
218
|
const set = (id, patch) => setDraft((d) => d.map((o) => (o.id === id ? { ...o, ...patch } : o)));
|
|
164
219
|
const add = () => {
|
|
165
220
|
if (draft.length >= MAX_OFFICES) return;
|
|
166
221
|
const id = newOfficeId(new Set(draft.map((o) => o.id)));
|
|
167
|
-
setDraft((d) => [...d, { id, name: te("newName"), skin: "
|
|
222
|
+
setDraft((d) => [...d, { id, name: te("newName"), skin: "cozy", members: [], layout: null }]); // #2631: a new office is cozy
|
|
168
223
|
setOpen(id);
|
|
169
224
|
};
|
|
170
225
|
// Everything is frozen from Save until its answer (and a 409's re-read) is in (#2424 review): no edit made meanwhile
|
|
@@ -191,7 +246,8 @@ export function OfficeEditor({ offices, rev, view, store, packs = [], ask = () =
|
|
|
191
246
|
};
|
|
192
247
|
const actions = html`<button type="button" class="btn" onClick=${onClose} disabled=${busy}>${te("cancel")}</button>
|
|
193
248
|
<button type="button" class="btn btn-primary" id="oeSave" onClick=${save} disabled=${busy || !!conflict}>${te("save")}</button>`;
|
|
194
|
-
|
|
249
|
+
// #2585: docked on the right on a wide desk (the page beside it in use); the centred dialog elsewhere.
|
|
250
|
+
return html`<${SidePanel} title=${te("title")} onClose=${onClose} actions=${actions} busy=${busy} dirty=${dirty}>
|
|
195
251
|
<p class="note">${te("lead")}</p>
|
|
196
252
|
<fieldset class="oe-form" disabled=${busy}>
|
|
197
253
|
${draft.length ? null : html`<p class="note" id="oeNone">${te("none")}</p>`}
|
|
@@ -201,7 +257,7 @@ export function OfficeEditor({ offices, rev, view, store, packs = [], ask = () =
|
|
|
201
257
|
<input type="text" class="oe-name" maxlength="60" value=${o.name} onInput=${(e) => set(o.id, { name: e.target.value })} /></label>
|
|
202
258
|
<label class="oe-field"><span class="oe-label">${te("styleLabel")}</span>
|
|
203
259
|
<select class="tb-select oe-style" value=${o.skin} onChange=${(e) => set(o.id, { skin: e.target.value })}>
|
|
204
|
-
${STYLES.map((s) => html`<option key=${s} value=${s}>${t(`orgo.style_${s}`)}</option>`)}
|
|
260
|
+
${STYLES.filter((s) => !packs.some((pk) => pk.id === s)).map((s) => html`<option key=${s} value=${s}>${t(`orgo.style_${s}`)}</option>`)}
|
|
205
261
|
${packs.map((pk) => html`<option key=${`pack:${pk.id}`} value=${pk.id}>${pk.name}</option>`)}
|
|
206
262
|
${STYLES.includes(o.skin) || packs.some((pk) => pk.id === o.skin) ? null : html`<option key=${o.skin} value=${o.skin}>${te("styleUnknown", o.skin)}</option>`}</select></label>
|
|
207
263
|
<button type="button" class="btn btn-sm oe-members-btn" aria-expanded=${open === o.id ? "true" : "false"} onClick=${() => setOpen(open === o.id ? null : o.id)}>
|
|
@@ -216,9 +272,10 @@ export function OfficeEditor({ offices, rev, view, store, packs = [], ask = () =
|
|
|
216
272
|
</fieldset>
|
|
217
273
|
${msg ? html`<p class="note oe-msg" role="status">${msg}</p>` : null}
|
|
218
274
|
${store.uploadSkin ? html`<${Packs} packs=${packs} store=${store} />` : null}
|
|
275
|
+
${store.packChanges ? html`<${PackAgents} packs=${packs} store=${store} />` : null}
|
|
219
276
|
${conflict ? html`<div class="oe-conflict">
|
|
220
277
|
<button type="button" class="btn btn-sm" id="oeKeepMine" onClick=${keepMine} disabled=${busy}>${te("keepMine")}</button>
|
|
221
278
|
<button type="button" class="btn btn-sm" id="oeLoadTheirs" onClick=${loadTheirs} disabled=${busy}>${te("loadTheirs")}</button>
|
|
222
279
|
</div>` : null}
|
|
223
|
-
</${
|
|
280
|
+
</${SidePanel}>`;
|
|
224
281
|
}
|