@peers-app/peers-ui 0.9.5 → 0.10.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.
@@ -1,41 +1,11 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
35
5
  Object.defineProperty(exports, "__esModule", { value: true });
36
6
  exports.AssistantDetails = void 0;
37
7
  const peers_sdk_1 = require("@peers-app/peers-sdk");
38
- const react_1 = __importStar(require("react"));
8
+ const react_1 = __importDefault(require("react"));
39
9
  const input_1 = require("../../components/input");
40
10
  const loading_indicator_1 = require("../../components/loading-indicator");
41
11
  const save_button_1 = require("../../components/save-button");
@@ -46,15 +16,13 @@ const assistant_config_1 = require("./assistant-config");
46
16
  const assistant_info_1 = require("./assistant-info");
47
17
  const assistant_tools_1 = require("./assistant-tools");
48
18
  const AssistantDetails = (props) => {
49
- const [isPrimaryAssistant] = (0, react_1.useState)(() => (0, peers_sdk_1.observable)(false));
19
+ const [userAssistantId] = (0, hooks_1.useObservable)(peers_sdk_1.userPrimaryAssistantVar);
20
+ const [groupAssistantId] = (0, hooks_1.useObservable)(peers_sdk_1.groupPrimaryAssistantVar);
50
21
  const assistant = (0, hooks_1.usePromise)((async () => {
51
22
  const assistant = await (0, peers_sdk_1.Assistants)().get(props.assistantId);
52
23
  if (!assistant) {
53
24
  return null;
54
25
  }
55
- const primaryAssistantId = (await (0, peers_sdk_1.getPrimaryAssistant)()).assistantId
56
- || peers_sdk_1.defaultAssistantId;
57
- isPrimaryAssistant(assistant.assistantId === primaryAssistantId);
58
26
  (0, tabs_state_1.updateActiveTabTitle)(assistant.name || "Assistant");
59
27
  return (0, peers_sdk_1.Assistants)().initDoc(assistant);
60
28
  }), undefined, [props.assistantId]);
@@ -77,7 +45,10 @@ const AssistantDetails = (props) => {
77
45
  react_1.default.createElement("div", { className: "" },
78
46
  react_1.default.createElement(save_button_1.SaveButton, { key: assistant.assistantId, doc: assistant }))),
79
47
  react_1.default.createElement(tabs_1.Tabs, { key: assistant.assistantId, tabs: [
80
- { name: 'Info', content: react_1.default.createElement(assistant_info_1.AssistantInfo, { assistant: assistant, isPrimaryAssistant: isPrimaryAssistant }) },
48
+ {
49
+ name: 'Info',
50
+ content: (react_1.default.createElement(assistant_info_1.AssistantInfo, { assistant: assistant, isPrimaryAssistant: userAssistantId === assistant.assistantId, isGroupPrimaryAssistant: groupAssistantId === assistant.assistantId, onSetPrimary: (checked) => (0, peers_sdk_1.userPrimaryAssistantVar)(checked ? assistant.assistantId : undefined), onSetGroupPrimary: (checked) => (0, peers_sdk_1.groupPrimaryAssistantVar)(checked ? assistant.assistantId : undefined) })),
51
+ },
81
52
  { name: 'Config', content: react_1.default.createElement(assistant_config_1.AssistantConfig, { assistant: assistant }) },
82
53
  { name: 'Tools', content: react_1.default.createElement(assistant_tools_1.AssistantTools, { assistant: assistant }), },
83
54
  ] })));
@@ -1,6 +1,11 @@
1
- import { IAssistant, IDoc, Observable } from "@peers-app/peers-sdk";
1
+ import { IAssistant, IDoc } from "@peers-app/peers-sdk";
2
2
  import React from "react";
3
- export declare const AssistantInfo: (props: {
3
+ interface AssistantInfoProps {
4
4
  assistant: IDoc<IAssistant>;
5
- isPrimaryAssistant: Observable<boolean>;
6
- }) => React.JSX.Element;
5
+ isPrimaryAssistant: boolean;
6
+ isGroupPrimaryAssistant: boolean;
7
+ onSetPrimary: (checked: boolean) => void;
8
+ onSetGroupPrimary: (checked: boolean) => void;
9
+ }
10
+ export declare const AssistantInfo: (props: AssistantInfoProps) => React.JSX.Element;
11
+ export {};
@@ -7,20 +7,17 @@ exports.AssistantInfo = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
8
  const input_1 = require("../../components/input");
