sh3-core 0.13.2 → 0.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/actions/MenuButton.svelte +2 -1
  2. package/dist/actions/contextMenuModel.d.ts +1 -1
  3. package/dist/actions/contextMenuModel.js +2 -1
  4. package/dist/actions/dispatcher.svelte.d.ts +1 -1
  5. package/dist/actions/dispatcher.svelte.js +2 -1
  6. package/dist/actions/listActive.d.ts +1 -1
  7. package/dist/actions/listActive.js +2 -1
  8. package/dist/actions/listeners.d.ts +1 -1
  9. package/dist/actions/listeners.js +6 -5
  10. package/dist/actions/menuBarModel.js +3 -2
  11. package/dist/actions/paletteModel.js +2 -1
  12. package/dist/actions/resolveLabel.test.d.ts +1 -0
  13. package/dist/actions/resolveLabel.test.js +14 -0
  14. package/dist/actions/types.d.ts +12 -1
  15. package/dist/actions/types.js +7 -1
  16. package/dist/app/store/AppUpdateAvailableModal.svelte +87 -0
  17. package/dist/app/store/AppUpdateAvailableModal.svelte.d.ts +11 -0
  18. package/dist/app/store/InstalledView.svelte +8 -54
  19. package/dist/app/store/UninstallAppDialog.svelte +86 -0
  20. package/dist/app/store/UninstallAppDialog.svelte.d.ts +10 -0
  21. package/dist/app/store/permissionConfirm.d.ts +4 -0
  22. package/dist/app/store/permissionConfirm.js +28 -0
  23. package/dist/app/store/storeShard.svelte.d.ts +8 -1
  24. package/dist/app/store/storeShard.svelte.js +42 -9
  25. package/dist/app/store/updatePackage.test.d.ts +1 -0
  26. package/dist/app/store/updatePackage.test.js +34 -0
  27. package/dist/app/store/verbs.d.ts +1 -0
  28. package/dist/app/store/verbs.js +79 -5
  29. package/dist/app/store/verbs.test.d.ts +1 -0
  30. package/dist/app/store/verbs.test.js +56 -0
  31. package/dist/app-appearance/AppAppearanceModal.svelte +174 -0
  32. package/dist/app-appearance/AppAppearanceModal.svelte.d.ts +8 -0
  33. package/dist/app-appearance/appearanceShard.svelte.d.ts +2 -0
  34. package/dist/app-appearance/appearanceShard.svelte.js +61 -0
  35. package/dist/app-appearance/appearanceState.svelte.d.ts +15 -0
  36. package/dist/app-appearance/appearanceState.svelte.js +59 -0
  37. package/dist/app-appearance/appearanceState.test.d.ts +1 -0
  38. package/dist/app-appearance/appearanceState.test.js +30 -0
  39. package/dist/app-appearance/index.d.ts +3 -0
  40. package/dist/app-appearance/index.js +2 -0
  41. package/dist/app-appearance/types.d.ts +11 -0
  42. package/dist/app-appearance/types.js +1 -0
  43. package/dist/apps/types.d.ts +7 -0
  44. package/dist/assets/iconIds.generated.d.ts +2 -0
  45. package/dist/assets/iconIds.generated.js +154 -0
  46. package/dist/host.js +2 -1
  47. package/dist/primitives/widgets/IconPicker.svelte +115 -0
  48. package/dist/primitives/widgets/IconPicker.svelte.d.ts +9 -0
  49. package/dist/primitives/widgets/IconPicker.svelte.test.d.ts +1 -0
  50. package/dist/primitives/widgets/IconPicker.svelte.test.js +43 -0
  51. package/dist/projects-shard/ProjectManage.svelte +14 -4
  52. package/dist/sh3core-shard/ShellHome.svelte +64 -38
  53. package/dist/sh3core-shard/appActions.d.ts +13 -0
  54. package/dist/sh3core-shard/appActions.js +181 -0
  55. package/dist/sh3core-shard/appActions.test.d.ts +1 -0
  56. package/dist/sh3core-shard/appActions.test.js +25 -0
  57. package/dist/sh3core-shard/sh3coreShard.svelte.js +2 -0
  58. package/dist/version.d.ts +1 -1
  59. package/dist/version.js +1 -1
  60. package/package.json +2 -2
