@peers-app/peers-ui 0.25.2 → 0.25.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/README.md +2 -1
  2. package/dist/components/markdown-editor/mention-node.d.ts +4 -0
  3. package/dist/components/markdown-editor/mention-node.js +4 -1
  4. package/dist/components/responsive-section-nav.d.ts +34 -0
  5. package/dist/components/responsive-section-nav.js +19 -0
  6. package/dist/components/responsive-section-nav.test.d.ts +1 -0
  7. package/dist/components/responsive-section-nav.test.js +45 -0
  8. package/dist/components/router.d.ts +2 -3
  9. package/dist/components/router.js +6 -9
  10. package/dist/globals-hash.test.d.ts +1 -0
  11. package/dist/globals-hash.test.js +16 -0
  12. package/dist/globals.d.ts +19 -0
  13. package/dist/globals.js +51 -12
  14. package/dist/hooks/use-host-contract.d.ts +18 -0
  15. package/dist/hooks/use-host-contract.js +53 -0
  16. package/dist/index.d.ts +1 -0
  17. package/dist/index.js +1 -0
  18. package/dist/peers-services-registration.d.ts +1 -5
  19. package/dist/peers-services-registration.js +6 -16
  20. package/dist/root-layout/root-layout-host.js +7 -4
  21. package/dist/root-layout/root-layout-host.test.js +3 -6
  22. package/dist/screens/account/account-screen.d.ts +1 -0
  23. package/dist/screens/account/account-screen.js +29 -53
  24. package/dist/screens/account/account-screen.test.d.ts +1 -0
  25. package/dist/screens/account/account-screen.test.js +47 -0
  26. package/dist/screens/contacts/contact-details.js +2 -23
  27. package/dist/screens/contacts/contact-list.d.ts +24 -1
  28. package/dist/screens/contacts/contact-list.js +128 -143
  29. package/dist/screens/contacts/contact-list.test.d.ts +1 -0
  30. package/dist/screens/contacts/contact-list.test.js +48 -0
  31. package/dist/screens/contacts/index.d.ts +0 -2
  32. package/dist/screens/contacts/index.js +0 -3
  33. package/dist/screens/device-pairing/device-pairing.js +17 -16
  34. package/dist/screens/device-pairing/device-pairing.test.js +4 -9
  35. package/dist/screens/device-pairing/identity-ipc.d.ts +11 -0
  36. package/dist/screens/device-pairing/identity-ipc.js +20 -0
  37. package/dist/screens/device-pairing/use-device-pairing-state.d.ts +2 -2
  38. package/dist/screens/device-pairing/use-device-pairing-state.js +7 -25
  39. package/dist/screens/devices/devices-list.d.ts +18 -0
  40. package/dist/screens/devices/devices-list.js +173 -0
  41. package/dist/screens/devices/devices-list.test.d.ts +1 -0
  42. package/dist/screens/devices/devices-list.test.js +53 -0
  43. package/dist/screens/devices/index.d.ts +1 -0
  44. package/dist/screens/devices/index.js +5 -0
  45. package/dist/screens/groups/group-details.d.ts +1 -0
  46. package/dist/screens/groups/group-details.js +4 -63
  47. package/dist/screens/groups/group-invite-panel.js +2 -2
  48. package/dist/screens/groups/group-list.d.ts +18 -1
  49. package/dist/screens/groups/group-list.js +107 -136
  50. package/dist/screens/groups/group-list.test.d.ts +1 -0
  51. package/dist/screens/groups/group-list.test.js +38 -0
  52. package/dist/screens/groups/group-members.d.ts +1 -0
  53. package/dist/screens/groups/group-members.js +2 -1
  54. package/dist/screens/groups/index.d.ts +0 -3
  55. package/dist/screens/groups/index.js +0 -4
  56. package/dist/screens/identity/identity-routes.d.ts +107 -0
  57. package/dist/screens/identity/identity-routes.js +245 -0
  58. package/dist/screens/identity/identity-routes.test.d.ts +1 -0
  59. package/dist/screens/identity/identity-routes.test.js +51 -0
  60. package/dist/screens/identity/identity-screen.d.ts +9 -0
  61. package/dist/screens/identity/identity-screen.js +143 -0
  62. package/dist/screens/identity/identity-screen.test.d.ts +1 -0
  63. package/dist/screens/identity/identity-screen.test.js +103 -0
  64. package/dist/screens/identity/index.d.ts +2 -0
  65. package/dist/screens/identity/index.js +6 -0
  66. package/dist/screens/identity/invite-contact-panel.d.ts +4 -0
  67. package/dist/screens/identity/invite-contact-panel.js +30 -0
  68. package/dist/screens/identity/profile-invite.d.ts +7 -0
  69. package/dist/screens/identity/profile-invite.js +62 -0
  70. package/dist/screens/invites/accept-invite.js +1 -1
  71. package/dist/screens/invites/activity-view.d.ts +24 -0
  72. package/dist/screens/invites/activity-view.js +64 -0
  73. package/dist/screens/invites/activity-view.test.d.ts +1 -0
  74. package/dist/screens/invites/activity-view.test.js +108 -0
  75. package/dist/screens/invites/index.d.ts +1 -2
  76. package/dist/screens/invites/index.js +1 -3
  77. package/dist/screens/invites/invite-capture.d.ts +0 -2
  78. package/dist/screens/invites/invite-capture.js +1 -3
  79. package/dist/screens/invites/invite-classify.test.d.ts +1 -0
  80. package/dist/screens/invites/invite-classify.test.js +98 -0
  81. package/dist/screens/invites/invites-ipc.d.ts +1 -1
  82. package/dist/screens/invites/invites-ipc.js +5 -45
  83. package/dist/screens/invites/pending-invites-list.d.ts +35 -16
  84. package/dist/screens/invites/pending-invites-list.js +69 -30
  85. package/dist/screens/network-viewer/network-viewer-ipc.js +4 -59
  86. package/dist/screens/search/global-search.d.ts +1 -0
  87. package/dist/screens/search/global-search.js +2 -1
  88. package/dist/screens/settings/settings-page.js +25 -58
  89. package/dist/screens/setup-user.js +5 -5
  90. package/dist/screens/tools/tool-access-ipc.d.ts +2 -0
  91. package/dist/screens/tools/tool-access-ipc.js +8 -55
  92. package/dist/screens/welcome-modal.js +3 -2
  93. package/dist/system-apps/identity.app.d.ts +3 -0
  94. package/dist/system-apps/identity.app.js +10 -0
  95. package/dist/system-apps/index.d.ts +1 -4
  96. package/dist/system-apps/index.js +5 -17
  97. package/dist/tabs-layout/network-status-indicator.js +10 -3
  98. package/dist/tabs-layout/network-status-indicator.test.js +15 -0
  99. package/dist/tabs-layout/tabs-layout.js +3 -1
  100. package/dist/tabs-layout/tabs-state.d.ts +79 -1
  101. package/dist/tabs-layout/tabs-state.js +256 -79
  102. package/dist/tabs-layout/tabs-state.test.d.ts +1 -0
  103. package/dist/tabs-layout/tabs-state.test.js +110 -0
  104. package/package.json +3 -3
  105. package/src/components/markdown-editor/mention-node.ts +5 -1
  106. package/src/components/responsive-section-nav.test.tsx +88 -0
  107. package/src/components/responsive-section-nav.tsx +92 -0
  108. package/src/components/router.tsx +6 -9
  109. package/src/globals-hash.test.ts +19 -0
  110. package/src/globals.tsx +53 -13
  111. package/src/hooks/use-host-contract.ts +75 -0
  112. package/src/index.tsx +1 -0
  113. package/src/peers-services-registration.ts +6 -17
  114. package/src/root-layout/root-layout-host.test.tsx +4 -7
  115. package/src/root-layout/root-layout-host.tsx +9 -11
  116. package/src/screens/account/account-screen.test.tsx +61 -0
  117. package/src/screens/account/account-screen.tsx +116 -95
  118. package/src/screens/contacts/contact-details.tsx +4 -26
  119. package/src/screens/contacts/contact-list.test.tsx +59 -0
  120. package/src/screens/contacts/contact-list.tsx +246 -260
  121. package/src/screens/contacts/index.ts +0 -4
  122. package/src/screens/device-pairing/device-pairing.test.tsx +7 -9
  123. package/src/screens/device-pairing/device-pairing.tsx +19 -23
  124. package/src/screens/device-pairing/identity-ipc.ts +25 -0
  125. package/src/screens/device-pairing/use-device-pairing-state.ts +10 -33
  126. package/src/screens/devices/devices-list.test.tsx +68 -0
  127. package/src/screens/devices/devices-list.tsx +361 -0
  128. package/src/screens/devices/index.ts +1 -0
  129. package/src/screens/groups/group-details.tsx +8 -142
  130. package/src/screens/groups/group-invite-panel.tsx +2 -7
  131. package/src/screens/groups/group-list.test.tsx +44 -0
  132. package/src/screens/groups/group-list.tsx +227 -288
  133. package/src/screens/groups/group-members.tsx +3 -2
  134. package/src/screens/groups/index.ts +0 -5
  135. package/src/screens/identity/identity-routes.test.ts +70 -0
  136. package/src/screens/identity/identity-routes.ts +301 -0
  137. package/src/screens/identity/identity-screen.test.tsx +138 -0
  138. package/src/screens/identity/identity-screen.tsx +282 -0
  139. package/src/screens/identity/index.ts +2 -0
  140. package/src/screens/identity/invite-contact-panel.tsx +45 -0
  141. package/src/screens/identity/profile-invite.tsx +93 -0
  142. package/src/screens/invites/accept-invite.tsx +1 -1
  143. package/src/screens/invites/activity-view.test.tsx +127 -0
  144. package/src/screens/invites/activity-view.tsx +162 -0
  145. package/src/screens/invites/index.ts +1 -4
  146. package/src/screens/invites/invite-capture.ts +0 -3
  147. package/src/screens/invites/invite-classify.test.ts +110 -0
  148. package/src/screens/invites/invites-ipc.ts +6 -55
  149. package/src/screens/invites/pending-invites-list.tsx +85 -61
  150. package/src/screens/network-viewer/network-viewer-ipc.ts +8 -82
  151. package/src/screens/search/global-search.tsx +2 -1
  152. package/src/screens/settings/settings-page.tsx +53 -126
  153. package/src/screens/setup-user.tsx +5 -6
  154. package/src/screens/tools/tool-access-ipc.ts +13 -74
  155. package/src/screens/welcome-modal.tsx +3 -3
  156. package/src/system-apps/identity.app.ts +9 -0
  157. package/src/system-apps/index.ts +3 -12
  158. package/src/tabs-layout/network-status-indicator.test.tsx +22 -0
  159. package/src/tabs-layout/network-status-indicator.tsx +31 -0
  160. package/src/tabs-layout/tabs-layout.tsx +7 -1
  161. package/src/tabs-layout/tabs-state.test.ts +152 -0
  162. package/src/tabs-layout/tabs-state.ts +300 -83
  163. package/dist/screens/invites/invites-screen.d.ts +0 -9
  164. package/dist/screens/invites/invites-screen.js +0 -36
  165. package/dist/system-apps/account.app.d.ts +0 -2
  166. package/dist/system-apps/account.app.js +0 -8
  167. package/dist/system-apps/contacts.app.d.ts +0 -2
  168. package/dist/system-apps/contacts.app.js +0 -9
  169. package/dist/system-apps/groups.app.d.ts +0 -2
  170. package/dist/system-apps/groups.app.js +0 -9
  171. package/dist/system-apps/invites.app.d.ts +0 -2
  172. package/dist/system-apps/invites.app.js +0 -9
  173. package/src/screens/invites/invites-screen.tsx +0 -78
  174. package/src/system-apps/account.app.ts +0 -7
  175. package/src/system-apps/contacts.app.ts +0 -8
  176. package/src/system-apps/groups.app.ts +0 -8
  177. package/src/system-apps/invites.app.ts +0 -8
