@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
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
GroupMemberRole,
|
|
3
|
-
GroupMembers,
|
|
4
|
-
Groups,
|
|
5
|
-
getRoleLabel,
|
|
6
|
-
getUserById,
|
|
7
|
-
getUserContext,
|
|
8
|
-
getUserRole,
|
|
9
|
-
type IUser,
|
|
10
|
-
setUserTrustLevel,
|
|
11
|
-
TrustLevel,
|
|
12
|
-
type UserContext,
|
|
13
|
-
Users,
|
|
14
|
-
usersCursor,
|
|
15
|
-
} from "@peers-app/peers-sdk";
|
|
16
|
-
import React from "react";
|
|
17
|
-
import { LoadingIndicator } from "../../components/loading-indicator";
|
|
18
|
-
import { TrustLevelBadge } from "../../components/trust-level-badge";
|
|
19
|
-
import { usePromise } from "../../hooks";
|
|
20
|
-
import { GroupInvitePanel } from "./group-invite-panel";
|
|
21
|
-
|
|
22
|
-
interface GroupMembersUIProps {
|
|
23
|
-
groupId: string;
|
|
24
|
-
userContext: UserContext;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** List group memberships and expose role-appropriate invite and member controls. */
|
|
28
|
-
export const GroupMembersUI = (props: GroupMembersUIProps) => {
|
|
29
|
-
const { groupId, userContext } = props;
|
|
30
|
-
|
|
31
|
-
// Get the group's data context and tables
|
|
32
|
-
const groupDataContext = userContext.getDataContext(groupId);
|
|
33
|
-
const groupMembersTable = GroupMembers(groupDataContext);
|
|
34
|
-
const groupUsersTable = Users(groupDataContext);
|
|
35
|
-
|
|
36
|
-
// State for refreshing the component
|
|
37
|
-
const [refreshKey, setRefreshKey] = React.useState(0);
|
|
38
|
-
|
|
39
|
-
// Load group members with user details and check current user permissions
|
|
40
|
-
const membersData = usePromise(
|
|
41
|
-
async () => {
|
|
42
|
-
const members = await groupMembersTable.list({ deleted: { $ne: true } });
|
|
43
|
-
|
|
44
|
-
// Get user details for each member using the group context
|
|
45
|
-
const membersWithUsers = await Promise.all(
|
|
46
|
-
members.map(async (member) => {
|
|
47
|
-
const user = await getUserById(member.userId, {
|
|
48
|
-
currentDataContext: groupDataContext,
|
|
49
|
-
includeTrustLevel: true,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// If user found from external source, save to current group
|
|
53
|
-
if (user && user.source !== "currentDataContext") {
|
|
54
|
-
try {
|
|
55
|
-
const raw = { ...user } as Record<string, unknown>;
|
|
56
|
-
delete raw.source;
|
|
57
|
-
delete raw.trustLevel;
|
|
58
|
-
await groupUsersTable.save(raw as IUser);
|
|
59
|
-
|
|
60
|
-
// Set trust level for this user in the group context
|
|
61
|
-
await setUserTrustLevel(user.userId, TrustLevel.NewUser, groupDataContext);
|
|
62
|
-
|
|
63
|
-
// Update user reference to reflect it's now in current group
|
|
64
|
-
user.trustLevel = TrustLevel.NewUser;
|
|
65
|
-
user.source = "currentDataContext";
|
|
66
|
-
} catch (saveErr) {
|
|
67
|
-
console.error("Failed to save user to group context:", saveErr);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// TODO don't do it this way!!! Use group-specific trust level fetching
|
|
72
|
-
if (user && !user.trustLevel) {
|
|
73
|
-
const userCursor = await usersCursor(
|
|
74
|
-
{ userId: member.userId },
|
|
75
|
-
{ includeTrustLevel: true },
|
|
76
|
-
);
|
|
77
|
-
const _user = await userCursor.next();
|
|
78
|
-
user.trustLevel = _user?.trustLevel || user.trustLevel || TrustLevel.Unknown;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// // Fetch trust level for this user in the group context
|
|
82
|
-
// if (user) {
|
|
83
|
-
// try {
|
|
84
|
-
// const trustLevel = await getUserTrustLevel(groupDataContext, user.userId);
|
|
85
|
-
// user.trustLevel = trustLevel;
|
|
86
|
-
// } catch (err) {
|
|
87
|
-
// console.error('Failed to get trust level:', err);
|
|
88
|
-
// user.trustLevel = TrustLevel.Unknown;
|
|
89
|
-
// }
|
|
90
|
-
// }
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
member,
|
|
94
|
-
user: user || null,
|
|
95
|
-
};
|
|
96
|
-
}),
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
return membersWithUsers;
|
|
100
|
-
},
|
|
101
|
-
[],
|
|
102
|
-
[groupId, refreshKey],
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
// Check if current user has admin privileges in this group
|
|
106
|
-
const userPermissions = usePromise(
|
|
107
|
-
async () => {
|
|
108
|
-
const currentUserContext = await getUserContext();
|
|
109
|
-
const currentUserId = currentUserContext.userId;
|
|
110
|
-
const userRole = await getUserRole(groupId, currentUserId);
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
isMember: !!userRole,
|
|
114
|
-
canEdit: userRole >= GroupMemberRole.Admin,
|
|
115
|
-
userRole: userRole,
|
|
116
|
-
currentUserId: currentUserId,
|
|
117
|
-
};
|
|
118
|
-
},
|
|
119
|
-
undefined,
|
|
120
|
-
[groupId],
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
// Load group and founder information
|
|
124
|
-
const founderData = usePromise(
|
|
125
|
-
async () => {
|
|
126
|
-
const groupsTable = Groups(groupDataContext);
|
|
127
|
-
const group =
|
|
128
|
-
(await groupsTable.get(groupId)) ||
|
|
129
|
-
(await Groups(userContext.userDataContext).get(groupId));
|
|
130
|
-
|
|
131
|
-
if (!group) {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Try to get founder user details
|
|
136
|
-
const founderUser = await getUserById(group.founderUserId, {
|
|
137
|
-
currentDataContext: groupDataContext,
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
group,
|
|
142
|
-
founderUser,
|
|
143
|
-
founderUserId: group.founderUserId,
|
|
144
|
-
};
|
|
145
|
-
},
|
|
146
|
-
undefined,
|
|
147
|
-
[groupId, refreshKey],
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
// Refresh the member list when an accepted invite adds a membership row.
|
|
151
|
-
React.useEffect(() => {
|
|
152
|
-
const sub = groupMembersTable.dataChanged.subscribe(() => setRefreshKey((prev) => prev + 1));
|
|
153
|
-
return () => {
|
|
154
|
-
sub.unsubscribe();
|
|
155
|
-
};
|
|
156
|
-
}, [groupMembersTable]);
|
|
157
|
-
|
|
158
|
-
const updateRole = async (memberId: string, newRole: GroupMemberRole) => {
|
|
159
|
-
try {
|
|
160
|
-
const member = await groupMembersTable.get(memberId);
|
|
161
|
-
if (member) {
|
|
162
|
-
member.role = newRole;
|
|
163
|
-
await groupMembersTable.signAndSave(member);
|
|
164
|
-
setRefreshKey((prev) => prev + 1);
|
|
165
|
-
}
|
|
166
|
-
} catch (err) {
|
|
167
|
-
console.error("Failed to update role:", err);
|
|
168
|
-
alert("Failed to update member role.");
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
const removeMember = async (memberId: string) => {
|
|
173
|
-
if (!confirm("Remove this member from the group?")) return;
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
await groupMembersTable.delete(memberId);
|
|
177
|
-
setRefreshKey((prev) => prev + 1);
|
|
178
|
-
} catch (err) {
|
|
179
|
-
console.error("Failed to remove member:", err);
|
|
180
|
-
alert("Failed to remove member.");
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
if (!membersData || !userPermissions || !founderData) {
|
|
185
|
-
return <LoadingIndicator />;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const { canEdit, userRole, currentUserId } = userPermissions;
|
|
189
|
-
|
|
190
|
-
return (
|
|
191
|
-
<div>
|
|
192
|
-
<div className="d-flex justify-content-between align-items-center mb-3">
|
|
193
|
-
<h6 className="mb-0">Group Members</h6>
|
|
194
|
-
<div className="d-flex align-items-center gap-2">
|
|
195
|
-
<div
|
|
196
|
-
className={`alert alert-${userRole ? "primary" : "warning"} py-2 px-3 mb-0 d-flex align-items-center`}
|
|
197
|
-
>
|
|
198
|
-
<i
|
|
199
|
-
className={`bi ${userRole ? "bi-person-badge" : "bi-exclamation-triangle"} me-2`}
|
|
200
|
-
></i>
|
|
201
|
-
<strong>Your role: {getRoleLabel(userRole)}</strong>
|
|
202
|
-
</div>
|
|
203
|
-
{/* Founder info - only show if current user is NOT the founder */}
|
|
204
|
-
{founderData && founderData.founderUserId !== currentUserId && (
|
|
205
|
-
<a
|
|
206
|
-
href={`#identity/people/${founderData.founderUserId}`}
|
|
207
|
-
className="alert alert-warning py-2 px-3 mb-0 d-flex align-items-center text-decoration-none"
|
|
208
|
-
style={{ cursor: "pointer" }}
|
|
209
|
-
>
|
|
210
|
-
<i className="bi bi-crown-fill me-2"></i>
|
|
211
|
-
<strong>Founder: {founderData.founderUser?.name || founderData.founderUserId}</strong>
|
|
212
|
-
</a>
|
|
213
|
-
)}
|
|
214
|
-
</div>
|
|
215
|
-
</div>
|
|
216
|
-
|
|
217
|
-
{/* Invite people - Only for admins/owners */}
|
|
218
|
-
{canEdit && (
|
|
219
|
-
<GroupInvitePanel
|
|
220
|
-
groupId={groupId}
|
|
221
|
-
excludeUserIds={membersData.map((m) => m.member.userId)}
|
|
222
|
-
myRole={userRole}
|
|
223
|
-
/>
|
|
224
|
-
)}
|
|
225
|
-
|
|
226
|
-
{!canEdit && userRole && (
|
|
227
|
-
<div className="alert alert-info">
|
|
228
|
-
<i className="bi bi-info-circle me-2"></i>
|
|
229
|
-
You can view group members, but only admins and owners can manage membership.
|
|
230
|
-
</div>
|
|
231
|
-
)}
|
|
232
|
-
|
|
233
|
-
{/* Members List */}
|
|
234
|
-
{membersData.length === 0 ? (
|
|
235
|
-
<div className="alert alert-info">No members in this group yet. Invite someone above.</div>
|
|
236
|
-
) : (
|
|
237
|
-
<div className="list-group">
|
|
238
|
-
{membersData.map(({ member, user }) => (
|
|
239
|
-
<div key={member.groupMemberId} className="list-group-item">
|
|
240
|
-
<div className="d-flex justify-content-between align-items-center">
|
|
241
|
-
<div className="flex-grow-1">
|
|
242
|
-
<div className="d-flex align-items-center">
|
|
243
|
-
<i className="bi bi-person-fill me-2"></i>
|
|
244
|
-
<div>
|
|
245
|
-
<div className="d-flex align-items-center">
|
|
246
|
-
<strong>
|
|
247
|
-
{user?.name || member.userId}
|
|
248
|
-
{member.userId === currentUserId && " (You)"}
|
|
249
|
-
</strong>
|
|
250
|
-
{user?.source === "userDataContext" && (
|
|
251
|
-
<span className="badge bg-info ms-2" style={{ fontSize: "0.7rem" }}>
|
|
252
|
-
<i className="bi bi-person me-1"></i>
|
|
253
|
-
Personal
|
|
254
|
-
</span>
|
|
255
|
-
)}
|
|
256
|
-
{user?.source === "otherDataContexts" && (
|
|
257
|
-
<span className="badge bg-secondary ms-2" style={{ fontSize: "0.7rem" }}>
|
|
258
|
-
<i className="bi bi-people me-1"></i>
|
|
259
|
-
Other Groups
|
|
260
|
-
</span>
|
|
261
|
-
)}
|
|
262
|
-
</div>
|
|
263
|
-
{user && user.userId !== user.name && (
|
|
264
|
-
<small className="text-muted d-block">{member.userId}</small>
|
|
265
|
-
)}
|
|
266
|
-
</div>
|
|
267
|
-
</div>
|
|
268
|
-
</div>
|
|
269
|
-
|
|
270
|
-
<div className="d-flex align-items-center">
|
|
271
|
-
<div className="me-2">
|
|
272
|
-
<TrustLevelBadge level={user?.trustLevel || TrustLevel.Unknown} />
|
|
273
|
-
</div>
|
|
274
|
-
|
|
275
|
-
{/* View button - Always visible */}
|
|
276
|
-
<a
|
|
277
|
-
href={`#identity/people/${member.userId}`}
|
|
278
|
-
className="btn btn-outline-primary btn-sm me-2"
|
|
279
|
-
>
|
|
280
|
-
<i className="bi-eye me-1" />
|
|
281
|
-
View
|
|
282
|
-
</a>
|
|
283
|
-
|
|
284
|
-
{canEdit ? (
|
|
285
|
-
<>
|
|
286
|
-
{/* Role Selector - Only for admins/owners */}
|
|
287
|
-
<select
|
|
288
|
-
className="form-select form-select-sm me-2"
|
|
289
|
-
style={{ width: "120px" }}
|
|
290
|
-
value={member.role}
|
|
291
|
-
onChange={(e) =>
|
|
292
|
-
updateRole(
|
|
293
|
-
member.groupMemberId,
|
|
294
|
-
Number(e.target.value) || (0 as GroupMemberRole),
|
|
295
|
-
)
|
|
296
|
-
}
|
|
297
|
-
>
|
|
298
|
-
<option value={GroupMemberRole.None}>None</option>
|
|
299
|
-
<option value={GroupMemberRole.Reader}>Reader</option>
|
|
300
|
-
<option value={GroupMemberRole.Writer}>Writer</option>
|
|
301
|
-
<option value={GroupMemberRole.Admin}>Admin</option>
|
|
302
|
-
<option value={GroupMemberRole.Owner}>Owner</option>
|
|
303
|
-
</select>
|
|
304
|
-
|
|
305
|
-
{/* Remove Button - Only for admins/owners */}
|
|
306
|
-
<button
|
|
307
|
-
className="btn btn-outline-danger btn-sm"
|
|
308
|
-
onClick={() => removeMember(member.groupMemberId)}
|
|
309
|
-
title="Remove member"
|
|
310
|
-
>
|
|
311
|
-
<i className="bi bi-trash"></i>
|
|
312
|
-
</button>
|
|
313
|
-
</>
|
|
314
|
-
) : (
|
|
315
|
-
/* Read-only role display for non-admins */
|
|
316
|
-
<span className="badge bg-secondary text-capitalize">
|
|
317
|
-
{getRoleLabel(member.role)}
|
|
318
|
-
</span>
|
|
319
|
-
)}
|
|
320
|
-
</div>
|
|
321
|
-
</div>
|
|
322
|
-
</div>
|
|
323
|
-
))}
|
|
324
|
-
</div>
|
|
325
|
-
)}
|
|
326
|
-
|
|
327
|
-
{/* Role Descriptions */}
|
|
328
|
-
<div className="mt-4">
|
|
329
|
-
<small className="text-muted">
|
|
330
|
-
<strong>Roles:</strong>
|
|
331
|
-
<br />
|
|
332
|
-
<strong>Reader:</strong> Can view group content
|
|
333
|
-
<br />
|
|
334
|
-
<strong>Writer:</strong> Can create and edit content
|
|
335
|
-
<br />
|
|
336
|
-
<strong>Admin:</strong> Can manage members and settings
|
|
337
|
-
<br />
|
|
338
|
-
<strong>Owner:</strong> Full control including group deletion
|
|
339
|
-
</small>
|
|
340
|
-
</div>
|
|
341
|
-
</div>
|
|
342
|
-
);
|
|
343
|
-
};
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
canonicalizeRoute,
|
|
3
|
-
IDENTITY_ACCEPT_PATH,
|
|
4
|
-
IDENTITY_ACCOUNT_PATH,
|
|
5
|
-
IDENTITY_ACTIVITY_PATH,
|
|
6
|
-
IDENTITY_DEVICES_PATH,
|
|
7
|
-
IDENTITY_GROUP_NEW_PATH,
|
|
8
|
-
IDENTITY_GROUPS_PATH,
|
|
9
|
-
IDENTITY_PAIR_PATH,
|
|
10
|
-
IDENTITY_PEOPLE_INVITE_PATH,
|
|
11
|
-
IDENTITY_PEOPLE_PATH,
|
|
12
|
-
IDENTITY_PEOPLE_SHARE_PATH,
|
|
13
|
-
identityActivityFilterPath,
|
|
14
|
-
identitySectionFromPath,
|
|
15
|
-
isIdentityPath,
|
|
16
|
-
parseIdentityLocation,
|
|
17
|
-
} from "./identity-routes";
|
|
18
|
-
|
|
19
|
-
const PERSON_ID = "abcdefghijklmnopqrstuvwxy";
|
|
20
|
-
const GROUP_ID = "zyxwvutsrqponmlkjihgfedcb";
|
|
21
|
-
const DEVICE_ID = "0123456789abcdefghijklmno";
|
|
22
|
-
|
|
23
|
-
describe("canonicalizeRoute", () => {
|
|
24
|
-
it.each([
|
|
25
|
-
["contacts", IDENTITY_PEOPLE_PATH],
|
|
26
|
-
[`contacts/${PERSON_ID}`, `${IDENTITY_PEOPLE_PATH}/${PERSON_ID}`],
|
|
27
|
-
["groups", IDENTITY_GROUPS_PATH],
|
|
28
|
-
[`groups/${GROUP_ID}`, `${IDENTITY_GROUPS_PATH}/${GROUP_ID}`],
|
|
29
|
-
["devices", IDENTITY_DEVICES_PATH],
|
|
30
|
-
[`devices/${DEVICE_ID}`, `${IDENTITY_DEVICES_PATH}/${DEVICE_ID}`],
|
|
31
|
-
["devices?action=pair", IDENTITY_PAIR_PATH],
|
|
32
|
-
["devices?action=pair&foo=bar", `${IDENTITY_PAIR_PATH}?foo=bar`],
|
|
33
|
-
["invites", IDENTITY_ACTIVITY_PATH],
|
|
34
|
-
["invites/accept", IDENTITY_ACCEPT_PATH],
|
|
35
|
-
["account", IDENTITY_ACCOUNT_PATH],
|
|
36
|
-
["account?x=1", `${IDENTITY_ACCOUNT_PATH}?x=1`],
|
|
37
|
-
["identity/account", IDENTITY_ACCOUNT_PATH],
|
|
38
|
-
["identity/people/invite", IDENTITY_PEOPLE_INVITE_PATH],
|
|
39
|
-
["identity/people/SHARE", IDENTITY_PEOPLE_SHARE_PATH],
|
|
40
|
-
["identity/groups/new", IDENTITY_GROUP_NEW_PATH],
|
|
41
|
-
["identity", IDENTITY_ACTIVITY_PATH],
|
|
42
|
-
[`/#contacts/${PERSON_ID}?x=1`, `${IDENTITY_PEOPLE_PATH}/${PERSON_ID}?x=1`],
|
|
43
|
-
["tools/abc", "tools/abc"],
|
|
44
|
-
["", ""],
|
|
45
|
-
])("rewrites %s to %s", (input, expected) => {
|
|
46
|
-
expect(canonicalizeRoute(input)).toBe(expected);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe("parseIdentityLocation", () => {
|
|
51
|
-
it("parses detail routes and activity filters", () => {
|
|
52
|
-
expect(parseIdentityLocation(`contacts/${PERSON_ID}`)?.personId).toBe(PERSON_ID);
|
|
53
|
-
expect(parseIdentityLocation(`groups/${GROUP_ID}`)?.groupId).toBe(GROUP_ID);
|
|
54
|
-
expect(parseIdentityLocation("devices?action=pair")?.pairing).toBe(true);
|
|
55
|
-
expect(parseIdentityLocation(`devices/${DEVICE_ID}`)?.deviceId).toBe(DEVICE_ID);
|
|
56
|
-
expect(parseIdentityLocation("invites/accept")?.accepting).toBe(true);
|
|
57
|
-
expect(parseIdentityLocation(IDENTITY_PEOPLE_INVITE_PATH)?.peopleAction).toBe("invite");
|
|
58
|
-
expect(parseIdentityLocation(IDENTITY_PEOPLE_SHARE_PATH)?.peopleAction).toBe("share");
|
|
59
|
-
expect(parseIdentityLocation(IDENTITY_GROUP_NEW_PATH)?.creatingGroup).toBe(true);
|
|
60
|
-
expect(
|
|
61
|
-
parseIdentityLocation(identityActivityFilterPath("group", GROUP_ID))?.activityFilter,
|
|
62
|
-
).toEqual({
|
|
63
|
-
type: "group",
|
|
64
|
-
groupId: GROUP_ID,
|
|
65
|
-
});
|
|
66
|
-
expect(identitySectionFromPath("contacts")).toBe("people");
|
|
67
|
-
expect(identitySectionFromPath("account")).toBe("account");
|
|
68
|
-
expect(isIdentityPath("settings")).toBe(false);
|
|
69
|
-
});
|
|
70
|
-
});
|