@@ -0,0 +1,181 @@
1
+ /*
2
+ * Element-scope actions for app cards. Wired by sh3coreShard.activate.
3
+ * The element scope is { element: 'app' } and activates when right-click
4
+ * on a host with data-sh3-scope="element:app" sets a selection of type
5
+ * 'app' (see ShellHome.svelte).
6
+ *
7
+ * Three actions are registered here:
8
+ * - app.info : info-only row showing "<id> v<version>" (always disabled).
9
+ * - app.checkUpdate : refresh catalog, then prompt update or toast up-to-date.
10
+ * - app.uninstall : open uninstall confirm dialog.
11
+ *
12
+ * The fourth menu item (app.customize) is registered by the app-appearance
13
+ * shard so its lifecycle is bound to that shard's activate/deactivate.
14
+ *
15
+ * Disabled predicate: !isAdmin || isBuiltin. Built-in means the app id is
16
+ * NOT in storeContext.state.ephemeral.installed (those are framework-shipped
17
+ * shards like sh3-store, sh3-shell, projects, etc.).
18
+ */
19
+ import { listRegisteredApps } from '../api';
20
+ import { isAdmin } from '../auth/auth.svelte';
21
+ import { getSelection } from '../actions/selection.svelte';
22
+ import { storeContext } from '../app/store/storeShard.svelte';
23
+ import { openPermissionConfirmModal } from '../app/store/permissionConfirm';
24
+ import { modalManager } from '../overlays/modal';
25
+ import { toastManager } from '../overlays/toast';
26
+ import AppUpdateAvailableModal from '../app/store/AppUpdateAvailableModal.svelte';
27
+ import UninstallAppDialog from '../app/store/UninstallAppDialog.svelte';
28
+ export function computeAppActionDisabled(g) {
29
+ return !g.admin || g.builtin;
30
+ }
31
+ export function computeAppActionLabelSuffix(g) {
32
+ if (!g.admin)
33
+ return ' · admin only';
34
+ if (g.builtin)
35
+ return ' · built-in';
36
+ return '';
37
+ }
38
+ function readSelection() {
39
+ const sel = getSelection();
40
+ if (!sel || sel.type !== 'app')
41
+ return null;
42
+ return sel.ref;
43
+ }
44
+ function findApp(appId) {
45
+ return listRegisteredApps().find((m) => m.id === appId);
46
+ }
47
+ function isBuiltin(appId) {
48
+ return !storeContext.state.ephemeral.installed.some((p) => p.id === appId);
49
+ }
50
+ function gateFor(appId) {
51
+ return { admin: isAdmin(), builtin: isBuiltin(appId) };
52
+ }
53
+ async function runCheckUpdate(_ctx) {
54
+ var _a, _b;
55
+ const ref = readSelection();
56
+ if (!ref)
57
+ return;
58
+ const { appId } = ref;
59
+ const checking = toastManager.notify('Checking for updates…', { duration: Infinity });
60
+ try {
61
+ await storeContext.refreshCatalog();
62
+ }
63
+ finally {
64
+ checking.close();
65
+ }
66
+ const entry = storeContext.state.ephemeral.updatable[appId];
67
+ const installed = storeContext.state.ephemeral.installed.find((p) => p.id === appId);
68
+ const label = (_b = (_a = findApp(appId)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : appId;
69
+ if (!entry || !installed) {
70
+ toastManager.notify(`${label} is up to date`, { level: 'info', duration: 2500 });
71
+ return;
72
+ }
73
+ const props = {
74
+ appId,
75
+ appLabel: label,
76
+ fromVersion: installed.version,
77
+ toVersion: entry.latest.version,
78
+ onConfirm: async () => {
79
+ try {
80
+ await storeContext.updatePackage(appId, (added, removed) => openPermissionConfirmModal({ label: installed.id, version: installed.version }, entry.latest.version, added, removed));
81
+ toastManager.notify(`Updated to v${entry.latest.version}`, { level: 'success' });
82
+ }
83
+ catch (e) {
84
+ toastManager.notify(`Update failed: ${e.message}`, { level: 'error', duration: 5000 });
85
+ throw e;
86
+ }
87
+ },
88
+ };
89
+ modalManager.open(AppUpdateAvailableModal, props);
90
+ }
91
+ function runUninstall(_ctx) {
92
+ var _a, _b;
93
+ const ref = readSelection();
94
+ if (!ref)
95
+ return;
96
+ const { appId } = ref;
97
+ const installed = storeContext.state.ephemeral.installed.find((p) => p.id === appId);
98
+ if (!installed)
99
+ return;
100
+ const label = (_b = (_a = findApp(appId)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : appId;
101
+ const props = {
102
+ appId,
103
+ appLabel: label,
104
+ version: installed.version,
105
+ onConfirm: async () => {
106
+ try {
107
+ await storeContext.uninstallPackage(appId);
108
+ toastManager.notify(`Uninstalled ${label}`, { level: 'success' });
109
+ }
110
+ catch (e) {
111
+ toastManager.notify(`Uninstall failed: ${e.message}`, { level: 'error', duration: 5000 });
112
+ throw e;
113
+ }
114
+ },
115
+ };
116
+ modalManager.open(UninstallAppDialog, props);
117
+ }
118
+ /**
119
+ * Register the three element-scope app actions on the given shard context.
120
+ * Returns a disposer that unregisters all three (the framework expects the
121
+ * shard's activate to keep the disposers alive across deactivate).
122
+ */
123
+ export function registerAppActions(ctx) {
124
+ const infoLabel = () => {
125
+ const ref = readSelection();
126
+ if (!ref)
127
+ return '';
128
+ const m = findApp(ref.appId);
129
+ if (!m)
130
+ return ref.appId;
131
+ return `${m.id} v${m.version}`;
132
+ };
133
+ const updateLabel = () => {
134
+ const ref = readSelection();
135
+ if (!ref)
136
+ return 'Check for updates';
137
+ return `Check for updates${computeAppActionLabelSuffix(gateFor(ref.appId))}`;
138
+ };
139
+ const uninstallLabel = () => {
140
+ const ref = readSelection();
141
+ if (!ref)
142
+ return 'Uninstall…';
143
+ return `Uninstall…${computeAppActionLabelSuffix(gateFor(ref.appId))}`;
144
+ };
145
+ const isDisabledForCurrent = () => {
146
+ const ref = readSelection();
147
+ if (!ref)
148
+ return true;
149
+ return computeAppActionDisabled(gateFor(ref.appId));
150
+ };
151
+ const actions = [
152
+ {
153
+ id: 'app.info',
154
+ label: infoLabel,
155
+ scope: { element: 'app' },
156
+ contextItem: true,
157
+ group: 'info',
158
+ disabled: true,
159
+ },
160
+ {
161
+ id: 'app.checkUpdate',
162
+ label: updateLabel,
163
+ scope: { element: 'app' },
164
+ contextItem: true,
165
+ group: 'update',
166
+ disabled: isDisabledForCurrent,
167
+ run: runCheckUpdate,
168
+ },
169
+ {
170
+ id: 'app.uninstall',
171
+ label: uninstallLabel,
172
+ scope: { element: 'app' },
173
+ contextItem: true,
174
+ group: 'uninstall',
175
+ disabled: isDisabledForCurrent,
176
+ run: runUninstall,
177
+ },
178
+ ];
179
+ const disposers = actions.map((a) => ctx.actions.register(a));
180
+ return () => disposers.forEach((d) => d());
181
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { computeAppActionDisabled, computeAppActionLabelSuffix } from './appActions';
3
+ describe('computeAppActionDisabled', () => {
4
+ it('disables when not admin', () => {
5
+ expect(computeAppActionDisabled({ admin: false, builtin: false })).toBe(true);
6
+ });
7
+ it('disables when builtin even for admin', () => {
8
+ expect(computeAppActionDisabled({ admin: true, builtin: true })).toBe(true);
9
+ });
10
+ it('enables for admin + non-builtin', () => {
11
+ expect(computeAppActionDisabled({ admin: true, builtin: false })).toBe(false);
12
+ });
13
+ });
14
+ describe('computeAppActionLabelSuffix', () => {
15
+ it('returns admin-only suffix when not admin', () => {
16
+ expect(computeAppActionLabelSuffix({ admin: false, builtin: true })).toBe(' · admin only');
17
+ expect(computeAppActionLabelSuffix({ admin: false, builtin: false })).toBe(' · admin only');
18
+ });
19
+ it('returns built-in suffix when admin + builtin', () => {
20
+ expect(computeAppActionLabelSuffix({ admin: true, builtin: true })).toBe(' · built-in');
21
+ });
22
+ it('returns empty when enabled', () => {
23
+ expect(computeAppActionLabelSuffix({ admin: true, builtin: false })).toBe('');
24
+ });
25
+ });
@@ -31,6 +31,7 @@ import { registeredApps } from '../apps/registry.svelte';
31
31
  import { launchApp } from '../apps/lifecycle';
32
32
  import { resetActivePresetToDefault } from '../layout/store.svelte';
33
33
  import { modalManager } from '../overlays/modal';
34
+ import { registerAppActions } from './appActions';
34
35
  export const sh3coreShard = {
35
36
  manifest: {
36
37
  id: '__sh3core__',
@@ -96,6 +97,7 @@ export const sh3coreShard = {
96
97
  };
97
98
  ctx.registerView('sh3core:home', factory);
98
99
  ctx.registerView('shell:keys-and-peers', keysFactory);
100
+ registerAppActions(ctx);
99
101
  // Launcher parent — submenu drill host. No `run` needed: the
100
102
  // dispatcher's default behavior opens a sub-palette filtered to
101
103
  // `submenuOf === 'sh3.app.launch'`. The single parent replaces the
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Auto-generated from package.json — do not edit manually. */
2
- export declare const VERSION = "0.13.2";
2
+ export declare const VERSION = "0.13.3";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Auto-generated from package.json — do not edit manually. */
2
- export const VERSION = '0.13.2';
2
+ export const VERSION = '0.13.3';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh3-core",
3
- "version": "0.13.2",
3
+ "version": "0.13.3",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -29,7 +29,7 @@
29
29
  }
30
30
  },
31
31
  "scripts": {
32
- "build": "node --import tsx scripts/sync-version.ts && svelte-package -i src -o dist && node --import tsx scripts/generate-api-docs.ts",
32
+ "build": "node --import tsx scripts/sync-version.ts && node --import tsx scripts/sync-icon-ids.ts && svelte-package -i src -o dist && node --import tsx scripts/generate-api-docs.ts",
33
33
  "check": "svelte-check --tsconfig ./tsconfig.json",
34
34
  "pack": "npm run build && npm pack",
35
35
  "test": "vitest run --passWithNoTests",