@peers-app/peers-ui 0.27.2 → 0.27.4
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/dist/screens/network-viewer/network-viewer-ipc.d.ts +3 -1
- package/dist/screens/network-viewer/network-viewer-ipc.js +6 -0
- package/dist/screens/network-viewer/sync-recovery.js +103 -1
- package/dist/screens/variables/variable-details.js +2 -1
- package/dist/tabs-layout/network-status-indicator.js +26 -12
- package/dist/tabs-layout/use-network-status.d.ts +6 -1
- package/dist/tabs-layout/use-network-status.js +27 -4
- package/package.json +9 -3
- package/.claude/settings.local.json +0 -34
- package/.github/README.md +0 -52
- package/.github/workflows/delete-all-artifacts.yml +0 -49
- package/.github/workflows/publish.yml +0 -51
- package/babel.config.js +0 -7
- package/biome.json +0 -198
- package/dist/app-updates/app-updates-consumer.test.d.ts +0 -1
- package/dist/app-updates/app-updates-consumer.test.js +0 -56
- package/dist/app-updates/app-updates-settings.test.d.ts +0 -1
- package/dist/app-updates/app-updates-settings.test.js +0 -93
- package/dist/app-updates/remote-app-update-panel.test.d.ts +0 -1
- package/dist/app-updates/remote-app-update-panel.test.js +0 -165
- package/dist/components/access-level-field.test.d.ts +0 -1
- package/dist/components/access-level-field.test.js +0 -28
- package/dist/components/message-logs/tool-access-approval-card.test.d.ts +0 -1
- package/dist/components/message-logs/tool-access-approval-card.test.js +0 -102
- package/dist/components/responsive-section-nav.test.d.ts +0 -1
- package/dist/components/responsive-section-nav.test.js +0 -45
- package/dist/globals-hash.test.d.ts +0 -1
- package/dist/globals-hash.test.js +0 -16
- package/dist/hooks/use-observable-state.test.d.ts +0 -1
- package/dist/hooks/use-observable-state.test.js +0 -64
- package/dist/hooks/use-observable.test.d.ts +0 -1
- package/dist/hooks/use-observable.test.js +0 -191
- package/dist/hooks/use-rows.test.d.ts +0 -1
- package/dist/hooks/use-rows.test.js +0 -175
- package/dist/hooks/use-tool.test.d.ts +0 -1
- package/dist/hooks/use-tool.test.js +0 -190
- package/dist/host-shell/host-shell-consumer.test.d.ts +0 -1
- package/dist/host-shell/host-shell-consumer.test.js +0 -28
- package/dist/root-layout/root-layout-host.test.d.ts +0 -1
- package/dist/root-layout/root-layout-host.test.js +0 -86
- package/dist/screens/account/account-screen.test.d.ts +0 -1
- package/dist/screens/account/account-screen.test.js +0 -51
- package/dist/screens/assistants/assistant-config.test.d.ts +0 -1
- package/dist/screens/assistants/assistant-config.test.js +0 -57
- package/dist/screens/contacts/contact-list.test.d.ts +0 -1
- package/dist/screens/contacts/contact-list.test.js +0 -48
- package/dist/screens/device-pairing/device-pairing.test.d.ts +0 -1
- package/dist/screens/device-pairing/device-pairing.test.js +0 -119
- package/dist/screens/devices/devices-list.test.d.ts +0 -1
- package/dist/screens/devices/devices-list.test.js +0 -53
- package/dist/screens/groups/group-list.test.d.ts +0 -1
- package/dist/screens/groups/group-list.test.js +0 -38
- package/dist/screens/identity/identity-routes.test.d.ts +0 -1
- package/dist/screens/identity/identity-routes.test.js +0 -51
- package/dist/screens/identity/identity-screen.test.d.ts +0 -1
- package/dist/screens/identity/identity-screen.test.js +0 -103
- package/dist/screens/invites/accept-invite.test.d.ts +0 -1
- package/dist/screens/invites/accept-invite.test.js +0 -103
- package/dist/screens/invites/activity-view.test.d.ts +0 -1
- package/dist/screens/invites/activity-view.test.js +0 -108
- package/dist/screens/invites/invite-classify.test.d.ts +0 -1
- package/dist/screens/invites/invite-classify.test.js +0 -115
- package/dist/screens/network-viewer/network-viewer-ipc.test.d.ts +0 -1
- package/dist/screens/network-viewer/network-viewer-ipc.test.js +0 -61
- package/dist/screens/network-viewer/network-viewer.section.test.d.ts +0 -1
- package/dist/screens/network-viewer/network-viewer.section.test.js +0 -63
- package/dist/screens/network-viewer/sync-recovery.test.d.ts +0 -1
- package/dist/screens/network-viewer/sync-recovery.test.js +0 -104
- package/dist/screens/packages/package-helpers.test.d.ts +0 -1
- package/dist/screens/packages/package-helpers.test.js +0 -53
- package/dist/screens/packages/package-runtime-status.test.d.ts +0 -1
- package/dist/screens/packages/package-runtime-status.test.js +0 -50
- package/dist/screens/packages/packages-ipc.test.d.ts +0 -1
- package/dist/screens/packages/packages-ipc.test.js +0 -43
- package/dist/screens/settings/settings-page.test.d.ts +0 -1
- package/dist/screens/settings/settings-page.test.js +0 -19
- package/dist/screens/tools/tool-access-ipc.test.d.ts +0 -1
- package/dist/screens/tools/tool-access-ipc.test.js +0 -40
- package/dist/screens/tools/tool-catalog-ipc.test.d.ts +0 -1
- package/dist/screens/tools/tool-catalog-ipc.test.js +0 -52
- package/dist/tabs-layout/network-status-indicator.test.d.ts +0 -1
- package/dist/tabs-layout/network-status-indicator.test.js +0 -665
- package/dist/tabs-layout/tabs-state.test.d.ts +0 -1
- package/dist/tabs-layout/tabs-state.test.js +0 -110
- package/dist/tabs-layout/use-network-status.test.d.ts +0 -1
- package/dist/tabs-layout/use-network-status.test.js +0 -45
- package/dist/ui-router/ui-loader.test.d.ts +0 -1
- package/dist/ui-router/ui-loader.test.js +0 -91
- package/jest.config.js +0 -25
- package/release-guard.js +0 -10
- package/src/app-updates/app-update-controls.tsx +0 -73
- package/src/app-updates/app-updates-consumer.test.ts +0 -83
- package/src/app-updates/app-updates-consumer.ts +0 -121
- package/src/app-updates/app-updates-settings.test.tsx +0 -109
- package/src/app-updates/app-updates-settings.tsx +0 -136
- package/src/app-updates/remote-app-update-panel.test.tsx +0 -205
- package/src/app-updates/remote-app-update-panel.tsx +0 -210
- package/src/app-updates/use-app-update-status.ts +0 -16
- package/src/command-palette/command-palette-ui.tsx +0 -564
- package/src/command-palette/command-palette.ts +0 -242
- package/src/components/access-level-field.test.tsx +0 -32
- package/src/components/access-level-field.tsx +0 -68
- package/src/components/checkbox.tsx +0 -25
- package/src/components/group-switcher.tsx +0 -526
- package/src/components/input-date.tsx +0 -29
- package/src/components/input-number.tsx +0 -83
- package/src/components/input.tsx +0 -25
- package/src/components/inverse-lazy-list.tsx +0 -107
- package/src/components/io-schema-values.tsx +0 -103
- package/src/components/io-schema.tsx +0 -259
- package/src/components/lazy-list.tsx +0 -115
- package/src/components/list-screen.tsx +0 -126
- package/src/components/loading-indicator.tsx +0 -7
- package/src/components/markdown-editor/autolink-plugin.tsx +0 -29
- package/src/components/markdown-editor/editor-inline.tsx +0 -9
- package/src/components/markdown-editor/editor.tsx +0 -158
- package/src/components/markdown-editor/markdown-plugin.tsx +0 -202
- package/src/components/markdown-editor/mention-node.ts +0 -204
- package/src/components/markdown-editor/mentions-plugin.tsx +0 -354
- package/src/components/markdown-editor/move-line-plugin.tsx +0 -186
- package/src/components/markdown-editor/select-line-boundary-plugin.tsx +0 -95
- package/src/components/markdown-editor/theme.ts +0 -46
- package/src/components/markdown-editor/toolbar.tsx +0 -269
- package/src/components/markdown-with-mentions.tsx +0 -198
- package/src/components/message-logs/message-logs.tsx +0 -523
- package/src/components/message-logs/tool-access-approval-card.test.tsx +0 -127
- package/src/components/message-logs/tool-access-approval-card.tsx +0 -178
- package/src/components/messages/avatar.tsx +0 -171
- package/src/components/messages/channel-message-list.tsx +0 -189
- package/src/components/messages/channel-view.tsx +0 -92
- package/src/components/messages/message-compose.tsx +0 -192
- package/src/components/messages/message-display.tsx +0 -231
- package/src/components/messages/thread-message-list.tsx +0 -135
- package/src/components/qr-scanner.tsx +0 -180
- package/src/components/responsive-section-nav.test.tsx +0 -88
- package/src/components/responsive-section-nav.tsx +0 -92
- package/src/components/router.tsx +0 -175
- package/src/components/save-button.tsx +0 -134
- package/src/components/sortable-list.tsx +0 -130
- package/src/components/tabs.tsx +0 -76
- package/src/components/tooltip.tsx +0 -43
- package/src/components/trust-level-badge.tsx +0 -44
- package/src/components/trust-level-dropdown.tsx +0 -136
- package/src/components/typeahead.tsx +0 -357
- package/src/globals-hash.test.ts +0 -19
- package/src/globals.tsx +0 -226
- package/src/hooks/index.ts +0 -8
- package/src/hooks/use-host-contract.ts +0 -75
- package/src/hooks/use-observable-state.test.tsx +0 -101
- package/src/hooks/use-observable-state.ts +0 -29
- package/src/hooks/use-observable.test.tsx +0 -258
- package/src/hooks/use-observable.ts +0 -67
- package/src/hooks/use-on-screen.ts +0 -24
- package/src/hooks/use-promise.ts +0 -34
- package/src/hooks/use-rows.test.tsx +0 -196
- package/src/hooks/use-rows.ts +0 -120
- package/src/hooks/use-subscription.ts +0 -24
- package/src/hooks/use-tool.test.tsx +0 -225
- package/src/hooks/use-tool.ts +0 -116
- package/src/host-shell/host-shell-consumer.test.ts +0 -32
- package/src/host-shell/host-shell-consumer.ts +0 -53
- package/src/index.tsx +0 -42
- package/src/mention-configs.ts +0 -185
- package/src/operator-console/operator-console-state.ts +0 -119
- package/src/operator-console/operator-console.tsx +0 -233
- package/src/peers-services-registration.ts +0 -6
- package/src/root-layout/global-overlays.ts +0 -50
- package/src/root-layout/layout-picker.tsx +0 -47
- package/src/root-layout/layouts/full-screen-layout.tsx +0 -144
- package/src/root-layout/layouts/tabs-with-console-layout.tsx +0 -260
- package/src/root-layout/root-layout-host.test.tsx +0 -108
- package/src/root-layout/root-layout-host.tsx +0 -147
- package/src/root-layout/root-layout-registry.ts +0 -51
- package/src/root-layout/root-layout-state.ts +0 -55
- package/src/root-layout/root-layout.ts +0 -32
- package/src/screens/account/account-screen.test.tsx +0 -65
- package/src/screens/account/account-screen.tsx +0 -942
- package/src/screens/assistants/assistant-config.test.tsx +0 -54
- package/src/screens/assistants/assistant-config.tsx +0 -121
- package/src/screens/assistants/assistant-details.tsx +0 -89
- package/src/screens/assistants/assistant-info.tsx +0 -66
- package/src/screens/assistants/assistant-list.tsx +0 -145
- package/src/screens/assistants/assistant-tools.tsx +0 -82
- package/src/screens/console-logs/console-logs-list.tsx +0 -374
- package/src/screens/console-logs/log-display.tsx +0 -137
- package/src/screens/console-logs/log-filters.tsx +0 -64
- package/src/screens/console-logs/mobile-log-card.tsx +0 -161
- package/src/screens/console-logs/resizable-table-header.tsx +0 -110
- package/src/screens/contacts/contact-details.tsx +0 -123
- package/src/screens/contacts/contact-list.test.tsx +0 -59
- package/src/screens/contacts/contact-list.tsx +0 -286
- package/src/screens/contacts/index.ts +0 -2
- package/src/screens/data-explorer/data-explorer.tsx +0 -633
- package/src/screens/data-explorer/index.ts +0 -6
- package/src/screens/data-explorer/query-executor.tsx +0 -520
- package/src/screens/device-pairing/device-pairing.test.tsx +0 -143
- package/src/screens/device-pairing/device-pairing.tsx +0 -461
- package/src/screens/device-pairing/identity-ipc.ts +0 -25
- package/src/screens/device-pairing/index.ts +0 -2
- package/src/screens/device-pairing/use-device-pairing-state.ts +0 -15
- package/src/screens/devices/devices-list.test.tsx +0 -68
- package/src/screens/devices/devices-list.tsx +0 -365
- package/src/screens/devices/index.ts +0 -1
- package/src/screens/groups/group-details.tsx +0 -160
- package/src/screens/groups/group-invite-panel.tsx +0 -311
- package/src/screens/groups/group-list.test.tsx +0 -44
- package/src/screens/groups/group-list.tsx +0 -317
- package/src/screens/groups/group-members.tsx +0 -343
- package/src/screens/groups/index.ts +0 -3
- package/src/screens/identity/identity-routes.test.ts +0 -70
- package/src/screens/identity/identity-routes.ts +0 -301
- package/src/screens/identity/identity-screen.test.tsx +0 -138
- package/src/screens/identity/identity-screen.tsx +0 -282
- package/src/screens/identity/index.ts +0 -2
- package/src/screens/identity/invite-contact-panel.tsx +0 -45
- package/src/screens/identity/profile-invite.tsx +0 -93
- package/src/screens/invites/accept-invite.test.tsx +0 -115
- package/src/screens/invites/accept-invite.tsx +0 -318
- package/src/screens/invites/activity-view.test.tsx +0 -127
- package/src/screens/invites/activity-view.tsx +0 -162
- package/src/screens/invites/index.ts +0 -6
- package/src/screens/invites/invite-capture.ts +0 -104
- package/src/screens/invites/invite-classify.test.ts +0 -129
- package/src/screens/invites/invite-share.tsx +0 -104
- package/src/screens/invites/invites-ipc.ts +0 -25
- package/src/screens/invites/pending-invites-list.tsx +0 -256
- package/src/screens/network-viewer/connection-troubleshooter.tsx +0 -395
- package/src/screens/network-viewer/cpu-usage-graph.tsx +0 -294
- package/src/screens/network-viewer/device-details-modal.tsx +0 -339
- package/src/screens/network-viewer/group-details-modal.tsx +0 -421
- package/src/screens/network-viewer/index.ts +0 -8
- package/src/screens/network-viewer/network-viewer-ipc.test.ts +0 -72
- package/src/screens/network-viewer/network-viewer-ipc.ts +0 -39
- package/src/screens/network-viewer/network-viewer-section.ts +0 -12
- package/src/screens/network-viewer/network-viewer.section.test.tsx +0 -68
- package/src/screens/network-viewer/network-viewer.tsx +0 -708
- package/src/screens/network-viewer/remote-logs-panel.tsx +0 -190
- package/src/screens/network-viewer/sync-recovery.test.tsx +0 -114
- package/src/screens/network-viewer/sync-recovery.tsx +0 -461
- package/src/screens/network-viewer/usage-graph.tsx +0 -455
- package/src/screens/packages/local-folder-grants-panel.tsx +0 -290
- package/src/screens/packages/local-folders-ipc.ts +0 -28
- package/src/screens/packages/package-details.tsx +0 -166
- package/src/screens/packages/package-helpers.test.ts +0 -57
- package/src/screens/packages/package-helpers.ts +0 -137
- package/src/screens/packages/package-info.tsx +0 -354
- package/src/screens/packages/package-list.tsx +0 -519
- package/src/screens/packages/package-network-panel.tsx +0 -82
- package/src/screens/packages/package-new-local.tsx +0 -100
- package/src/screens/packages/package-runtime-status.test.tsx +0 -58
- package/src/screens/packages/package-runtime-status.tsx +0 -68
- package/src/screens/packages/package-versions.tsx +0 -298
- package/src/screens/packages/packages-ipc.test.ts +0 -47
- package/src/screens/packages/packages-ipc.ts +0 -125
- package/src/screens/peer-types/peer-type-details.tsx +0 -172
- package/src/screens/peer-types/peer-type-list.tsx +0 -64
- package/src/screens/search/global-search.tsx +0 -406
- package/src/screens/settings/color-mode-dropdown.tsx +0 -82
- package/src/screens/settings/settings-page.test.tsx +0 -24
- package/src/screens/settings/settings-page.tsx +0 -426
- package/src/screens/setup-user.tsx +0 -355
- package/src/screens/tools/tool-access-ipc.test.ts +0 -55
- package/src/screens/tools/tool-access-ipc.ts +0 -27
- package/src/screens/tools/tool-catalog-ipc.test.ts +0 -52
- package/src/screens/tools/tool-catalog-ipc.ts +0 -51
- package/src/screens/tools/tool-details.tsx +0 -52
- package/src/screens/tools/tool-info.tsx +0 -45
- package/src/screens/tools/tool-list.tsx +0 -106
- package/src/screens/tools/tool-schema.tsx +0 -44
- package/src/screens/tools/tool-test-details.tsx +0 -89
- package/src/screens/tools/tool-test-list.tsx +0 -73
- package/src/screens/variables/variable-details.tsx +0 -289
- package/src/screens/variables/variable-list.tsx +0 -110
- package/src/screens/welcome-modal.tsx +0 -294
- package/src/screens/workflows/workflow-details.tsx +0 -115
- package/src/screens/workflows/workflow-info.tsx +0 -22
- package/src/screens/workflows/workflow-instructions.tsx +0 -134
- package/src/screens/workflows/workflow-list.tsx +0 -117
- package/src/setupTests.ts +0 -38
- package/src/system-apps/assistants.app.ts +0 -7
- package/src/system-apps/console-logs.app.ts +0 -7
- package/src/system-apps/data-explorer.app.ts +0 -8
- package/src/system-apps/identity.app.ts +0 -9
- package/src/system-apps/index.ts +0 -77
- package/src/system-apps/mobile-settings.app.ts +0 -7
- package/src/system-apps/network-viewer.app.ts +0 -8
- package/src/system-apps/packages.app.ts +0 -7
- package/src/system-apps/search.app.ts +0 -8
- package/src/system-apps/settings.app.ts +0 -7
- package/src/system-apps/threads.app.ts +0 -7
- package/src/system-apps/tools.app.ts +0 -7
- package/src/system-apps/types.app.ts +0 -7
- package/src/system-apps/variables.app.ts +0 -7
- package/src/system-apps/workflows.app.ts +0 -7
- package/src/tabs-layout/network-status-indicator.test.tsx +0 -799
- package/src/tabs-layout/network-status-indicator.tsx +0 -756
- package/src/tabs-layout/tabs-layout.tsx +0 -857
- package/src/tabs-layout/tabs-state.test.ts +0 -152
- package/src/tabs-layout/tabs-state.ts +0 -587
- package/src/tabs-layout/use-network-status.test.tsx +0 -58
- package/src/tabs-layout/use-network-status.ts +0 -68
- package/src/ui-defaults/index.ts +0 -2
- package/src/ui-defaults/list-screen.tsx +0 -94
- package/src/ui-defaults/markdown-field.tsx +0 -87
- package/src/ui-router/routes-loader.ts +0 -193
- package/src/ui-router/ui-loader.test.tsx +0 -108
- package/src/ui-router/ui-loader.tsx +0 -606
- package/src/utils.ts +0 -95
- package/tsconfig.json +0 -18
package/src/ui-defaults/index.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { FieldType, getAllTables, getIconClassName, newid, z } from "@peers-app/peers-sdk";
|
|
2
|
-
// biome-ignore lint/correctness/noUnusedImports: classic JSX (`jsx: react`) needs React in scope for emit
|
|
3
|
-
import React from "react";
|
|
4
|
-
import { ListScreen } from "../components/list-screen";
|
|
5
|
-
import { mainContentPath } from "../globals";
|
|
6
|
-
import { registerInternalPeersUI } from "../ui-router/ui-loader";
|
|
7
|
-
|
|
8
|
-
const propsSchema = z.object({
|
|
9
|
-
// items: zodAnyObject.array().describe('Items to display in the list'),
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
type IProps = z.infer<typeof propsSchema>;
|
|
13
|
-
|
|
14
|
-
export const DefaultListScreen = (_props: IProps) => {
|
|
15
|
-
const path =
|
|
16
|
-
mainContentPath().toLowerCase().trim().split("?")[0].split("#").pop()?.split("/")[0] || "";
|
|
17
|
-
const fuzzyTableName = (
|
|
18
|
-
{
|
|
19
|
-
variables: "persistent_vars",
|
|
20
|
-
}[path] || path
|
|
21
|
-
)
|
|
22
|
-
.replace(/[_-]/g, "")
|
|
23
|
-
.trim();
|
|
24
|
-
|
|
25
|
-
const allTables = getAllTables();
|
|
26
|
-
const tableName = Object.keys(allTables).find(
|
|
27
|
-
(t) => t.toLowerCase().replace(/[_-]/g, "").trim() === fuzzyTableName,
|
|
28
|
-
);
|
|
29
|
-
const table = allTables[tableName || ""];
|
|
30
|
-
if (!table) {
|
|
31
|
-
return <div className="m-4">Table not found for path: "{path}"</div>;
|
|
32
|
-
}
|
|
33
|
-
const idField = table.metaData.fields.find((f) => f.name === table.metaData.primaryKeyName);
|
|
34
|
-
if (!idField) {
|
|
35
|
-
throw new Error("No primary key field found for table");
|
|
36
|
-
}
|
|
37
|
-
const nameField =
|
|
38
|
-
table.metaData.fields.find((f) => f.name === "name") ||
|
|
39
|
-
table.metaData.fields.find((f) => f.name === "title") ||
|
|
40
|
-
table.metaData.fields.find((f) => f.type === FieldType.string);
|
|
41
|
-
if (!nameField) {
|
|
42
|
-
throw new Error("No name field found to create new record with");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<ListScreen
|
|
47
|
-
key={path}
|
|
48
|
-
{...{
|
|
49
|
-
table,
|
|
50
|
-
sortBy: [`-${idField.name}`],
|
|
51
|
-
newRecord: async (text: string) => {
|
|
52
|
-
text = text.trim().replace(/\s+/g, "_");
|
|
53
|
-
let item = table.initRecord({
|
|
54
|
-
[idField.name]: newid(),
|
|
55
|
-
[nameField?.name]: text,
|
|
56
|
-
});
|
|
57
|
-
item = await table.insert(item);
|
|
58
|
-
mainContentPath(`${path}/${item[idField.name]}`);
|
|
59
|
-
return item;
|
|
60
|
-
},
|
|
61
|
-
renderItem: (item) => {
|
|
62
|
-
const row = item as Record<string, unknown>;
|
|
63
|
-
const rowId = row[idField.name];
|
|
64
|
-
const displayName = row.name;
|
|
65
|
-
return (
|
|
66
|
-
<div key={String(rowId)} className="container-fluid pb-4">
|
|
67
|
-
<i className={getIconClassName(table)}></i>
|
|
68
|
-
<a href={`#${path}/${String(rowId)}`}>
|
|
69
|
-
{typeof displayName === "string" ? displayName : "<empty-name>"}
|
|
70
|
-
</a>
|
|
71
|
-
<div style={{ paddingLeft: "20px" }}>
|
|
72
|
-
{/* <MarkdownWithMentions content={item.description || ''} /> */}
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
);
|
|
76
|
-
},
|
|
77
|
-
}}
|
|
78
|
-
/>
|
|
79
|
-
);
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
registerInternalPeersUI({
|
|
83
|
-
peersUIId: "00m5fql0x5v48vyrk5bllzdrr",
|
|
84
|
-
component: DefaultListScreen,
|
|
85
|
-
routes: [
|
|
86
|
-
{
|
|
87
|
-
isMatch: (_props, context) => context.path.split("/").length === 1,
|
|
88
|
-
uiEditMode: "view",
|
|
89
|
-
uiCategory: "screen",
|
|
90
|
-
uiSubcategory: "list",
|
|
91
|
-
priority: -Number.MAX_SAFE_INTEGER,
|
|
92
|
-
},
|
|
93
|
-
],
|
|
94
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { type Observable, observable, z } from "@peers-app/peers-sdk";
|
|
2
|
-
// biome-ignore lint/correctness/noUnusedImports: classic JSX (`jsx: react`) needs React in scope for emit
|
|
3
|
-
import React, { useEffect, useRef, useState } from "react";
|
|
4
|
-
import { MarkdownEditorInline } from "../components/markdown-editor/editor-inline";
|
|
5
|
-
import { MarkdownWithMentions } from "../components/markdown-with-mentions";
|
|
6
|
-
import { registerInternalPeersUI } from "../ui-router/ui-loader";
|
|
7
|
-
|
|
8
|
-
interface IMarkdownFieldProps {
|
|
9
|
-
value: string | Observable<string>;
|
|
10
|
-
onChange?: (value: string) => void;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Markdown field component for viewing markdown content
|
|
15
|
-
*/
|
|
16
|
-
const MarkdownFieldView = (props: IMarkdownFieldProps) => {
|
|
17
|
-
const value = typeof props.value === "function" ? props.value() : props.value;
|
|
18
|
-
|
|
19
|
-
if (!value) {
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return <MarkdownWithMentions content={value} />;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Markdown field component for editing markdown content
|
|
28
|
-
*/
|
|
29
|
-
const MarkdownFieldEdit = (props: IMarkdownFieldProps) => {
|
|
30
|
-
const onChangeRef = useRef(props.onChange);
|
|
31
|
-
onChangeRef.current = props.onChange;
|
|
32
|
-
|
|
33
|
-
// Create an observable for the editor that calls onChange when it changes
|
|
34
|
-
const [valueObs] = useState(() => {
|
|
35
|
-
const initialValue = typeof props.value === "function" ? props.value() : props.value;
|
|
36
|
-
const obs = observable(initialValue || "");
|
|
37
|
-
|
|
38
|
-
// Subscribe to changes and call onChange
|
|
39
|
-
obs.subscribe((newValue) => {
|
|
40
|
-
onChangeRef.current?.(newValue);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
return obs;
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Sync external value changes to the observable
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
const currentValue = typeof props.value === "function" ? props.value() : props.value;
|
|
49
|
-
if (currentValue !== valueObs()) {
|
|
50
|
-
valueObs(currentValue || "");
|
|
51
|
-
}
|
|
52
|
-
}, [props.value, valueObs]);
|
|
53
|
-
|
|
54
|
-
return <MarkdownEditorInline value={valueObs} />;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// Schema for markdown field props
|
|
58
|
-
const markdownFieldPropsSchema = z.object({
|
|
59
|
-
value: z.any(), // Can be string or Observable<string>
|
|
60
|
-
onChange: z.function().optional(),
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Register the view mode component
|
|
64
|
-
registerInternalPeersUI({
|
|
65
|
-
component: MarkdownFieldView,
|
|
66
|
-
propsSchema: markdownFieldPropsSchema,
|
|
67
|
-
routes: [
|
|
68
|
-
{
|
|
69
|
-
uiCategory: "field",
|
|
70
|
-
uiSubcategory: "markdown",
|
|
71
|
-
uiEditMode: "view",
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Register the edit mode component
|
|
77
|
-
registerInternalPeersUI({
|
|
78
|
-
component: MarkdownFieldEdit,
|
|
79
|
-
propsSchema: markdownFieldPropsSchema,
|
|
80
|
-
routes: [
|
|
81
|
-
{
|
|
82
|
-
uiCategory: "field",
|
|
83
|
-
uiSubcategory: "markdown",
|
|
84
|
-
uiEditMode: "edit",
|
|
85
|
-
},
|
|
86
|
-
],
|
|
87
|
-
});
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
debounceByArgs,
|
|
3
|
-
type IAppNav,
|
|
4
|
-
type IPackage,
|
|
5
|
-
type IPeersPackageRoutes,
|
|
6
|
-
type IPeersUIRoute,
|
|
7
|
-
observable,
|
|
8
|
-
Packages,
|
|
9
|
-
PackageVersions,
|
|
10
|
-
packagePrefsVar,
|
|
11
|
-
rpcServerCalls,
|
|
12
|
-
} from "@peers-app/peers-sdk";
|
|
13
|
-
import "../ui-defaults";
|
|
14
|
-
|
|
15
|
-
/** IPackage enriched with appNavs from the active PackageVersion. */
|
|
16
|
-
export type IPackageWithNavs = IPackage & { appNavs?: IAppNav[] };
|
|
17
|
-
|
|
18
|
-
export const allPackages = observable<IPackageWithNavs[]>([]);
|
|
19
|
-
let allRoutesLoaded = false;
|
|
20
|
-
|
|
21
|
-
const prefsSubscribed = new Set<string>();
|
|
22
|
-
|
|
23
|
-
function subscribeToPrefs(packageId: string) {
|
|
24
|
-
if (prefsSubscribed.has(packageId)) return;
|
|
25
|
-
prefsSubscribed.add(packageId);
|
|
26
|
-
const pvar = packagePrefsVar(packageId);
|
|
27
|
-
let lastPvId = pvar()?.activePackageVersionId;
|
|
28
|
-
pvar.subscribe(async (prefs) => {
|
|
29
|
-
const newPvId = prefs?.activePackageVersionId;
|
|
30
|
-
if (newPvId && newPvId !== lastPvId) {
|
|
31
|
-
lastPvId = newPvId;
|
|
32
|
-
const pkg = await Packages().get(packageId);
|
|
33
|
-
if (pkg) {
|
|
34
|
-
const enrichedPkg = await enrichWithPvAppNavs(pkg);
|
|
35
|
-
const _allPackages = allPackages();
|
|
36
|
-
const idx = _allPackages.findIndex((p) => p.packageId === packageId);
|
|
37
|
-
if (idx >= 0) {
|
|
38
|
-
_allPackages[idx] = enrichedPkg;
|
|
39
|
-
allPackages([..._allPackages]);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
reloadPackage(packageId);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Enrich an IPackage with appNavs from the device's active PackageVersion record.
|
|
49
|
-
*/
|
|
50
|
-
async function enrichWithPvAppNavs(pkg: IPackage): Promise<IPackageWithNavs> {
|
|
51
|
-
let pvId = pkg.activePackageVersionId;
|
|
52
|
-
try {
|
|
53
|
-
const pvar = packagePrefsVar(pkg.packageId);
|
|
54
|
-
await pvar.loadingPromise;
|
|
55
|
-
pvId = pvar()?.activePackageVersionId ?? pvId;
|
|
56
|
-
} catch {
|
|
57
|
-
/* use group default */
|
|
58
|
-
}
|
|
59
|
-
if (!pvId) return pkg;
|
|
60
|
-
try {
|
|
61
|
-
const pv = await PackageVersions().get(pvId);
|
|
62
|
-
if (pv?.appNavs) {
|
|
63
|
-
return { ...pkg, appNavs: pv.appNavs };
|
|
64
|
-
}
|
|
65
|
-
} catch {
|
|
66
|
-
/* PV not found */
|
|
67
|
-
}
|
|
68
|
-
return pkg;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export const loadAllRoutes = async () => {
|
|
72
|
-
if (allRoutesLoaded) return;
|
|
73
|
-
allRoutesLoaded = true;
|
|
74
|
-
const packagesWithUI = await Packages().list({
|
|
75
|
-
disabled: { $ne: true },
|
|
76
|
-
activePackageVersionId: { $exists: true },
|
|
77
|
-
});
|
|
78
|
-
const enriched = await Promise.all(packagesWithUI.map(enrichWithPvAppNavs));
|
|
79
|
-
allPackages(enriched);
|
|
80
|
-
await Promise.all(enriched.map((pkg) => loadRoutesBundle(pkg)));
|
|
81
|
-
|
|
82
|
-
for (const pkg of enriched) {
|
|
83
|
-
subscribeToPrefs(pkg.packageId);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
Packages().dataChanged.subscribe(async (evt) => {
|
|
87
|
-
const enrichedPkg = await enrichWithPvAppNavs(evt.dataObject);
|
|
88
|
-
const _allPackages = allPackages();
|
|
89
|
-
if (evt.op === "insert") {
|
|
90
|
-
_allPackages.push(enrichedPkg);
|
|
91
|
-
subscribeToPrefs(evt.dataObject.packageId);
|
|
92
|
-
} else if (evt.op === "delete") {
|
|
93
|
-
const idx = _allPackages.findIndex((p) => p.packageId === evt.dataObject.packageId);
|
|
94
|
-
if (idx >= 0) {
|
|
95
|
-
_allPackages.splice(idx, 1);
|
|
96
|
-
}
|
|
97
|
-
} else {
|
|
98
|
-
const idx = _allPackages.findIndex((p) => p.packageId === evt.dataObject.packageId);
|
|
99
|
-
if (idx >= 0) {
|
|
100
|
-
_allPackages[idx] = enrichedPkg;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
allPackages([..._allPackages]);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
Packages().dataChanged.subscribe((evt) => {
|
|
107
|
-
const pkg = evt.dataObject;
|
|
108
|
-
const loadingPromise = routeLoadingPromises[pkg.packageId];
|
|
109
|
-
if (!loadingPromise) return;
|
|
110
|
-
reloadPackage(pkg.packageId);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
return true;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
type RoutesBundleWindow = Window & {
|
|
117
|
-
registerPeersUIRoute?: (route: IPeersUIRoute) => void;
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const routeLoadingPromises: Record<string, Promise<unknown>> = {};
|
|
121
|
-
function loadRoutesBundle(pkg: IPackageWithNavs, forceRefresh?: boolean): Promise<unknown> {
|
|
122
|
-
// Dynamically import the bundle
|
|
123
|
-
let importPromise: Promise<unknown> = routeLoadingPromises[pkg.packageId];
|
|
124
|
-
if (!importPromise || forceRefresh) {
|
|
125
|
-
console.log(`loading routes bundle for ${pkg.name}`);
|
|
126
|
-
// just importing the module (running it) should be registering all of the package UIs with the Peers App runtime
|
|
127
|
-
|
|
128
|
-
importPromise = (async () => {
|
|
129
|
-
try {
|
|
130
|
-
const w = window as RoutesBundleWindow;
|
|
131
|
-
while (!w.registerPeersUIRoute) {
|
|
132
|
-
console.log(`waiting for registerPeersUIRoute to be defined on the window object`);
|
|
133
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
let pvId = pkg.activePackageVersionId;
|
|
137
|
-
try {
|
|
138
|
-
const pvar = packagePrefsVar(pkg.packageId);
|
|
139
|
-
await pvar.loadingPromise;
|
|
140
|
-
pvId = pvar()?.activePackageVersionId ?? pvId;
|
|
141
|
-
} catch {
|
|
142
|
-
/* use group default */
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
let routesBundleFileId: string | undefined;
|
|
146
|
-
if (pvId) {
|
|
147
|
-
try {
|
|
148
|
-
const pv = await PackageVersions().get(pvId);
|
|
149
|
-
routesBundleFileId = pv?.routesBundleFileId;
|
|
150
|
-
} catch {
|
|
151
|
-
/* no version record */
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
let bundleCode = "";
|
|
156
|
-
if (routesBundleFileId) {
|
|
157
|
-
bundleCode = await rpcServerCalls.getFileContents(routesBundleFileId);
|
|
158
|
-
}
|
|
159
|
-
if (bundleCode) {
|
|
160
|
-
const exportRoutes = (peerRoutes: IPeersPackageRoutes) => {
|
|
161
|
-
const rw = window as RoutesBundleWindow;
|
|
162
|
-
peerRoutes.routes.forEach((route) => {
|
|
163
|
-
rw.registerPeersUIRoute?.(route);
|
|
164
|
-
});
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const bundleFunction = new Function("exportRoutes", bundleCode);
|
|
168
|
-
bundleFunction(exportRoutes);
|
|
169
|
-
|
|
170
|
-
return {};
|
|
171
|
-
} else if (routesBundleFileId) {
|
|
172
|
-
console.warn(
|
|
173
|
-
`Routes bundle file not found for ${pkg.name} (fileId: ${routesBundleFileId})`,
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
return null;
|
|
177
|
-
} catch (err) {
|
|
178
|
-
console.error(`Error while loading routes bundle for ${pkg.name}`, err);
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
})();
|
|
182
|
-
|
|
183
|
-
routeLoadingPromises[pkg.packageId] = importPromise;
|
|
184
|
-
}
|
|
185
|
-
return importPromise;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const reloadPackage = debounceByArgs(async (packageId: string) => {
|
|
189
|
-
const pkg = await Packages().get(packageId);
|
|
190
|
-
if (pkg) {
|
|
191
|
-
await loadRoutesBundle(pkg, true);
|
|
192
|
-
}
|
|
193
|
-
}, 200);
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { act, fireEvent, render, screen } from "@testing-library/react";
|
|
2
|
-
import { useEffect, useState, useSyncExternalStore } from "react";
|
|
3
|
-
|
|
4
|
-
const mockPackages: Record<string, unknown>[] = [];
|
|
5
|
-
const mockGetFileContents = jest.fn();
|
|
6
|
-
jest.mock("@peers-app/peers-sdk", () => ({
|
|
7
|
-
debounceByArgs: (fn: unknown) => fn,
|
|
8
|
-
getUserContext: () => new Promise(() => {}),
|
|
9
|
-
packagePrefsVar: () => Object.assign(() => ({}), { loadingPromise: Promise.resolve() }),
|
|
10
|
-
PackageVersions: () => ({ get: async () => ({ uiBundleFileId: "bundle" }) }),
|
|
11
|
-
rpcServerCalls: { getFileContents: (...args: unknown[]) => mockGetFileContents(...args) },
|
|
12
|
-
}));
|
|
13
|
-
jest.mock("../globals", () => ({ mainContentPath: () => "", packageReloaded: () => 0 }));
|
|
14
|
-
jest.mock("../hooks", () => ({ useObservable: (value: () => unknown) => [value()] }));
|
|
15
|
-
jest.mock("../ui-defaults", () => ({}));
|
|
16
|
-
jest.mock("../components/loading-indicator", () => ({
|
|
17
|
-
LoadingIndicator: () => <p>Loading bundle</p>,
|
|
18
|
-
}));
|
|
19
|
-
jest.mock("./routes-loader", () => ({ allPackages: () => mockPackages }));
|
|
20
|
-
|
|
21
|
-
import { registerInternalPeersUI, UIRouter } from "./ui-loader";
|
|
22
|
-
|
|
23
|
-
test.each([
|
|
24
|
-
false,
|
|
25
|
-
true,
|
|
26
|
-
])("query changes retain screen state and props (preloaded: %s)", async (preloaded) => {
|
|
27
|
-
const packageId = `package-${preloaded}`;
|
|
28
|
-
const peersUIId = `ui-${preloaded}`;
|
|
29
|
-
const base = `package-nav/${packageId}/app`;
|
|
30
|
-
let path = `${base}?jobId=first`;
|
|
31
|
-
const listeners = new Set<() => void>();
|
|
32
|
-
let mounts = 0;
|
|
33
|
-
let unmounts = 0;
|
|
34
|
-
function Content({ caller }: { caller: string }) {
|
|
35
|
-
const [draft, setDraft] = useState("");
|
|
36
|
-
const currentPath = useSyncExternalStore(
|
|
37
|
-
(listener) => {
|
|
38
|
-
listeners.add(listener);
|
|
39
|
-
return () => {
|
|
40
|
-
listeners.delete(listener);
|
|
41
|
-
};
|
|
42
|
-
},
|
|
43
|
-
() => path,
|
|
44
|
-
);
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
mounts++;
|
|
47
|
-
return () => {
|
|
48
|
-
unmounts++;
|
|
49
|
-
};
|
|
50
|
-
}, []);
|
|
51
|
-
return (
|
|
52
|
-
<>
|
|
53
|
-
<p>{caller}</p>
|
|
54
|
-
<p>{currentPath}</p>
|
|
55
|
-
<input
|
|
56
|
-
aria-label="Draft"
|
|
57
|
-
value={draft}
|
|
58
|
-
onChange={(event) => setDraft(event.target.value)}
|
|
59
|
-
/>
|
|
60
|
-
</>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
const schema = { parse: (value: unknown) => value, safeParse: () => ({ success: true }) };
|
|
64
|
-
const ui = { peersUIId, content: Content, propsSchema: schema };
|
|
65
|
-
const routeWindow = window as unknown as {
|
|
66
|
-
registerPeersUIRoute: (route: object) => void;
|
|
67
|
-
testUI?: object;
|
|
68
|
-
};
|
|
69
|
-
routeWindow.registerPeersUIRoute({ packageId, peersUIId, path: base });
|
|
70
|
-
mockPackages.length = 0;
|
|
71
|
-
mockGetFileContents.mockReset();
|
|
72
|
-
let releaseBundle!: (code: string) => void;
|
|
73
|
-
if (preloaded) {
|
|
74
|
-
await registerInternalPeersUI({ component: Content, peersUIId, propsSchema: schema });
|
|
75
|
-
} else {
|
|
76
|
-
mockPackages.push({ packageId, name: "Test package", activePackageVersionId: "version" });
|
|
77
|
-
routeWindow.testUI = ui;
|
|
78
|
-
mockGetFileContents.mockImplementation(
|
|
79
|
-
() =>
|
|
80
|
-
new Promise<string>((resolve) => {
|
|
81
|
-
releaseBundle = resolve;
|
|
82
|
-
}),
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
const view = render(<UIRouter path={path} props={{ caller: "Caller props" }} />);
|
|
86
|
-
if (!preloaded) {
|
|
87
|
-
expect(await screen.findByText("Loading bundle")).toBeInTheDocument();
|
|
88
|
-
await act(async () => {
|
|
89
|
-
releaseBundle("exportUIs({uis: [window.testUI]});");
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
expect(await screen.findByText("Caller props")).toBeInTheDocument();
|
|
93
|
-
fireEvent.change(screen.getByLabelText("Draft"), { target: { value: "Unsaved edits" } });
|
|
94
|
-
await act(async () => {
|
|
95
|
-
path = `${base}?jobId=second`;
|
|
96
|
-
for (const listener of listeners) listener();
|
|
97
|
-
view.rerender(<UIRouter path={path} props={{ caller: "Caller props" }} />);
|
|
98
|
-
});
|
|
99
|
-
expect(screen.getByLabelText("Draft")).toHaveValue("Unsaved edits");
|
|
100
|
-
expect(screen.getByText(path)).toBeInTheDocument();
|
|
101
|
-
expect({ mounts, unmounts, loads: mockGetFileContents.mock.calls.length }).toEqual({
|
|
102
|
-
mounts: 1,
|
|
103
|
-
unmounts: 0,
|
|
104
|
-
loads: preloaded ? 0 : 1,
|
|
105
|
-
});
|
|
106
|
-
view.unmount();
|
|
107
|
-
delete routeWindow.testUI;
|
|
108
|
-
});
|