@peers-app/peers-ui 0.27.3 → 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
|
@@ -1,606 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
debounceByArgs,
|
|
3
|
-
getUserContext,
|
|
4
|
-
type IPackage,
|
|
5
|
-
type IPeersPackageUIs,
|
|
6
|
-
type IPeersUI,
|
|
7
|
-
type IPeersUIRoute,
|
|
8
|
-
newid,
|
|
9
|
-
Packages,
|
|
10
|
-
PackageVersions,
|
|
11
|
-
packagePrefsVar,
|
|
12
|
-
rpcServerCalls,
|
|
13
|
-
toJSON,
|
|
14
|
-
type UIContext,
|
|
15
|
-
zodAnyObject,
|
|
16
|
-
} from "@peers-app/peers-sdk";
|
|
17
|
-
import { orderBy } from "lodash";
|
|
18
|
-
import React, { Component, useEffect } from "react";
|
|
19
|
-
import { LoadingIndicator } from "../components/loading-indicator";
|
|
20
|
-
import { mainContentPath, packageReloaded } from "../globals";
|
|
21
|
-
import { useObservable } from "../hooks";
|
|
22
|
-
import "../ui-defaults";
|
|
23
|
-
import { allPackages } from "./routes-loader";
|
|
24
|
-
|
|
25
|
-
const peersUIs: { [key: string]: IPeersUI } = {};
|
|
26
|
-
|
|
27
|
-
interface ErrorBoundaryState {
|
|
28
|
-
hasError: boolean;
|
|
29
|
-
error: Error | null;
|
|
30
|
-
errorInfo: React.ErrorInfo | null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
interface ErrorBoundaryProps {
|
|
34
|
-
peersUIId?: string;
|
|
35
|
-
packageName?: string;
|
|
36
|
-
componentName?: string;
|
|
37
|
-
children: React.ReactNode;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
class UIErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
41
|
-
constructor(props: ErrorBoundaryProps) {
|
|
42
|
-
super(props);
|
|
43
|
-
this.state = { hasError: false, error: null, errorInfo: null };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
|
47
|
-
return { hasError: true, error, errorInfo: null };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
|
|
51
|
-
console.error("UIErrorBoundary caught an error:", error, errorInfo);
|
|
52
|
-
this.setState({
|
|
53
|
-
error,
|
|
54
|
-
errorInfo,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
render() {
|
|
59
|
-
if (this.state.hasError) {
|
|
60
|
-
const { peersUIId, packageName, componentName } = this.props;
|
|
61
|
-
const { error, errorInfo } = this.state;
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<div
|
|
65
|
-
style={{
|
|
66
|
-
padding: "20px",
|
|
67
|
-
border: "2px solid #ff6b6b",
|
|
68
|
-
borderRadius: "8px",
|
|
69
|
-
backgroundColor: "#fff5f5",
|
|
70
|
-
color: "#721c24",
|
|
71
|
-
fontFamily: "monospace",
|
|
72
|
-
margin: "10px 0",
|
|
73
|
-
}}
|
|
74
|
-
>
|
|
75
|
-
<h3 style={{ color: "#c53030", marginTop: 0 }}>UI Component Error</h3>
|
|
76
|
-
<div style={{ marginBottom: "15px" }}>
|
|
77
|
-
{peersUIId && (
|
|
78
|
-
<div>
|
|
79
|
-
<strong>Peers UI ID:</strong> {peersUIId}
|
|
80
|
-
</div>
|
|
81
|
-
)}
|
|
82
|
-
{packageName && (
|
|
83
|
-
<div>
|
|
84
|
-
<strong>Package:</strong> {packageName}
|
|
85
|
-
</div>
|
|
86
|
-
)}
|
|
87
|
-
{componentName && (
|
|
88
|
-
<div>
|
|
89
|
-
<strong>Component:</strong> {componentName}
|
|
90
|
-
</div>
|
|
91
|
-
)}
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
<details style={{ marginBottom: "15px" }}>
|
|
95
|
-
<summary style={{ cursor: "pointer", fontWeight: "bold", marginBottom: "10px" }}>
|
|
96
|
-
Error Details
|
|
97
|
-
</summary>
|
|
98
|
-
<div
|
|
99
|
-
style={{
|
|
100
|
-
backgroundColor: "#fed7d7",
|
|
101
|
-
padding: "10px",
|
|
102
|
-
borderRadius: "4px",
|
|
103
|
-
whiteSpace: "pre-wrap",
|
|
104
|
-
overflow: "auto",
|
|
105
|
-
maxHeight: "200px",
|
|
106
|
-
}}
|
|
107
|
-
>
|
|
108
|
-
<strong>Error:</strong> {error?.message || "Unknown error"}
|
|
109
|
-
{error?.stack && (
|
|
110
|
-
<>
|
|
111
|
-
<br />
|
|
112
|
-
<br />
|
|
113
|
-
<strong>Stack Trace:</strong>
|
|
114
|
-
<br />
|
|
115
|
-
{error.stack}
|
|
116
|
-
</>
|
|
117
|
-
)}
|
|
118
|
-
</div>
|
|
119
|
-
</details>
|
|
120
|
-
|
|
121
|
-
{errorInfo && (
|
|
122
|
-
<details>
|
|
123
|
-
<summary style={{ cursor: "pointer", fontWeight: "bold", marginBottom: "10px" }}>
|
|
124
|
-
Component Stack
|
|
125
|
-
</summary>
|
|
126
|
-
<div
|
|
127
|
-
style={{
|
|
128
|
-
backgroundColor: "#fed7d7",
|
|
129
|
-
padding: "10px",
|
|
130
|
-
borderRadius: "4px",
|
|
131
|
-
whiteSpace: "pre-wrap",
|
|
132
|
-
overflow: "auto",
|
|
133
|
-
maxHeight: "200px",
|
|
134
|
-
}}
|
|
135
|
-
>
|
|
136
|
-
{errorInfo.componentStack}
|
|
137
|
-
</div>
|
|
138
|
-
</details>
|
|
139
|
-
)}
|
|
140
|
-
|
|
141
|
-
<button
|
|
142
|
-
type="button"
|
|
143
|
-
onClick={() => this.setState({ hasError: false, error: null, errorInfo: null })}
|
|
144
|
-
style={{
|
|
145
|
-
marginTop: "15px",
|
|
146
|
-
padding: "8px 16px",
|
|
147
|
-
backgroundColor: "#c53030",
|
|
148
|
-
color: "white",
|
|
149
|
-
border: "none",
|
|
150
|
-
borderRadius: "4px",
|
|
151
|
-
cursor: "pointer",
|
|
152
|
-
}}
|
|
153
|
-
>
|
|
154
|
-
Try Again
|
|
155
|
-
</button>
|
|
156
|
-
</div>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return this.props.children;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
interface IProps extends UIContext {
|
|
165
|
-
props: Record<string, unknown>;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Pick a registered route for the current screen context and render its component.
|
|
170
|
-
*
|
|
171
|
-
* @param props - Screen context, including the route props to validate.
|
|
172
|
-
*/
|
|
173
|
-
export const UIRouter = (props: IProps) => {
|
|
174
|
-
let matchingRoute: IPeersUIRoute | undefined;
|
|
175
|
-
const allRoutes = _window.getPeersUIRoutes() as IPeersUIRoute[];
|
|
176
|
-
const filteredRoutes = allRoutes.filter((r) => {
|
|
177
|
-
if (
|
|
178
|
-
props.uiEditMode &&
|
|
179
|
-
props.uiEditMode !== "*" &&
|
|
180
|
-
r.uiEditMode !== "*" &&
|
|
181
|
-
r.uiEditMode !== props.uiEditMode
|
|
182
|
-
)
|
|
183
|
-
return false;
|
|
184
|
-
if (
|
|
185
|
-
props.uiCategory &&
|
|
186
|
-
props.uiCategory !== "*" &&
|
|
187
|
-
r.uiCategory !== "*" &&
|
|
188
|
-
r.uiCategory !== props.uiCategory
|
|
189
|
-
)
|
|
190
|
-
return false;
|
|
191
|
-
if (
|
|
192
|
-
props.uiSubcategory &&
|
|
193
|
-
props.uiSubcategory !== "*" &&
|
|
194
|
-
r.uiSubcategory !== "*" &&
|
|
195
|
-
r.uiSubcategory !== props.uiSubcategory
|
|
196
|
-
)
|
|
197
|
-
return false;
|
|
198
|
-
return true;
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const context: UIContext & { path: string } = {
|
|
202
|
-
...props,
|
|
203
|
-
path: props.path || mainContentPath(),
|
|
204
|
-
};
|
|
205
|
-
for (const route of filteredRoutes) {
|
|
206
|
-
// if (route.path && !context.path.startsWith(route.path)) continue;
|
|
207
|
-
|
|
208
|
-
// <todo> test this
|
|
209
|
-
if (route.path) {
|
|
210
|
-
// since `isMatch` can already be used to match the path, this might be overkill
|
|
211
|
-
// but if you just need a simple regex match this makes it nice instead of having to declare a whole function
|
|
212
|
-
const match = route.path.match(/^\/(.+)\/([gimsuy]{0,6})$/);
|
|
213
|
-
if (match) {
|
|
214
|
-
const [, pattern, flags] = match;
|
|
215
|
-
try {
|
|
216
|
-
const regex = new RegExp(pattern, flags);
|
|
217
|
-
if (!regex.test(context.path)) continue;
|
|
218
|
-
} catch {
|
|
219
|
-
// Invalid regex → treat as plain prefix
|
|
220
|
-
if (!context.path.startsWith(route.path)) continue;
|
|
221
|
-
}
|
|
222
|
-
} else {
|
|
223
|
-
// TODO treating path as a prefix is confusing.
|
|
224
|
-
// Now that we have regex matching, we should treat it as exact match if it's not a regex
|
|
225
|
-
if (!context.path.startsWith(route.path)) continue;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
// </todo>
|
|
229
|
-
|
|
230
|
-
if (!route.propsSchema || route.propsSchema.safeParse(props.props).success) {
|
|
231
|
-
if (!route.isMatch || route.isMatch(props.props, context)) {
|
|
232
|
-
matchingRoute = route;
|
|
233
|
-
break;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (!matchingRoute) {
|
|
239
|
-
return undefined;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return <UILoader peersUIId={matchingRoute.peersUIId} props={props.props} />;
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
const UILoader = (args: { peersUIId: string; props?: Record<string, unknown> }) => {
|
|
246
|
-
if (!args.props) {
|
|
247
|
-
args.props = {};
|
|
248
|
-
}
|
|
249
|
-
const { props, peersUIId } = args;
|
|
250
|
-
const [lastReloadTime] = useObservable(packageReloaded);
|
|
251
|
-
props.__lastPackageReload = lastReloadTime;
|
|
252
|
-
// Keep the same loader ancestor after the bundle enters the cache. Replacing it
|
|
253
|
-
// on a path change would unmount the screen before its navigation guard can run.
|
|
254
|
-
return <UIAsyncLoader key={peersUIId} peersUIId={peersUIId} props={props} />;
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
const uiLoadingPromises: Record<string, Promise<void>> = {};
|
|
258
|
-
|
|
259
|
-
async function resolveUiBundleFileId(pkg: IPackage): Promise<string | undefined> {
|
|
260
|
-
let pvId = pkg.activePackageVersionId;
|
|
261
|
-
try {
|
|
262
|
-
const pvar = packagePrefsVar(pkg.packageId);
|
|
263
|
-
await pvar.loadingPromise;
|
|
264
|
-
pvId = pvar()?.activePackageVersionId ?? pvId;
|
|
265
|
-
} catch {
|
|
266
|
-
/* use group default */
|
|
267
|
-
}
|
|
268
|
-
if (!pvId) return undefined;
|
|
269
|
-
try {
|
|
270
|
-
const pv = await PackageVersions().get(pvId);
|
|
271
|
-
return pv?.uiBundleFileId;
|
|
272
|
-
} catch {
|
|
273
|
-
return undefined;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function loadUIBundle(pkg: IPackage, forceRefresh?: boolean) {
|
|
278
|
-
let importPromise: Promise<void> = uiLoadingPromises[pkg.packageId];
|
|
279
|
-
if (!importPromise || forceRefresh) {
|
|
280
|
-
const sTime = Date.now();
|
|
281
|
-
console.log(`loading ui bundle for ${pkg.name}`);
|
|
282
|
-
importPromise = (async () => {
|
|
283
|
-
const uiBundleFileId = await resolveUiBundleFileId(pkg);
|
|
284
|
-
if (!uiBundleFileId) {
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const bundleCode = await rpcServerCalls.getFileContents(uiBundleFileId);
|
|
289
|
-
if (bundleCode) {
|
|
290
|
-
const exportUIs = (peerUIs: IPeersPackageUIs) => {
|
|
291
|
-
peerUIs?.uis?.forEach((ui) => {
|
|
292
|
-
peersUIs[ui.peersUIId] = ui;
|
|
293
|
-
});
|
|
294
|
-
};
|
|
295
|
-
const bundleFunction = new Function("exportUIs", bundleCode);
|
|
296
|
-
await bundleFunction(exportUIs);
|
|
297
|
-
}
|
|
298
|
-
console.log(
|
|
299
|
-
`finished loading ui bundle for ${pkg.name}: ${(Date.now() - sTime).toFixed(0)}ms, ${bundleCode ? (bundleCode.length / 1000).toFixed(0) : "0"} KB`,
|
|
300
|
-
);
|
|
301
|
-
})().catch((err: unknown) => {
|
|
302
|
-
console.error(`Error while loading ui module for ${pkg.name}`, err);
|
|
303
|
-
throw err;
|
|
304
|
-
});
|
|
305
|
-
uiLoadingPromises[pkg.packageId] = importPromise;
|
|
306
|
-
}
|
|
307
|
-
return importPromise;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const UIAsyncLoader = (props: { peersUIId: string; props: Record<string, unknown> }) => {
|
|
311
|
-
const { peersUIId } = props;
|
|
312
|
-
const peersUI = peersUIs[peersUIId];
|
|
313
|
-
const [loaded, setLoaded] = React.useState(false);
|
|
314
|
-
const [loadError, setLoadError] = React.useState<Error | null>(null);
|
|
315
|
-
|
|
316
|
-
const allRoutes = _window.getPeersUIRoutes() as IPeersUIRoute[];
|
|
317
|
-
const uiPackageId = allRoutes.find((r) => r.peersUIId === peersUIId)?.packageId;
|
|
318
|
-
|
|
319
|
-
useObservable(allPackages);
|
|
320
|
-
const pkg = allPackages().find((p) => p.packageId === uiPackageId);
|
|
321
|
-
|
|
322
|
-
useEffect(() => {
|
|
323
|
-
if (!pkg || peersUIs[peersUIId]?.content) return;
|
|
324
|
-
const pkgRef = pkg;
|
|
325
|
-
setLoadError(null);
|
|
326
|
-
loadUIBundle(pkgRef)
|
|
327
|
-
.then(() => setLoaded(true))
|
|
328
|
-
.catch((error) => {
|
|
329
|
-
console.error(`Failed to load UI bundle for package ${pkgRef.name}:`, error);
|
|
330
|
-
setLoadError(error);
|
|
331
|
-
});
|
|
332
|
-
}, [peersUIId, pkg?.packageId, pkg?.name, pkg]);
|
|
333
|
-
|
|
334
|
-
if (!peersUI?.content && !pkg) {
|
|
335
|
-
return <div>Could not find package that owns peersUIId {peersUIId}</div>;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (!peersUI?.content && loadError) {
|
|
339
|
-
return (
|
|
340
|
-
<div
|
|
341
|
-
style={{
|
|
342
|
-
padding: "20px",
|
|
343
|
-
border: "2px solid #ff6b6b",
|
|
344
|
-
borderRadius: "8px",
|
|
345
|
-
backgroundColor: "#fff5f5",
|
|
346
|
-
color: "#721c24",
|
|
347
|
-
fontFamily: "monospace",
|
|
348
|
-
margin: "10px 0",
|
|
349
|
-
}}
|
|
350
|
-
>
|
|
351
|
-
<h3 style={{ color: "#c53030", marginTop: 0 }}>Bundle Loading Error</h3>
|
|
352
|
-
<div style={{ marginBottom: "15px" }}>
|
|
353
|
-
<div>
|
|
354
|
-
<strong>Peers UI ID:</strong> {peersUIId}
|
|
355
|
-
</div>
|
|
356
|
-
<div>
|
|
357
|
-
<strong>Package:</strong> {pkg?.name}
|
|
358
|
-
</div>
|
|
359
|
-
<div>
|
|
360
|
-
<strong>Package ID:</strong> {pkg?.packageId}
|
|
361
|
-
</div>
|
|
362
|
-
</div>
|
|
363
|
-
|
|
364
|
-
<details style={{ marginBottom: "15px" }}>
|
|
365
|
-
<summary style={{ cursor: "pointer", fontWeight: "bold", marginBottom: "10px" }}>
|
|
366
|
-
Error Details
|
|
367
|
-
</summary>
|
|
368
|
-
<div
|
|
369
|
-
style={{
|
|
370
|
-
backgroundColor: "#fed7d7",
|
|
371
|
-
padding: "10px",
|
|
372
|
-
borderRadius: "4px",
|
|
373
|
-
whiteSpace: "pre-wrap",
|
|
374
|
-
overflow: "auto",
|
|
375
|
-
maxHeight: "200px",
|
|
376
|
-
}}
|
|
377
|
-
>
|
|
378
|
-
<strong>Error:</strong> {loadError.message || "Unknown error"}
|
|
379
|
-
{loadError.stack && (
|
|
380
|
-
<>
|
|
381
|
-
<br />
|
|
382
|
-
<br />
|
|
383
|
-
<strong>Stack Trace:</strong>
|
|
384
|
-
<br />
|
|
385
|
-
{loadError.stack}
|
|
386
|
-
</>
|
|
387
|
-
)}
|
|
388
|
-
</div>
|
|
389
|
-
</details>
|
|
390
|
-
|
|
391
|
-
<button
|
|
392
|
-
type="button"
|
|
393
|
-
onClick={() => {
|
|
394
|
-
setLoadError(null);
|
|
395
|
-
setLoaded(false);
|
|
396
|
-
if (pkg) {
|
|
397
|
-
loadUIBundle(pkg, true)
|
|
398
|
-
.then(() => setLoaded(true))
|
|
399
|
-
.catch(setLoadError);
|
|
400
|
-
}
|
|
401
|
-
}}
|
|
402
|
-
style={{
|
|
403
|
-
marginTop: "15px",
|
|
404
|
-
padding: "8px 16px",
|
|
405
|
-
backgroundColor: "#c53030",
|
|
406
|
-
color: "white",
|
|
407
|
-
border: "none",
|
|
408
|
-
borderRadius: "4px",
|
|
409
|
-
cursor: "pointer",
|
|
410
|
-
}}
|
|
411
|
-
>
|
|
412
|
-
Retry Loading
|
|
413
|
-
</button>
|
|
414
|
-
</div>
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (!peersUI?.content && !loaded) {
|
|
419
|
-
return <LoadingIndicator />;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
if (peersUI?.content) {
|
|
423
|
-
const _props = props.props;
|
|
424
|
-
try {
|
|
425
|
-
peersUI.propsSchema.parse(_props);
|
|
426
|
-
const Component = peersUI.content as React.ComponentType<Record<string, unknown>>;
|
|
427
|
-
return (
|
|
428
|
-
<UIErrorBoundary
|
|
429
|
-
peersUIId={peersUIId}
|
|
430
|
-
packageName={pkg?.name}
|
|
431
|
-
componentName={peersUI.content?.name}
|
|
432
|
-
>
|
|
433
|
-
<Component {..._props} />
|
|
434
|
-
</UIErrorBoundary>
|
|
435
|
-
);
|
|
436
|
-
} catch (parseError) {
|
|
437
|
-
return (
|
|
438
|
-
<div
|
|
439
|
-
style={{
|
|
440
|
-
padding: "20px",
|
|
441
|
-
border: "2px solid #ff6b6b",
|
|
442
|
-
borderRadius: "8px",
|
|
443
|
-
backgroundColor: "#fff5f5",
|
|
444
|
-
color: "#721c24",
|
|
445
|
-
fontFamily: "monospace",
|
|
446
|
-
margin: "10px 0",
|
|
447
|
-
}}
|
|
448
|
-
>
|
|
449
|
-
<h3 style={{ color: "#c53030", marginTop: 0 }}>Props Validation Error</h3>
|
|
450
|
-
<div style={{ marginBottom: "15px" }}>
|
|
451
|
-
<div>
|
|
452
|
-
<strong>Peers UI ID:</strong> {peersUIId}
|
|
453
|
-
</div>
|
|
454
|
-
<div>
|
|
455
|
-
<strong>Package:</strong> {pkg?.name}
|
|
456
|
-
</div>
|
|
457
|
-
<div>
|
|
458
|
-
<strong>Component:</strong> {peersUI.content?.name}
|
|
459
|
-
</div>
|
|
460
|
-
</div>
|
|
461
|
-
|
|
462
|
-
<div
|
|
463
|
-
style={{
|
|
464
|
-
backgroundColor: "#fed7d7",
|
|
465
|
-
padding: "10px",
|
|
466
|
-
borderRadius: "4px",
|
|
467
|
-
whiteSpace: "pre-wrap",
|
|
468
|
-
overflow: "auto",
|
|
469
|
-
maxHeight: "200px",
|
|
470
|
-
marginBottom: "15px",
|
|
471
|
-
}}
|
|
472
|
-
>
|
|
473
|
-
<strong>Error:</strong> Props did not match schema
|
|
474
|
-
<br />
|
|
475
|
-
<strong>Validation Error:</strong> {JSON.stringify(parseError, null, 2)}
|
|
476
|
-
<br />
|
|
477
|
-
<br />
|
|
478
|
-
<strong>Props:</strong> {JSON.stringify(toJSON(_props), null, 2)}
|
|
479
|
-
</div>
|
|
480
|
-
</div>
|
|
481
|
-
);
|
|
482
|
-
}
|
|
483
|
-
} else {
|
|
484
|
-
return <div>Component not found</div>;
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
type PeersRuntimeWindow = Window & {
|
|
489
|
-
registerPeersUIRoute: (route: IPeersUIRoute) => void;
|
|
490
|
-
getPeersUIRoutes: () => IPeersUIRoute[];
|
|
491
|
-
UIRouter: typeof UIRouter;
|
|
492
|
-
UILoader: typeof UILoader;
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
let _window: PeersRuntimeWindow;
|
|
496
|
-
|
|
497
|
-
if (typeof window !== "undefined") {
|
|
498
|
-
_window = window as unknown as PeersRuntimeWindow;
|
|
499
|
-
if (!_window.registerPeersUIRoute) {
|
|
500
|
-
let uiRoutes: IPeersUIRoute[] = [];
|
|
501
|
-
Object.defineProperty(window, "registerPeersUIRoute", {
|
|
502
|
-
value: (route: IPeersUIRoute) => {
|
|
503
|
-
uiRoutes = uiRoutes.filter((r) => !(r.peersUIId === route.peersUIId));
|
|
504
|
-
uiRoutes.push(route);
|
|
505
|
-
uiRoutes = orderBy(uiRoutes, (r) => r.priority ?? 0, "desc");
|
|
506
|
-
},
|
|
507
|
-
writable: false,
|
|
508
|
-
configurable: false,
|
|
509
|
-
});
|
|
510
|
-
Object.defineProperty(window, "getPeersUIRoutes", {
|
|
511
|
-
value: () => {
|
|
512
|
-
return [...uiRoutes];
|
|
513
|
-
},
|
|
514
|
-
writable: false,
|
|
515
|
-
configurable: false,
|
|
516
|
-
});
|
|
517
|
-
Object.defineProperty(window, "UIRouter", {
|
|
518
|
-
value: UIRouter,
|
|
519
|
-
writable: false,
|
|
520
|
-
configurable: false,
|
|
521
|
-
});
|
|
522
|
-
Object.defineProperty(window, "UILoader", {
|
|
523
|
-
value: UILoader,
|
|
524
|
-
writable: false,
|
|
525
|
-
configurable: false,
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
/** Package id used when peers-ui registers its own built-in screens. */
|
|
531
|
-
export const peersSystemPackageId = "000peers0system000package";
|
|
532
|
-
|
|
533
|
-
/**
|
|
534
|
-
* This is meant to make it easy to register components that are internal to peers
|
|
535
|
-
*/
|
|
536
|
-
export async function registerInternalPeersUI(props: {
|
|
537
|
-
component: IPeersUI["content"];
|
|
538
|
-
/** Zod schemas may use a different zod instance than peers-sdk (duplicate resolution); keep loose. */
|
|
539
|
-
propsSchema?: any;
|
|
540
|
-
routes?: Omit<IPeersUIRoute, "peersUIId" | "packageId">[];
|
|
541
|
-
peersUIId?: string;
|
|
542
|
-
}) {
|
|
543
|
-
const routeWin = window as Window & { registerPeersUIRoute?: (route: IPeersUIRoute) => void };
|
|
544
|
-
while (!routeWin.registerPeersUIRoute) {
|
|
545
|
-
console.log("Waiting for registerPeersUIRoute to be defined on the window object");
|
|
546
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
547
|
-
}
|
|
548
|
-
const peersUIId = props.peersUIId || newid();
|
|
549
|
-
|
|
550
|
-
const peersUI: IPeersUI = {
|
|
551
|
-
peersUIId,
|
|
552
|
-
content: props.component,
|
|
553
|
-
propsSchema: props.propsSchema || zodAnyObject,
|
|
554
|
-
};
|
|
555
|
-
peersUIs[peersUIId] = peersUI;
|
|
556
|
-
|
|
557
|
-
if (props.routes?.length) {
|
|
558
|
-
props.routes.forEach((route) => {
|
|
559
|
-
_window.registerPeersUIRoute({
|
|
560
|
-
packageId: peersSystemPackageId,
|
|
561
|
-
peersUIId,
|
|
562
|
-
propsSchema: props.propsSchema,
|
|
563
|
-
...route,
|
|
564
|
-
});
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
const reloadPackage = debounceByArgs(async (packageId: string) => {
|
|
570
|
-
const pkg = await Packages().get(packageId);
|
|
571
|
-
if (pkg) {
|
|
572
|
-
await loadUIBundle(pkg, true);
|
|
573
|
-
console.log(`reloaded UI bundle for ${pkg.name}`);
|
|
574
|
-
packageReloaded(Date.now());
|
|
575
|
-
}
|
|
576
|
-
}, 200);
|
|
577
|
-
|
|
578
|
-
const uiPrefsSubscribed = new Set<string>();
|
|
579
|
-
|
|
580
|
-
function subscribeToPrefs(packageId: string) {
|
|
581
|
-
if (uiPrefsSubscribed.has(packageId)) return;
|
|
582
|
-
uiPrefsSubscribed.add(packageId);
|
|
583
|
-
const pvar = packagePrefsVar(packageId);
|
|
584
|
-
let lastPvId = pvar()?.activePackageVersionId;
|
|
585
|
-
pvar.subscribe((prefs) => {
|
|
586
|
-
const newPvId = prefs?.activePackageVersionId;
|
|
587
|
-
if (newPvId && newPvId !== lastPvId) {
|
|
588
|
-
lastPvId = newPvId;
|
|
589
|
-
reloadPackage(packageId);
|
|
590
|
-
}
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
getUserContext().then((_userContext) => {
|
|
595
|
-
for (const packageId of Object.keys(uiLoadingPromises)) {
|
|
596
|
-
subscribeToPrefs(packageId);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
Packages().dataChanged.subscribe(async (evt) => {
|
|
600
|
-
const pkg = evt.dataObject;
|
|
601
|
-
const loadingPromise = uiLoadingPromises[pkg.packageId];
|
|
602
|
-
if (!loadingPromise) return;
|
|
603
|
-
subscribeToPrefs(pkg.packageId);
|
|
604
|
-
reloadPackage(pkg.packageId);
|
|
605
|
-
});
|
|
606
|
-
});
|
package/src/utils.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import DOMPurify from "dompurify";
|
|
2
|
-
import _ from "lodash";
|
|
3
|
-
|
|
4
|
-
/** Plain text content of an HTML string (parsed with `DOMParser`, so browser-only). */
|
|
5
|
-
export function htmlToText(html: string): string {
|
|
6
|
-
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
7
|
-
return doc.body.textContent || "";
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/** Replaces `<@type:name:id>` / `<$type:name:id>` mentions with the readable name, underscores as spaces. */
|
|
11
|
-
export function stripMentions(text: string): string {
|
|
12
|
-
// Replace <type:name:id> with just the readable name part
|
|
13
|
-
// Convert underscores to spaces for better readability
|
|
14
|
-
return text.replace(/<[@$]([^:]+):([^:]+):([^>]+)>/g, (_match, _type, name, _id) => {
|
|
15
|
-
return name.replace(/_/g, " ");
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Sanitizes HTML with DOMPurify, collapses repeated blank paragraphs, and drops a trailing one. */
|
|
20
|
-
export function trimAndSanitizeHtml(value: string) {
|
|
21
|
-
let sanitizedValue: string = DOMPurify.sanitize(value);
|
|
22
|
-
// removes empty paragraphs
|
|
23
|
-
// return sanitizedValue.replace(/\<p\>\<br\>\<\/p\>/ig, '').trim()
|
|
24
|
-
|
|
25
|
-
const singleBlankLine = "<p><br></p>";
|
|
26
|
-
const doubleBlankLine = singleBlankLine + singleBlankLine;
|
|
27
|
-
|
|
28
|
-
// collapse lots of blank lines into one
|
|
29
|
-
while (sanitizedValue.includes(doubleBlankLine)) {
|
|
30
|
-
sanitizedValue = sanitizedValue.replaceAll(doubleBlankLine, singleBlankLine);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// remove trailing blank line
|
|
34
|
-
if (sanitizedValue.endsWith(singleBlankLine)) {
|
|
35
|
-
sanitizedValue = sanitizedValue.substr(0, sanitizedValue.length - singleBlankLine.length);
|
|
36
|
-
}
|
|
37
|
-
return sanitizedValue;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// must be done this way so TypeScript doesn't rewrite async keyword
|
|
41
|
-
// export const AsyncFunction = eval('Object.getPrototypeOf(async function () { }).constructor');
|
|
42
|
-
/** The `AsyncFunction` constructor, for compiling async code from a string. */
|
|
43
|
-
export const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Compiles and runs `jsCode` as the body of a strict async function. `utils`, `Promise`,
|
|
47
|
-
* `console` and each key of `externalReferences` are in scope; `process` and `global` are hidden.
|
|
48
|
-
* Runs arbitrary code: never pass it untrusted input.
|
|
49
|
-
*/
|
|
50
|
-
export function jsAsync(jsCode: string, externalReferences: any = {}) {
|
|
51
|
-
jsCode = String(jsCode).trim();
|
|
52
|
-
const hideGlobals = [
|
|
53
|
-
"process",
|
|
54
|
-
"global", //,'setTimeout','setInterval','setImmediate','clearImmediate','clearInterval','clearTimeout'
|
|
55
|
-
];
|
|
56
|
-
const utils = module.exports;
|
|
57
|
-
const refNames = ["utils", "utils_1", "Promise", "console"];
|
|
58
|
-
const refValues = [utils, utils, Promise, console];
|
|
59
|
-
_.keys(externalReferences).forEach((key) => {
|
|
60
|
-
refNames.push(key);
|
|
61
|
-
refValues.push(externalReferences[key]);
|
|
62
|
-
});
|
|
63
|
-
const compiledJs = AsyncFunction.apply(null, [
|
|
64
|
-
...refNames,
|
|
65
|
-
...hideGlobals,
|
|
66
|
-
`"use strict";\n${jsCode}`,
|
|
67
|
-
]);
|
|
68
|
-
return compiledJs.apply(null, refValues);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// export type IObjectMatch<T> = {
|
|
72
|
-
// [key in keyof T]?: RegExp | string | number | boolean
|
|
73
|
-
// }
|
|
74
|
-
|
|
75
|
-
// export function objectMatch<T>(value: T, match: IObjectMatch<T>): boolean {
|
|
76
|
-
// for (const [k, _m] of Object.entries(match)) {
|
|
77
|
-
// const m = _m as any;
|
|
78
|
-
// if (m === undefined) continue; // NOTE we are not trying to match undefined values
|
|
79
|
-
// // NOTE null will match null or undefined
|
|
80
|
-
// if (m === null && (value[k] === null || value[k] === undefined)) {
|
|
81
|
-
// return true
|
|
82
|
-
// }
|
|
83
|
-
// if (_.isRegExp(m)) {
|
|
84
|
-
// if (!String(value[k]).match(m)) {
|
|
85
|
-
// return false;
|
|
86
|
-
// }
|
|
87
|
-
// } else if (m != value[k]) {
|
|
88
|
-
// return false;
|
|
89
|
-
// }
|
|
90
|
-
// }
|
|
91
|
-
// return true;
|
|
92
|
-
// }
|
|
93
|
-
|
|
94
|
-
// @ts-expect-error
|
|
95
|
-
if (typeof window !== "undefined") window.utils = module.exports;
|