@@ -1,7 +1,5 @@
1
1
  import {
2
- copyToClipboard,
3
2
  Groups,
4
- generateGroupShare,
5
3
  getIconClassName,
6
4
  getUserContext,
7
5
  type IDoc,
@@ -10,22 +8,20 @@ import {
10
8
  rpcServerCalls,
11
9
  sleep,
12
10
  } from "@peers-app/peers-sdk";
13
- import { useState } from "react";
14
11
  import { Checkbox } from "../../components/checkbox";
15
12
  import { Input } from "../../components/input";
16
13
  import { LoadingIndicator } from "../../components/loading-indicator";
17
14
  import { MarkdownEditorInline } from "../../components/markdown-editor/editor-inline";
18
15
  import { SaveButton } from "../../components/save-button";
19
- import { ScreenTabBody, Tabs } from "../../components/tabs";
16
+ import { Tabs } from "../../components/tabs";
20
17
  import { usePromise } from "../../hooks";
21
- import { updateActiveTabTitle } from "../../tabs-layout/tabs-state";
22
- import { registerInternalPeersUI } from "../../ui-router/ui-loader";
23
18
  import { GroupMembersUI } from "./group-members";
24
19
 
25
20
  interface IProps {
26
21
  groupId: string;
27
22
  }
28
23
 
24
+ /** Edit group metadata and manage members and invitations inside Identity. */
29
25
  export const GroupDetails = (props: IProps) => {
30
26
  const group = usePromise(
31
27
  async () => {
@@ -35,7 +31,6 @@ export const GroupDetails = (props: IProps) => {
35
31
  if (!group) {
36
32
  throw new Error("Group not found");
37
33
  }
38
- updateActiveTabTitle(group.name || "Group");
39
34
  const groupDoc = userGroupTable.initDoc(group);
40
35
  // saves go to both the group and user db
41
36
  groupDoc.save = async () => {
@@ -66,7 +61,7 @@ export const GroupDetails = (props: IProps) => {
66
61
  }
67
62
 
68
63
  return (
69
- <div className="container-fluid p-3">
64
+ <div className="container-xxl p-3">
70
65
  <div className="d-flex">
71
66
  <div>
72
67
  <h4>
@@ -83,10 +78,7 @@ export const GroupDetails = (props: IProps) => {
83
78
  />
84
79
  </h4>
85
80
  </div>
86
- <div className="d-flex gap-2">
87
- <ShareButton groupId={props.groupId} />
88
- <SaveButton key={group.groupId} doc={group} />
89
- </div>
81
+ <SaveButton key={group.groupId} doc={group} />
90
82
  </div>
91
83
 
92
84
  <Tabs
@@ -95,17 +87,17 @@ export const GroupDetails = (props: IProps) => {
95
87
  {
96
88
  name: "Info",
97
89
  content: (
98
- <ScreenTabBody>
90
+ <div>
99
91
  <GroupInfo group={group} />
100
- </ScreenTabBody>
92
+ </div>
101
93
  ),
102
94
  },
103
95
  {
104
96
  name: "Members",
105
97
  content: (
106
- <ScreenTabBody>
98
+ <div>
107
99
  <GroupMembersWrapper groupId={props.groupId} />
108
- </ScreenTabBody>
100
+ </div>
109
101
  ),
110
102
  },
111
103
  ]}
@@ -160,135 +152,9 @@ const GroupInfo = (props: { group: IDoc<IGroup> }) => {
160
152
  );
161
153
  };
162
154
 
163
- const ShareButton = ({ groupId }: { groupId: string }) => {
164
- const [isSharing, setIsSharing] = useState(false);
165
- const [shareResult, setShareResult] = useState<{
166
- success: boolean;
167
- message: string;
168
- } | null>(null);
169
-
170
- const handleShare = async () => {
171
- setIsSharing(true);
172
- setShareResult(null);
173
-
174
- try {
175
- // Generate the group share data
176
- const groupShare = await generateGroupShare(groupId);
177
-
178
- // Convert to JSON
179
- const groupShareJson = JSON.stringify(groupShare, null, 2);
180
-
181
- // Copy to clipboard
182
- const copied = await copyToClipboard(groupShareJson);
183
-
184
- if (copied) {
185
- setShareResult({
186
- success: true,
187
- message: `Group share data copied to clipboard! (${groupShareJson.length} chars, ${groupShare.groupMembers.length} admin members)`,
188
- });
189
- } else {
190
- setShareResult({
191
- success: false,
192
- message: "Failed to copy to clipboard. Please copy manually from the modal.",
193
- });
194
- }
195
- } catch (error: unknown) {
196
- setShareResult({
197
- success: false,
198
- message: `Error generating share: ${error instanceof Error ? error.message : String(error)}`,
199
- });
200
- } finally {
201
- setIsSharing(false);
202
- }
203
- };
204
-
205
- return (
206
- <>
207
- <button
208
- className="btn btn-secondary btn-sm"
209
- onClick={handleShare}
210
- disabled={isSharing}
211
- title="Share group with admin members"
212
- >
213
- {isSharing ? (
214
- <>
215
- <span
216
- className="spinner-border spinner-border-sm me-1"
217
- role="status"
218
- aria-hidden="true"
219
- ></span>
220
- Sharing...
221
- </>
222
- ) : (
223
- <>
224
- <i className="bi-share me-1"></i>
225
- Share
226
- </>
227
- )}
228
- </button>
229
-
230
- {shareResult && (
231
- <div
232
- className="position-fixed top-0 start-0 w-100 h-100 d-flex align-items-center justify-content-center"
233
- style={{ backgroundColor: "rgba(0,0,0,0.5)", zIndex: 1050 }}
234
- >
235
- <div className="card" style={{ maxWidth: "500px", width: "90%" }}>
236
- <div className="card-header d-flex justify-content-between align-items-center">
237
- <h6 className="mb-0">
238
- <i
239
- className={`bi-${shareResult.success ? "check-circle text-success" : "exclamation-triangle text-warning"} me-2`}
240
- ></i>
241
- Group Share {shareResult.success ? "Ready" : "Error"}
242
- </h6>
243
- <button
244
- className="btn-close"
245
- onClick={() => setShareResult(null)}
246
- aria-label="Close"
247
- ></button>
248
- </div>
249
- <div className="card-body">
250
- <p className="mb-3">{shareResult.message}</p>
251
-
252
- <div className="text-end">
253
- <button className="btn btn-secondary me-2" onClick={() => setShareResult(null)}>
254
- Close
255
- </button>
256
- {shareResult.success && (
257
- <button className="btn btn-primary" onClick={handleShare}>
258
- Copy Again
259
- </button>
260
- )}
261
- </div>
262
- </div>
263
- </div>
264
- </div>
265
- )}
266
- </>
267
- );
268
- };
269
-
270
155
  const GroupMembersWrapper = (props: { groupId: string }) => {
271
156
  const userContext = usePromise(() => getUserContext());
272
157
  if (!userContext) return null;
273
158
 
274
159
  return <GroupMembersUI groupId={props.groupId} userContext={userContext} />;
275
160
  };
276
-
277
- registerInternalPeersUI({
278
- peersUIId: "00group00details00component",
279
- component: GroupDetails,
280
- routes: [
281
- {
282
- isMatch: (props, context) => {
283
- const match = context.path.match(/^groups\/([a-zA-Z0-9]{25})$/);
284
- if (match) {
285
- props.groupId = match[1];
286
- return true;
287
- }
288
- return false;
289
- },
290
- uiCategory: "screen",
291
- priority: 2,
292
- },
293
- ],
294
- });
@@ -7,9 +7,9 @@ import {
7
7
  } from "@peers-app/peers-sdk";
8
8
  import { useState } from "react";
9
9
  import { Typeahead, type TypeaheadItem } from "../../components/typeahead";
10
+ import { PendingWorkLink } from "../invites/activity-view";
10
11
  import { InviteShare } from "../invites/invite-share";
11
12
  import { inviteTools } from "../invites/invites-ipc";
12
- import { PendingInvitesList } from "../invites/pending-invites-list";
13
13
 
14
14
  /** Props for {@link GroupInvitePanel}. */
15
15
  export interface GroupInvitePanelProps {
@@ -305,12 +305,7 @@ export function GroupInvitePanel(props: GroupInvitePanelProps) {
305
305
  {tab === "contacts" ? <InviteContactsCard {...props} /> : <ShareLinkCard {...props} />}
306
306
  </div>
307
307
  </div>
308
- <PendingInvitesList
309
- type="group"
310
- groupId={props.groupId}
311
- hideWhenEmpty
312
- title="Pending invites and join requests"
313
- />
308
+ <PendingWorkLink type="group" groupId={props.groupId} />
314
309
  </>
315
310
  );
316
311
  }
@@ -0,0 +1,44 @@
1
+ import { GroupMemberRole } from "@peers-app/peers-sdk";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { GroupSummaryRow, type IGroupSummary } from "./group-list";
4
+
5
+ jest.mock("../../globals", () => ({
6
+ mainContentPath: jest.fn(),
7
+ }));
8
+
9
+ jest.mock("../../hooks", () => ({
10
+ usePromise: jest.fn(),
11
+ }));
12
+
13
+ jest.mock("../invites/activity-view", () => ({
14
+ PendingWorkLink: () => null,
15
+ }));
16
+
17
+ const summary: IGroupSummary = {
18
+ group: {
19
+ groupId: "zyxwvutsrqponmlkjihgfedcb",
20
+ name: "Neighborhood",
21
+ description: "**Local** projects and shared plans",
22
+ founderUserId: "abcdefghijklmnopqrstuvwxy",
23
+ publicKey: "signing-key",
24
+ publicBoxKey: "box-key",
25
+ signature: "signature",
26
+ },
27
+ memberCount: 7,
28
+ myRole: GroupMemberRole.Admin,
29
+ };
30
+
31
+ describe("GroupSummaryRow", () => {
32
+ it("shows description, member count, and local role in a clickable row", () => {
33
+ render(<GroupSummaryRow summary={summary} />);
34
+
35
+ expect(screen.getByText("Neighborhood")).toBeInTheDocument();
36
+ expect(screen.getByText("Local projects and shared plans")).toBeInTheDocument();
37
+ expect(screen.getByText("7 members")).toBeInTheDocument();
38
+ expect(screen.getByText("Admin")).toBeInTheDocument();
39
+ expect(screen.getByRole("link")).toHaveAttribute(
40
+ "href",
41
+ `#identity/groups/${summary.group.groupId}`,
42
+ );
43
+ });
44
+ });