mirror of
https://github.com/anywhere-labs/dsh-desktop.git
synced 2026-09-28 05:03:17 +08:00
224 lines
11 KiB
Diff
224 lines
11 KiB
Diff
diff --git a/lib/client.js b/lib/client.js
|
|
index 31ae9a6..3c2ee39 100644
|
|
--- a/lib/client.js
|
|
+++ b/lib/client.js
|
|
@@ -28,6 +28,8 @@ window.__ModuleLoader__.load({
|
|
return `${bundle}#${rowId}`;
|
|
}
|
|
const SLOTS = [
|
|
+ "plugins.bundle.hidden",
|
|
+ "plugins.item.hidden",
|
|
"plugins.item",
|
|
"plugins.bundle.config",
|
|
"plugins.row.config"
|
|
@@ -42,6 +44,8 @@ window.__ModuleLoader__.load({
|
|
let revision = -1;
|
|
let ledger = {
|
|
items: [],
|
|
+ hiddenBundles: new Set(),
|
|
+ hiddenItems: new Set(),
|
|
bundles: /* @__PURE__ */ new Set(),
|
|
rows: /* @__PURE__ */ new Set()
|
|
};
|
|
@@ -59,6 +63,8 @@ window.__ModuleLoader__.load({
|
|
id: entry.options.id ?? "",
|
|
label: (0, _deepseek_ai_dsh_client_ui_slots.resolveSlotLabel)(entry.options.label) ?? ""
|
|
})),
|
|
+ hiddenBundles: keysOf("plugins.bundle.hidden"),
|
|
+ hiddenItems: keysOf("plugins.item.hidden"),
|
|
bundles: keysOf("plugins.bundle.config"),
|
|
rows: keysOf("plugins.row.config")
|
|
};
|
|
@@ -1589,9 +1595,15 @@ window.__ModuleLoader__.load({
|
|
]
|
|
});
|
|
}
|
|
+ /** Sidebar control in native window chrome, independent of the scrolling page header. */
|
|
+ function PluginSidebarControl({ renderSlot }) {
|
|
+ if (!(0, _deepseek_ai_dsh_client_ui_primitives.isDarwinDesktop)()) return null;
|
|
+ return (0, react_jsx_runtime.jsx)("div", { "data-plugin-sidebar-control": "", children: renderSlot("plugins.header.leading", {}) });
|
|
+ }
|
|
/** The top every page shares: the crumb that leads back, then the icon with the page's actions at its right. */
|
|
function DetailTop({ crumbLabel, crumbText, onBack, icon, actions }) {
|
|
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
+ "data-plugin-page-header": "detail",
|
|
type: "button",
|
|
className: PluginManagerPage_module_css_default.crumb,
|
|
"aria-label": crumbLabel,
|
|
@@ -1610,7 +1622,7 @@ window.__ModuleLoader__.load({
|
|
})] });
|
|
}
|
|
/** One package as a card that opens its page: its name, its one-liner, its tags, and its bundle switch. */
|
|
- function PackageCard({ pkg, t, resolveText, busy, highlighted, onOpen, onSetEnabled }) {
|
|
+ function PackageCard({ pkg, t, resolveText, busy, highlighted, onOpen, onSetEnabled, renderSlot }) {
|
|
const { title, description, beta } = packageText(pkg, resolveText);
|
|
const status = packageStatus(pkg);
|
|
return (0, react_jsx_runtime.jsxs)("li", {
|
|
@@ -1633,13 +1645,15 @@ window.__ModuleLoader__.load({
|
|
children: t("statusProblem")
|
|
}) : null] }),
|
|
description,
|
|
- end: (0, react_jsx_runtime.jsx)(EnableSwitch, {
|
|
+ end: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
+ renderSlot("plugins.bundle.actions", { subject: { kind: "bundle", pkg: packageRef(pkg) } }, { entryKey: pkg.name }),
|
|
+ (0, react_jsx_runtime.jsx)(EnableSwitch, {
|
|
pkg,
|
|
title,
|
|
t,
|
|
busy,
|
|
onSetEnabled
|
|
- })
|
|
+ })] })
|
|
}), (0, react_jsx_runtime.jsx)(MetadataError, {
|
|
error: pkg.meta?.error,
|
|
t
|
|
@@ -2656,11 +2670,12 @@ window.__ModuleLoader__.load({
|
|
};
|
|
}, [highlight, clearHighlight]);
|
|
const noticeLine = state.notice === null ? null : noticeText(state.notice, t);
|
|
- const listed = state.packages.filter((pkg) => !BUILTIN_PROFILE_BUNDLES.has(pkg.name) && (pkg.installed || pkg.optional || pkg.error !== void 0));
|
|
+ const available = state.packages.filter((pkg) => !BUILTIN_PROFILE_BUNDLES.has(pkg.name) && (pkg.installed || pkg.optional || pkg.error !== void 0));
|
|
+ const listed = available.filter((pkg) => !ledger.hiddenBundles?.has(pkg.name));
|
|
const mine = listed.filter((pkg) => pkg.installed || !pkg.optional);
|
|
const official = listed.filter((pkg) => pkg.optional && !pkg.installed);
|
|
const loaded = state.status === "ready" || state.status === "error";
|
|
- const openPkg = view.kind === "package" || view.kind === "row" ? listed.find((pkg) => pkg.name === view.name) : void 0;
|
|
+ const openPkg = view.kind === "package" || view.kind === "row" ? available.find((pkg) => pkg.name === view.name) : void 0;
|
|
const openItem = view.kind === "item" ? ledger.items.find((item) => item.id === view.id) : void 0;
|
|
const openRow = view.kind === "row" && openPkg !== void 0 ? openPkg.rows.find((row) => row.rowId === view.rowId) : void 0;
|
|
const showsCards = openPkg === void 0 && openItem === void 0;
|
|
@@ -2681,6 +2696,7 @@ window.__ModuleLoader__.load({
|
|
});
|
|
const packageCard = (pkg) => (0, react_jsx_runtime.jsx)(PackageCard, {
|
|
pkg,
|
|
+ renderSlot,
|
|
t,
|
|
resolveText,
|
|
busy: state.busy.includes(pkg.name),
|
|
@@ -2697,7 +2713,7 @@ window.__ModuleLoader__.load({
|
|
props.setEnabled(pkg.name, enabled);
|
|
}
|
|
}, pkg.name);
|
|
- const officialCards = [...official.map(packageCard), ...ledger.items.map((item) => (0, react_jsx_runtime.jsx)(ItemCard, {
|
|
+ const officialCards = [...official.map(packageCard), ...ledger.items.filter((item) => !ledger.hiddenItems?.has(item.id)).map((item) => (0, react_jsx_runtime.jsx)(ItemCard, {
|
|
item,
|
|
t,
|
|
renderSlot,
|
|
@@ -2732,8 +2748,10 @@ window.__ModuleLoader__.load({
|
|
"data-plugin-panel": true,
|
|
"aria-busy": state.status === "loading",
|
|
children: [
|
|
+ (0, react_jsx_runtime.jsx)(PluginSidebarControl, { renderSlot }),
|
|
showsCards ? (0, react_jsx_runtime.jsxs)("header", {
|
|
className: PluginManagerPage_module_css_default.pageHead,
|
|
+ "data-plugin-page-header": "list",
|
|
children: [(0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)("h1", {
|
|
className: PluginManagerPage_module_css_default.pageTitle,
|
|
children: t("title")
|
|
@@ -2765,6 +2783,18 @@ window.__ModuleLoader__.load({
|
|
})]
|
|
})]
|
|
}) : null,
|
|
+ showsCards && loaded ? renderSlot("plugins.overview", {
|
|
+ onOpenBundle: (name) => {
|
|
+ if (!available.some((pkg) => pkg.name === name)) return;
|
|
+ setActivation(null);
|
|
+ setView({ kind: "package", name });
|
|
+ },
|
|
+ onOpenItem: (id) => {
|
|
+ if (!ledger.items.some((item) => item.id === id)) return;
|
|
+ setActivation(null);
|
|
+ setView({ kind: "item", id });
|
|
+ }
|
|
+ }) : null,
|
|
showsCards && state.status === "loading" ? (0, react_jsx_runtime.jsxs)("p", {
|
|
className: `${PluginManagerPage_module_css_default.status} ${PluginManagerPage_module_css_default.statusWithDot}`,
|
|
role: "status",
|
|
@@ -3349,6 +3379,11 @@ window.__ModuleLoader__.load({
|
|
locale: NS,
|
|
inject: () => controller.inject(configLedger, (text) => ctx.locale.resolveText(text)),
|
|
children: {
|
|
+ "plugins.header.leading": { kind: "single", scope: "root" },
|
|
+ "plugins.overview": { kind: "list", scope: "root" },
|
|
+ "plugins.bundle.hidden": { kind: "keyed", scope: "root" },
|
|
+ "plugins.item.hidden": { kind: "keyed", scope: "root" },
|
|
+ "plugins.bundle.actions": { kind: "keyed", scope: "root" },
|
|
"plugins.item": {
|
|
kind: "list",
|
|
scope: "root"
|
|
@@ -3396,4 +3431,4 @@ window.__ModuleLoader__.load({
|
|
}
|
|
});
|
|
|
|
-//# sourceMappingURL=client.js.map
|
|
\ No newline at end of file
|
|
+//# sourceMappingURL=client.js.map
|
|
diff --git a/lib/types/client/PluginManagerPage.d.ts b/lib/types/client/PluginManagerPage.d.ts
|
|
index d9e8e74..08042a4 100644
|
|
--- a/lib/types/client/PluginManagerPage.d.ts
|
|
+++ b/lib/types/client/PluginManagerPage.d.ts
|
|
@@ -12,7 +12,7 @@ import { type ReactNode } from 'react';
|
|
import type { InjectFace, PropsLocale, PropsRenderSlots, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
import { type PluginManagerFace } from './manager-store.ts';
|
|
/** Full component props assembled by the main slot renderer. */
|
|
-export type PluginManagerPageProps = PropsRuntime<'main'> & PropsLocale<'pluginManager'> & PropsRenderSlots<'plugins.item' | 'plugins.bundle.config' | 'plugins.row.config' | 'plugins.bundle.activation' | 'plugins.detail.actions' | 'plugins.detail.badge' | 'plugins.detail.section'> & InjectFace<PluginManagerFace>;
|
|
+export type PluginManagerPageProps = PropsRuntime<'main'> & PropsLocale<'pluginManager'> & PropsRenderSlots<'plugins.header.leading' | 'plugins.overview' | 'plugins.item' | 'plugins.bundle.actions' | 'plugins.bundle.config' | 'plugins.row.config' | 'plugins.bundle.activation' | 'plugins.detail.actions' | 'plugins.detail.badge' | 'plugins.detail.section'> & InjectFace<PluginManagerFace>;
|
|
/** Render the plugin manager: the official plugins and installed bundles, their pages, the install dialog, and the confirmation. */
|
|
export declare function PluginManagerPage(props: PluginManagerPageProps): ReactNode;
|
|
-//# sourceMappingURL=PluginManagerPage.d.ts.map
|
|
\ No newline at end of file
|
|
+//# sourceMappingURL=PluginManagerPage.d.ts.map
|
|
diff --git a/lib/types/client/config-ledger.d.ts b/lib/types/client/config-ledger.d.ts
|
|
index 3abc24e..8f49351 100644
|
|
--- a/lib/types/client/config-ledger.d.ts
|
|
+++ b/lib/types/client/config-ledger.d.ts
|
|
@@ -19,6 +19,8 @@ export interface OfficialItem {
|
|
*/
|
|
export interface ConfigLedger {
|
|
readonly items: readonly OfficialItem[];
|
|
+ readonly hiddenBundles?: ReadonlySet<string>;
|
|
+ readonly hiddenItems?: ReadonlySet<string>;
|
|
readonly bundles: ReadonlySet<string>;
|
|
readonly rows: ReadonlySet<string>;
|
|
}
|
|
@@ -35,4 +37,4 @@ export declare function rowConfigKey(bundle: string, rowId: string): string;
|
|
* @returns the ledger source; its snapshot changes only when a ledger or the locale does.
|
|
*/
|
|
export declare function configLedgerSource(ctx: ClientContext): HostObservable<ConfigLedger>;
|
|
-//# sourceMappingURL=config-ledger.d.ts.map
|
|
\ No newline at end of file
|
|
+//# sourceMappingURL=config-ledger.d.ts.map
|
|
diff --git a/lib/types/client/slot-contract.d.ts b/lib/types/client/slot-contract.d.ts
|
|
index f7ba8cc..de2bd3d 100644
|
|
--- a/lib/types/client/slot-contract.d.ts
|
|
+++ b/lib/types/client/slot-contract.d.ts
|
|
@@ -72,6 +72,21 @@ export interface PluginActivationOwnerProps {
|
|
}
|
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
interface SlotMap {
|
|
+ /** Native sidebar control, separate from the scrolling page header. */
|
|
+ 'plugins.header.leading': { kind: 'single'; scope: 'root'; };
|
|
+ /** Controls above the ordinary plugin cards. */
|
|
+ 'plugins.overview': { kind: 'list'; scope: 'root'; owner: {
|
|
+ /** Open the manager's existing bundle detail, including an overview-owned bundle. */
|
|
+ onOpenBundle(name: string): void;
|
|
+ /** Open a registered item's existing configuration detail. */
|
|
+ onOpenItem(id: string): void;
|
|
+ }; };
|
|
+ /** Bundle names managed by overview controls instead of ordinary cards. */
|
|
+ 'plugins.bundle.hidden': { kind: 'keyed'; scope: 'root'; };
|
|
+ /** Item ids presented by overview controls, omitted only from ordinary cards and counts. */
|
|
+ 'plugins.item.hidden': { kind: 'keyed'; scope: 'root'; };
|
|
+ /** Desktop-owned actions before a bundle card's switch, keyed by package name. */
|
|
+ 'plugins.bundle.actions': { kind: 'keyed'; scope: 'root'; owner: PluginDetailProps; };
|
|
/** Optional guidance after the user enables a bundle from the list, keyed by npm package name. */
|
|
'plugins.bundle.activation': {
|
|
kind: 'keyed';
|
|
@@ -153,4 +168,4 @@ export interface ConfigPageForm {
|
|
/** Submit all field edits together with the revision the editor read. */
|
|
readonly mutate: ConfigForm<Record<string, unknown>>['mutate'];
|
|
}
|
|
-//# sourceMappingURL=slot-contract.d.ts.map
|
|
\ No newline at end of file
|
|
+//# sourceMappingURL=slot-contract.d.ts.map
|