9
9
  const editor_inline_1 = require("../../components/markdown-editor/editor-inline");
10
- const hooks_1 = require("../../hooks");
11
10
  const AssistantInfo = (props) => {
12
- const { assistant, isPrimaryAssistant } = props;
13
- (0, hooks_1.useObservable)(isPrimaryAssistant);
11
+ const { assistant, isPrimaryAssistant, isGroupPrimaryAssistant, onSetPrimary, onSetGroupPrimary } = props;
14
12
  return (react_1.default.createElement("div", null,
15
13
  react_1.default.createElement("small", null, "Name:"),
16
14
  react_1.default.createElement(input_1.Input, { value: assistant.qs.name, className: "form-control mb-3 p-0 ps-2", placeholder: "Tool name", title: "Tool name" }),
17
15
  react_1.default.createElement("div", null,
18
- react_1.default.createElement("label", { htmlFor: "isPrimary", className: "form-label small mt-2 me-2" }, "Primary Assistant:"),
19
- react_1.default.createElement("input", { type: "checkbox", checked: isPrimaryAssistant(), onChange: (e) => {
20
- const checked = e.target.checked;
21
- isPrimaryAssistant(checked);
22
- assistant.q(assistant.q() + 1);
23
- } })),
16
+ react_1.default.createElement("label", { htmlFor: "isPrimary", className: "form-label small mt-2 me-2" }, "My Default Assistant:"),
17
+ react_1.default.createElement("input", { type: "checkbox", id: "isPrimary", checked: isPrimaryAssistant, onChange: (e) => onSetPrimary(e.target.checked) })),
18
+ react_1.default.createElement("div", null,
19
+ react_1.default.createElement("label", { htmlFor: "isGroupPrimary", className: "form-label small mt-2 me-2" }, "Group Default Assistant:"),
20
+ react_1.default.createElement("input", { type: "checkbox", id: "isGroupPrimary", checked: isGroupPrimaryAssistant, onChange: (e) => onSetGroupPrimary(e.target.checked) })),
24
21
  react_1.default.createElement("div", { className: 'mt-2' },
25
22
  react_1.default.createElement("small", null, "Description:"),
26
23
  react_1.default.createElement(editor_inline_1.MarkdownEditorInline, { value: assistant.qs.description }))));
@@ -10,11 +10,13 @@ const loading_indicator_1 = require("../../components/loading-indicator");
10
10
  const save_button_1 = require("../../components/save-button");
11
11
  const tabs_1 = require("../../components/tabs");
12
12
  const package_info_1 = require("./package-info");
13
+ const package_versions_1 = require("./package-versions");
13
14
  const hooks_1 = require("../../hooks");
14
15
  const input_1 = require("../../components/input");
15
16
  const tabs_state_1 = require("../../tabs-layout/tabs-state");
16
17
  const PackageDetails = (props) => {
17
18
  const refresh = (0, hooks_1.useObservableState)(Date.now());
19
+ const saveDeviceTagRef = react_1.default.useRef(null);
18
20
  const pkg = (0, hooks_1.usePromise)(async () => {
19
21
  const pkg = await (0, peers_sdk_1.Packages)().get(props.packageId);
20
22
  if (!pkg) {
@@ -62,13 +64,20 @@ const PackageDetails = (props) => {
62
64
  react_1.default.createElement("h4", null,
63
65
  react_1.default.createElement(input_1.Input, { key: pkg.packageId, className: 'border border-0', style: { width: '100%', outline: 'none', backgroundColor: 'transparent' }, value: pkg.qs.name }))),
64
66
  react_1.default.createElement("div", null,
65
- react_1.default.createElement(save_button_1.SaveButton, { key: pkg.packageId, doc: pkg, addActions: [
67
+ react_1.default.createElement(save_button_1.SaveButton, { key: pkg.packageId, doc: pkg, onClick: async () => {
68
+ await pkg.save();
69
+ await saveDeviceTagRef.current?.();
70
+ }, addActions: [
66
71
  ...addActions
67
72
  ] }))),
68
73
  react_1.default.createElement(tabs_1.Tabs, { key: pkg.packageId, tabs: [
69
74
  {
70
75
  name: 'Info', content: react_1.default.createElement(tabs_1.ScreenTabBody, null,
71
- react_1.default.createElement(package_info_1.PackageInfo, { pkg: pkg }))
76
+ react_1.default.createElement(package_info_1.PackageInfo, { pkg: pkg, saveDeviceTagRef: saveDeviceTagRef }))
77
+ },
78
+ {
79
+ name: 'Versions', content: react_1.default.createElement(tabs_1.ScreenTabBody, null,
80
+ react_1.default.createElement(package_versions_1.PackageVersionsList, { pkg: pkg }))
72
81
  },
73
82
  {
74
83
  name: 'Components', content: react_1.default.createElement(tabs_1.ScreenTabBody, null, "TODO - show all of the different components in the package")
@@ -2,4 +2,5 @@ import React from "react";
2
2
  import { IDoc, IPackage } from "@peers-app/peers-sdk";
3
3
  export declare const PackageInfo: (props: {
4
4
  pkg: IDoc<IPackage>;
5
+ saveDeviceTagRef?: React.MutableRefObject<(() => Promise<void>) | null>;
5
6
  }) => React.JSX.Element;
@@ -9,8 +9,89 @@ const peers_sdk_1 = require("@peers-app/peers-sdk");
9
9
  const markdown_with_mentions_1 = require("../../components/markdown-with-mentions");
10
10
  const tooltip_1 = require("../../components/tooltip");
11
11
  const input_1 = require("../../components/input");
12
+ const hooks_1 = require("../../hooks");
13
+ const deviceVersionTagVar = (0, peers_sdk_1.groupDeviceVar)('deviceVersionTag');
12
14
  const PackageInfo = (props) => {
13
15
  const { pkg } = props;
16
+ const [activeVersionId] = (0, hooks_1.useObservable)(pkg.qs.activePackageVersionId);
17
+ const [versionFollowRange] = (0, hooks_1.useObservable)(pkg.qs.versionFollowRange);
18
+ const [followVersionTags] = (0, hooks_1.useObservable)(pkg.qs.followVersionTags);
19
+ const [deviceTag] = (0, hooks_1.useObservable)(deviceVersionTagVar);
20
+ const [deviceTagDraft, setDeviceTagDraft] = react_1.default.useState(deviceTag || '');
21
+ const savingRef = react_1.default.useRef(false);
22
+ react_1.default.useEffect(() => {
23
+ if (!savingRef.current) {
24
+ setDeviceTagDraft(deviceTag || '');
25
+ }
26
+ }, [deviceTag]);
27
+ const deviceTagDirty = deviceTagDraft.trim() !== (deviceTag || '');
28
+ const prevDirtyRef = react_1.default.useRef(false);
29
+ react_1.default.useEffect(() => {
30
+ if (deviceTagDirty && !prevDirtyRef.current) {
31
+ pkg.q((pkg.q() || 0) + 1);
32
+ }
33
+ else if (!deviceTagDirty && prevDirtyRef.current) {
34
+ pkg.q(Math.max(0, (pkg.q() || 0) - 1));
35
+ }
36
+ prevDirtyRef.current = deviceTagDirty;
37
+ }, [deviceTagDirty]);
38
+ if (props.saveDeviceTagRef) {
39
+ props.saveDeviceTagRef.current = async () => {
40
+ const val = deviceTagDraft.trim();
41
+ if (val !== (deviceTag || '')) {
42
+ savingRef.current = true;
43
+ try {
44
+ if (val) {
45
+ deviceVersionTagVar(val);
46
+ }
47
+ else {
48
+ await deviceVersionTagVar.delete();
49
+ }
50
+ }
51
+ finally {
52
+ savingRef.current = false;
53
+ }
54
+ }
55
+ };
56
+ }
57
+ const activeVersion = (0, hooks_1.usePromise)(async () => {
58
+ if (!activeVersionId)
59
+ return null;
60
+ return (0, peers_sdk_1.PackageVersions)().get(activeVersionId);
61
+ }, undefined, [activeVersionId]);
62
+ const newerLevel = (0, hooks_1.usePromise)(async () => {
63
+ if (!activeVersionId)
64
+ return 'uptodate';
65
+ const all = await (0, peers_sdk_1.PackageVersions)().list({ packageId: pkg.packageId });
66
+ const active = all.find(v => v.packageVersionId === activeVersionId);
67
+ if (!active?.version)
68
+ return 'uptodate';
69
+ const parse = (v) => v.split('.').map(Number);
70
+ const [aMaj, aMin, aPat] = parse(active.version);
71
+ let highest = null;
72
+ for (const v of all) {
73
+ if (!v.version || v.packageVersionId === activeVersionId)
74
+ continue;
75
+ if (!(0, peers_sdk_1.doesTagMatch)(active.versionTag, v.versionTag, followVersionTags, deviceTag))
76
+ continue;
77
+ const [maj, min, pat] = parse(v.version);
78
+ if (maj > aMaj)
79
+ return 'major';
80
+ if (maj === aMaj && min > aMin) {
81
+ highest = 'minor';
82
+ continue;
83
+ }
84
+ if (maj === aMaj && min === aMin && pat > aPat && !highest) {
85
+ highest = 'patch';
86
+ continue;
87
+ }
88
+ if (maj === aMaj && min === aMin && pat === aPat && (v.createdAt || '') > (active.createdAt || '') && !highest) {
89
+ highest = 'patch';
90
+ }
91
+ }
92
+ return highest || 'uptodate';
93
+ }, undefined, [activeVersionId, pkg.packageId, followVersionTags, deviceTag]);
94
+ const isPinned = versionFollowRange === 'pinned';
14
95
  return (react_1.default.createElement("div", null,
15
96
  react_1.default.createElement("small", null, "Name:"),
16
97
  react_1.default.createElement(input_1.Input, { value: pkg.qs.name, className: "form-control mb-3 p-0 ps-2", placeholder: "Package name", title: "Package name", disabled: true }),
@@ -32,6 +113,46 @@ const PackageInfo = (props) => {
32
113
  peers_sdk_1.rpcServerCalls.openLinkInBrowser(pkg.remoteRepo);
33
114
  } }, "Open Remote"))),
34
115
  react_1.default.createElement(input_1.Input, { value: pkg.qs.remoteRepo, className: "form-control mb-3 p-0 ps-2", disabled: true }))),
116
+ react_1.default.createElement("div", { className: "mt-2" },
117
+ react_1.default.createElement("hr", null),
118
+ react_1.default.createElement("small", null,
119
+ "Version:",
120
+ react_1.default.createElement(tooltip_1.Tooltip, { markdownContent: "The currently active version of this package. Manage versions in the Versions tab." })),
121
+ activeVersion ? (react_1.default.createElement("div", { className: "d-flex align-items-center mt-1 mb-3" },
122
+ react_1.default.createElement("strong", { className: "me-2" },
123
+ "v",
124
+ activeVersion.version),
125
+ activeVersion.versionTag && (react_1.default.createElement("span", { className: `badge ${activeVersion.versionTag.startsWith('beta') ? 'text-bg-warning' : 'text-bg-info'} me-2` }, activeVersion.versionTag)),
126
+ react_1.default.createElement("code", { className: "text-muted small me-2" }, activeVersion.packageVersionHash?.substring(0, 8)),
127
+ newerLevel === 'uptodate' ? (react_1.default.createElement("span", { className: "badge text-bg-success" }, "Up to date")) : newerLevel ? (react_1.default.createElement("span", { className: `badge text-bg-${newerLevel === 'major' ? 'danger' : newerLevel === 'minor' ? 'warning' : 'info'}` },
128
+ "Newer ",
129
+ newerLevel,
130
+ " version available")) : null)) : (react_1.default.createElement("div", { className: "text-muted small mt-1 mb-3" }, "No active version")),
131
+ react_1.default.createElement("div", { className: "mb-3" },
132
+ react_1.default.createElement("small", null,
133
+ "Auto-Update Range:",
134
+ react_1.default.createElement(tooltip_1.Tooltip, { markdownContent: "Controls which new versions are auto-activated. **Pinned** = never auto-update. **Patch** = same major.minor (e.g. 1.2.x). **Minor** = same major (e.g. 1.x.x). **Latest** = always auto-update to newest." })),
135
+ react_1.default.createElement("select", { className: "form-select form-select-sm", value: versionFollowRange || 'latest', onChange: (e) => {
136
+ const val = e.target.value;
137
+ pkg.versionFollowRange = val === 'latest' ? undefined : val;
138
+ } },
139
+ react_1.default.createElement("option", { value: "latest" }, "Latest (auto-update to newest)"),
140
+ react_1.default.createElement("option", { value: "minor" }, "Minor (same major version)"),
141
+ react_1.default.createElement("option", { value: "patch" }, "Patch (same major.minor version)"),
142
+ react_1.default.createElement("option", { value: "pinned" }, "Pinned (no auto-updates)"))),
143
+ react_1.default.createElement("div", { className: `mb-3 ${isPinned ? 'opacity-50' : ''}` },
144
+ react_1.default.createElement("small", null,
145
+ "Follow Version Tags:",
146
+ react_1.default.createElement(tooltip_1.Tooltip, { markdownContent: "Which version tags to auto-activate. Leave empty for **current** (follows the active version's tag). Use `*` for any tag, or a comma-separated list like `stable,prod`." })),
147
+ react_1.default.createElement(input_1.Input, { value: pkg.qs.followVersionTags, className: "form-control form-control-sm p-0 ps-2", placeholder: `Following "${activeVersion?.versionTag || 'stable'}"`, disabled: isPinned })),
148
+ react_1.default.createElement("div", { className: "mb-2" },
149
+ react_1.default.createElement("small", null,
150
+ "Device-Specific Version Tag:",
151
+ react_1.default.createElement(tooltip_1.Tooltip, { markdownContent: "Override the tag policy for this device only. For example, set to `beta` to test pre-release versions on this device without affecting other devices or group members. This is not synced." })),
152
+ react_1.default.createElement("div", { className: "d-flex align-items-center gap-2" },
153
+ react_1.default.createElement("input", { type: "text", className: "form-control form-control-sm p-0 ps-2", placeholder: "e.g. beta", value: deviceTagDraft, onChange: (e) => setDeviceTagDraft(e.target.value) }),
154
+ deviceTagDraft && (react_1.default.createElement("button", { className: "btn btn-sm btn-outline-secondary", title: "Clear device tag override", onClick: () => setDeviceTagDraft('') },
155
+ react_1.default.createElement("i", { className: "bi bi-x-lg" })))))),
35
156
  react_1.default.createElement("div", { className: "mt-2" },
36
157
  react_1.default.createElement("hr", null),
37
158
  react_1.default.createElement("small", null,
@@ -43,6 +43,55 @@ const tooltip_1 = require("../../components/tooltip");
43
43
  const globals_1 = require("../../globals");
44
44
  const hooks_1 = require("../../hooks");
45
45
  const ui_loader_1 = require("../../ui-router/ui-loader");
46
+ const PackageVersionBadge = ({ activePackageVersionId, packageId, followVersionTags }) => {
47
+ const data = (0, hooks_1.usePromise)(async () => {
48
+ if (!activePackageVersionId)
49
+ return null;
50
+ const all = await (0, peers_sdk_1.PackageVersions)().list({ packageId });
51
+ const active = all.find(v => v.packageVersionId === activePackageVersionId);
52
+ if (!active)
53
+ return null;
54
+ let newerLevel = null;
55
+ if (active.version) {
56
+ const parse = (v) => v.split('.').map(Number);
57
+ const [aMaj, aMin, aPat] = parse(active.version);
58
+ for (const v of all) {
59
+ if (!v.version || v.packageVersionId === activePackageVersionId)
60
+ continue;
61
+ if (!(0, peers_sdk_1.doesTagMatch)(active.versionTag, v.versionTag, followVersionTags, undefined))
62
+ continue;
63
+ const [maj, min, pat] = parse(v.version);
64
+ if (maj > aMaj) {
65
+ newerLevel = 'major';
66
+ break;
67
+ }
68
+ if (maj === aMaj && min > aMin) {
69
+ newerLevel = 'minor';
70
+ continue;
71
+ }
72
+ if (maj === aMaj && min === aMin && pat > aPat && !newerLevel) {
73
+ newerLevel = 'patch';
74
+ continue;
75
+ }
76
+ if (maj === aMaj && min === aMin && pat === aPat && (v.createdAt || '') > (active.createdAt || '') && !newerLevel) {
77
+ newerLevel = 'patch';
78
+ }
79
+ }
80
+ }
81
+ return { pv: active, newerLevel };
82
+ }, undefined, [activePackageVersionId, packageId, followVersionTags]);
83
+ if (!data)
84
+ return null;
85
+ const { pv, newerLevel } = data;
86
+ return (react_1.default.createElement("span", { className: "ms-2" },
87
+ react_1.default.createElement("small", { className: "text-muted" },
88
+ "v",
89
+ pv.version),
90
+ pv.versionTag && (react_1.default.createElement("span", { className: `badge ms-1 ${pv.versionTag.startsWith('beta') ? 'text-bg-warning' : 'text-bg-info'}`, style: { fontSize: '0.65em' } }, pv.versionTag)),
91
+ newerLevel ? (react_1.default.createElement("span", { className: `badge ms-1 text-bg-${newerLevel === 'major' ? 'danger' : newerLevel === 'minor' ? 'warning' : 'info'}`, style: { fontSize: '0.65em' } },
92
+ newerLevel,
93
+ " update")) : (react_1.default.createElement("span", { className: "badge ms-1 text-bg-success", style: { fontSize: '0.65em' } }, "up to date"))));
94
+ };
46
95
  const PackageList = () => {
47
96
  const [searchTextObs] = (0, react_1.useState)(() => (0, peers_sdk_1.observable)(''));
48
97
  const [searchText] = (0, hooks_1.useObservable)(searchTextObs);
@@ -157,6 +206,7 @@ const PackageList = () => {
157
206
  react_1.default.createElement("i", { className: "bi bi-box-fill" }),
158
207
  "\u00A0\u00A0",
159
208
  react_1.default.createElement("a", { href: `#packages/${pkg.packageId}` }, pkg.name),
209
+ react_1.default.createElement(PackageVersionBadge, { activePackageVersionId: pkg.activePackageVersionId, packageId: pkg.packageId, followVersionTags: pkg.followVersionTags }),
160
210
  react_1.default.createElement(tooltip_1.Tooltip, { markdownContent: pkg.description, positions: ['bottom', 'top', 'right', 'left'] })));
161
211
  });
162
212
  }, loadingIndicator: react_1.default.createElement("div", { className: "d-flex justify-content-center", style: { height: 200 } },
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ import { IDoc, IPackage } from "@peers-app/peers-sdk";
3
+ export declare const PackageVersionsList: (props: {
4
+ pkg: IDoc<IPackage>;
5
+ }) => React.JSX.Element;
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.PackageVersionsList = void 0;
37
+ const react_1 = __importStar(require("react"));
38
+ const peers_sdk_1 = require("@peers-app/peers-sdk");
39
+ const hooks_1 = require("../../hooks");
40
+ function formatDate(iso) {
41
+ try {
42
+ const d = new Date(iso);
43
+ const now = new Date();
44
+ const diffMs = now.getTime() - d.getTime();
45
+ const diffMins = Math.floor(diffMs / 60000);
46
+ if (diffMins < 1)
47
+ return 'just now';
48
+ if (diffMins < 60)
49
+ return `${diffMins}m ago`;
50
+ const diffHours = Math.floor(diffMins / 60);
51
+ if (diffHours < 24)
52
+ return `${diffHours}h ago`;
53
+ const diffDays = Math.floor(diffHours / 24);
54
+ if (diffDays < 30)
55
+ return `${diffDays}d ago`;
56
+ return d.toLocaleDateString();
57
+ }
58
+ catch {
59
+ return iso;
60
+ }
61
+ }
62
+ function tagBadgeClass(tag) {
63
+ if (!tag)
64
+ return 'text-bg-secondary';
65
+ if (tag.startsWith('beta'))
66
+ return 'text-bg-warning';
67
+ if (tag === 'stable')
68
+ return 'text-bg-info';
69
+ return 'text-bg-secondary';
70
+ }
71
+ const PackageVersionsList = (props) => {
72
+ const { pkg } = props;
73
+ const [activeVersionId] = (0, hooks_1.useObservable)(pkg.qs.activePackageVersionId);
74
+ const [versionFollowRange] = (0, hooks_1.useObservable)(pkg.qs.versionFollowRange);
75
+ const refreshKey = (0, hooks_1.useObservableState)(0);
76
+ const [activating, setActivating] = (0, react_1.useState)(null);
77
+ const [deleting, setDeleting] = (0, react_1.useState)(null);
78
+ const [pinning, setPinning] = (0, react_1.useState)(false);
79
+ const isPinned = versionFollowRange === 'pinned';
80
+ const versions = (0, hooks_1.usePromise)(async () => {
81
+ const all = await (0, peers_sdk_1.PackageVersions)().list({ packageId: pkg.packageId });
82
+ const parse = (v) => v.split('.').map(Number);
83
+ const sorted = all.sort((a, b) => {
84
+ const [aMaj, aMin, aPat] = parse(a.version || '0.0.0');
85
+ const [bMaj, bMin, bPat] = parse(b.version || '0.0.0');
86
+ if (bMaj !== aMaj)
87
+ return bMaj - aMaj;
88
+ if (bMin !== aMin)
89
+ return bMin - aMin;
90
+ if (bPat !== aPat)
91
+ return bPat - aPat;
92
+ return (b.createdAt || '').localeCompare(a.createdAt || '');
93
+ });
94
+ const uniqueCreatorIds = [...new Set(sorted.map(pv => pv.createdBy).filter(Boolean))];
95
+ const userMap = new Map();
96
+ await Promise.all(uniqueCreatorIds.map(async (uid) => {
97
+ try {
98
+ const user = await (0, peers_sdk_1.Users)().get(uid, { useCache: true });
99
+ if (user?.name)
100
+ userMap.set(uid, user.name);
101
+ }
102
+ catch { }
103
+ }));
104
+ return { sorted, userMap };
105
+ }, undefined, [pkg.packageId, refreshKey()]);
106
+ async function activateVersion(pv) {
107
+ setActivating(pv.packageVersionId);
108
+ try {
109
+ const current = await (0, peers_sdk_1.Packages)().get(pkg.packageId);
110
+ if (current) {
111
+ current.activePackageVersionId = pv.packageVersionId;
112
+ await (0, peers_sdk_1.Packages)().signAndSave(current);
113
+ await pkg.load();
114
+ refreshKey(refreshKey() + 1);
115
+ }
116
+ }
117
+ catch (err) {
118
+ alert(`Failed to activate version: ${err}`);
119
+ }
120
+ finally {
121
+ setActivating(null);
122
+ }
123
+ }
124
+ async function deleteVersion(pv) {
125
+ if (!confirm(`Delete version v${pv.version} (${pv.packageVersionHash?.substring(0, 8)})?`))
126
+ return;
127
+ setDeleting(pv.packageVersionId);
128
+ try {
129
+ await (0, peers_sdk_1.PackageVersions)().delete(pv.packageVersionId);
130
+ refreshKey(refreshKey() + 1);
131
+ }
132
+ catch (err) {
133
+ alert(`Failed to delete version: ${err}`);
134
+ }
135
+ finally {
136
+ setDeleting(null);
137
+ }
138
+ }
139
+ async function pinVersion() {
140
+ setPinning(true);
141
+ try {
142
+ const current = await (0, peers_sdk_1.Packages)().get(pkg.packageId);
143
+ if (current) {
144
+ current.versionFollowRange = 'pinned';
145
+ await (0, peers_sdk_1.Packages)().signAndSave(current);
146
+ await pkg.load();
147
+ }
148
+ }
149
+ catch (err) {
150
+ alert(`Failed to pin version: ${err}`);
151
+ }
152
+ finally {
153
+ setPinning(false);
154
+ }
155
+ }
156
+ if (!versions) {
157
+ return react_1.default.createElement("div", { className: "text-center p-3" },
158
+ react_1.default.createElement("div", { className: "spinner-border spinner-border-sm" }));
159
+ }
160
+ const { sorted, userMap } = versions;
161
+ if (sorted.length === 0) {
162
+ return (react_1.default.createElement("div", { className: "text-muted text-center p-4" },
163
+ react_1.default.createElement("i", { className: "bi bi-tag me-1" }),
164
+ "No versions found for this package."));
165
+ }
166
+ return (react_1.default.createElement("div", null,
167
+ react_1.default.createElement("small", { className: "text-muted" },
168
+ sorted.length,
169
+ " version",
170
+ sorted.length !== 1 ? 's' : ''),
171
+ react_1.default.createElement("div", { className: "list-group mt-2" }, sorted.map(pv => {
172
+ const isActive = pv.packageVersionId === activeVersionId;
173
+ const creatorName = userMap.get(pv.createdBy);
174
+ return (react_1.default.createElement("div", { key: pv.packageVersionId, className: `list-group-item ${isActive ? 'list-group-item-success' : ''}` },
175
+ react_1.default.createElement("div", { className: "d-flex align-items-center justify-content-between" },
176
+ react_1.default.createElement("div", null,
177
+ react_1.default.createElement("strong", { className: "me-2" },
178
+ "v",
179
+ pv.version),
180
+ pv.versionTag && (react_1.default.createElement("span", { className: `badge ${tagBadgeClass(pv.versionTag)} me-2` }, pv.versionTag)),
181
+ react_1.default.createElement("code", { className: "text-muted small me-2" }, pv.packageVersionHash?.substring(0, 8)),
182
+ react_1.default.createElement("small", { className: "text-muted me-2" }, formatDate(pv.createdAt)),
183
+ creatorName && (react_1.default.createElement("small", { className: "text-muted" },
184
+ "by ",
185
+ creatorName))),
186
+ react_1.default.createElement("div", { className: "d-flex gap-1" },
187
+ isActive ? (react_1.default.createElement(react_1.default.Fragment, null,
188
+ react_1.default.createElement("button", { className: "btn btn-sm btn-outline-secondary", disabled: isPinned || pinning, onClick: () => pinVersion(), title: isPinned ? 'Already pinned' : 'Pin to this version (disable auto-updates)' },
189
+ pinning ? (react_1.default.createElement("span", { className: "spinner-border spinner-border-sm" })) : (react_1.default.createElement("i", { className: "bi bi-pin-fill" })),
190
+ isPinned ? ' Pinned' : ' Pin'),
191
+ react_1.default.createElement("span", { className: "badge text-bg-success align-self-center" }, "active"))) : (react_1.default.createElement("button", { className: "btn btn-sm btn-outline-primary", disabled: activating === pv.packageVersionId, onClick: () => activateVersion(pv) },
192
+ activating === pv.packageVersionId ? (react_1.default.createElement("span", { className: "spinner-border spinner-border-sm me-1" })) : (react_1.default.createElement("i", { className: "bi bi-check2-circle me-1" })),
193
+ "Activate")),
194
+ !isActive && (react_1.default.createElement("button", { className: "btn btn-sm btn-outline-danger", disabled: deleting === pv.packageVersionId, onClick: () => deleteVersion(pv) }, deleting === pv.packageVersionId ? (react_1.default.createElement("span", { className: "spinner-border spinner-border-sm" })) : (react_1.default.createElement("i", { className: "bi bi-trash" }))))))));
195
+ }))));
196
+ };
197
+ exports.PackageVersionsList = PackageVersionsList;
@@ -106,7 +106,4 @@ exports.systemPackage = {
106
106
  localPath: '',
107
107
  disabled: false,
108
108
  signature: '',
109
- packageBundleFileId: '',
110
- packageBundleFileHash: '',
111
- // System apps use existing router instead of separate bundle files
112
109
  };
@@ -6,19 +6,16 @@ export declare const allPackages: import("@peers-app/peers-sdk").Observable<{
6
6
  createdBy: string;
7
7
  packageId: string;
8
8
  localPath: string;
9
- packageBundleFileId: string;
10
- packageBundleFileHash: string;
11
9
  disabled?: boolean | undefined;
12
- remoteRepo?: string | undefined;
13
10
  appNavs?: {
14
11
  name: string;
15
12
  iconClassName: string;
16
13
  navigationPath: string;
17
14
  displayName?: string | undefined;
18
15
  }[] | undefined;
19
- routesBundleFileId?: string | undefined;
20
- routesBundleFileHash?: string | undefined;
21
- uiBundleFileId?: string | undefined;
22
- uiBundleFileHash?: string | undefined;
16
+ remoteRepo?: string | undefined;
17
+ activePackageVersionId?: string | undefined;
18
+ versionFollowRange?: "pinned" | "patch" | "minor" | "latest" | undefined;
19
+ followVersionTags?: string | undefined;
23
20
  }[]>;
24
21
  export declare const loadAllRoutes: () => Promise<true | undefined>;