@agimon-ai/po-template-advanced 0.0.0-alpha.74 → 0.0.0-alpha.76

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.
@@ -3,8 +3,8 @@ import { View } from "react-native-unistyles/components/native/View";
3
3
  import { Text } from "react-native-unistyles/components/native/Text";
4
4
  import { SectionList } from "react-native-unistyles/components/native/SectionList";
5
5
  import { Pressable } from "react-native-unistyles/components/native/Pressable";
6
- import { ActivityIcon, AlertIcon, Badge, BranchIcon, Button, CheckIcon, CountBadge, EditIcon, EmptyState, FolderIcon, ForkIcon, HostTag, InfoStrip, Input, KebabIcon, Label, ListRow, LiveDuration, PlusIcon, Sheet, SheetBody, SheetContent, SheetHeader, SheetTitle, Spinner, Textarea, TrashIcon, UsersIcon, fontOf } from "@agimon-ai/po-native-components";
7
- import { useCallback, useEffect, useMemo, useState } from "react";
6
+ import { ActivityIcon, AlertIcon, Badge, BranchIcon, Button, CheckIcon, CountBadge, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, EditIcon, EmptyState, FolderIcon, ForkIcon, HostTag, InfoStrip, Input, KebabIcon, Label, ListRow, LiveDuration, PlusIcon, Sheet, SheetBody, SheetContent, SheetHeader, SheetTitle, Spinner, Textarea, TrashIcon, UsersIcon, fontOf } from "@agimon-ai/po-native-components";
7
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
8
8
  import { StyleSheet } from "react-native-unistyles";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
10
  /** Every group some session uses, in rail order, with the other sessions in it. */
@@ -1351,8 +1351,9 @@ function sessionSections(workspaces, presentation, selectedHost = null) {
1351
1351
  return filter === null || owner === filter;
1352
1352
  });
1353
1353
  const sections = [];
1354
- for (const workspace of visible) {
1355
- const existing = presentation && presentation.hosts.length > 1 && !workspace.legacy ? sections.find((section) => !section.workspace.legacy && section.workspace.name === workspace.name) : void 0;
1354
+ for (const workspace of [...visible.filter((item) => item.kind === "session"), ...visible.filter((item) => item.kind !== "session")]) {
1355
+ if (workspace.kind === "session" && workspace.sessions.length === 0) continue;
1356
+ const existing = workspace.kind === "session" ? sections.find((section) => section.workspace.kind === "session") : presentation && presentation.hosts.length > 1 && !workspace.legacy ? sections.find((section) => section.workspace.kind !== "session" && !section.workspace.legacy && section.workspace.name === workspace.name) : void 0;
1356
1357
  if (existing) {
1357
1358
  existing.members.push(workspace);
1358
1359
  existing.data = [...existing.data, ...workspace.sessions];
@@ -1369,6 +1370,28 @@ function sessionSections(workspaces, presentation, selectedHost = null) {
1369
1370
  }
1370
1371
  return sections;
1371
1372
  }
1373
+ function SessionCreateMenu({ onCreateWorkspace, onCreateSession, workspaceDisabled = false, sessionDisabled = false, defaultOpen = false }) {
1374
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
1375
+ defaultOpen,
1376
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
1377
+ variant: "ghost",
1378
+ size: "icon",
1379
+ accessibilityLabel: "Create workspace or session",
1380
+ children: /* @__PURE__ */ jsx(PlusIcon, {
1381
+ size: 18,
1382
+ color: "dim"
1383
+ })
1384
+ }), /* @__PURE__ */ jsxs(DropdownMenuContent, { children: [onCreateWorkspace ? /* @__PURE__ */ jsx(DropdownMenuItem, {
1385
+ disabled: workspaceDisabled,
1386
+ onSelect: onCreateWorkspace,
1387
+ children: "Create workspace"
1388
+ }) : null, onCreateSession ? /* @__PURE__ */ jsx(DropdownMenuItem, {
1389
+ disabled: sessionDisabled,
1390
+ onSelect: onCreateSession,
1391
+ children: "Create session"
1392
+ }) : null] })]
1393
+ });
1394
+ }
1372
1395
  /** The cockpit's workspace groups, with computers as a display filter rather than separate rails. */
1373
1396
  function AdvancedSessions({ workspaces, openSession, actions, setHeaderAction, hostPresentation }) {
1374
1397
  const [selectedHost, setSelectedHost] = useState(hostPresentation?.initialHostId ?? null);
@@ -1408,24 +1431,43 @@ function AdvancedSessions({ workspaces, openSession, actions, setHeaderAction, h
1408
1431
  }
1409
1432
  setAdding(true);
1410
1433
  }, [hosts]);
1411
- const titleAdd = canAdd && setHeaderAction !== void 0;
1434
+ const generalAction = useRef(actions.createGeneralSession);
1435
+ useEffect(() => {
1436
+ generalAction.current = actions.createGeneralSession;
1437
+ }, [actions.createGeneralSession]);
1438
+ const canGeneral = hosts.length > 0 ? hosts.some((host) => host.createGeneralSession !== void 0) : actions.createGeneralSession !== void 0;
1439
+ const beginGeneral = useCallback(() => {
1440
+ const host = hosts.find((host) => host.id === selected) ?? (hosts.length === 1 ? hosts[0] : void 0);
1441
+ if (host) {
1442
+ if (host.status === "connected") host.createGeneralSession?.();
1443
+ } else if (hosts.length > 1) setChoosing("general");
1444
+ else generalAction.current?.();
1445
+ }, [hosts, selected]);
1446
+ const workspaceDisabled = hosts.length === 1 && hosts[0].status !== "connected";
1447
+ const generalHost = hosts.find((host) => host.id === selected) ?? (hosts.length === 1 ? hosts[0] : void 0);
1448
+ const sessionDisabled = generalHost !== void 0 && (generalHost.status !== "connected" || generalHost.createGeneralSession === void 0);
1449
+ const createMenu = useMemo(() => /* @__PURE__ */ jsx(SessionCreateMenu, {
1450
+ onCreateWorkspace: canAdd ? beginAdd : void 0,
1451
+ onCreateSession: canGeneral ? beginGeneral : void 0,
1452
+ workspaceDisabled,
1453
+ sessionDisabled
1454
+ }), [
1455
+ canAdd,
1456
+ canGeneral,
1457
+ beginAdd,
1458
+ beginGeneral,
1459
+ workspaceDisabled,
1460
+ sessionDisabled
1461
+ ]);
1462
+ const titleAdd = (canGeneral || canAdd) && setHeaderAction !== void 0;
1412
1463
  useEffect(() => {
1413
1464
  if (!titleAdd) return;
1414
- setHeaderAction(/* @__PURE__ */ jsx(IconButton, {
1415
- label: "Add workspace",
1416
- onPress: beginAdd,
1417
- disabled: hosts.length === 1 && hosts[0].status !== "connected",
1418
- children: /* @__PURE__ */ jsx(PlusIcon, {
1419
- size: 18,
1420
- color: "dim"
1421
- })
1422
- }));
1465
+ setHeaderAction(createMenu);
1423
1466
  return () => setHeaderAction(null);
1424
1467
  }, [
1425
1468
  titleAdd,
1426
1469
  setHeaderAction,
1427
- beginAdd,
1428
- hosts
1470
+ createMenu
1429
1471
  ]);
1430
1472
  const sessions = workspaces.flatMap((workspace) => workspace.sessions).filter((session) => !stale(session.id));
1431
1473
  const { setSessionGroups, renameGroup, deleteGroup, removePendingSetup } = actions;
@@ -1445,7 +1487,7 @@ function AdvancedSessions({ workspaces, openSession, actions, setHeaderAction, h
1445
1487
  initialNumToRender: 12,
1446
1488
  maxToRenderPerBatch: 12,
1447
1489
  windowSize: 5,
1448
- renderSectionHeader: ({ section }) => /* @__PURE__ */ jsx(WorkspaceHeader, {
1490
+ renderSectionHeader: ({ section }) => section.workspace.kind === "session" ? null : /* @__PURE__ */ jsx(WorkspaceHeader, {
1449
1491
  workspace: section.workspace,
1450
1492
  actions,
1451
1493
  onWorkspaceMenu: (entry) => {
@@ -1483,7 +1525,7 @@ function AdvancedSessions({ workspaces, openSession, actions, setHeaderAction, h
1483
1525
  }),
1484
1526
  ListEmptyComponent: /* @__PURE__ */ jsx(EmptyState, {
1485
1527
  title: selected ? "No sessions on this computer." : "No sessions yet.",
1486
- description: "Add a workspace to start working with Po."
1528
+ description: canGeneral ? "Start a session to work with Po. No workspace needed." : "Add a workspace to start working with Po."
1487
1529
  }),
1488
1530
  ListHeaderComponent: /* @__PURE__ */ jsxs(View, {
1489
1531
  style: styles.listHeader,
@@ -1491,15 +1533,7 @@ function AdvancedSessions({ workspaces, openSession, actions, setHeaderAction, h
1491
1533
  message: host.status === "update_required" ? `${host.label} needs an app update. Sessions are read-only.` : `${host.label} is offline. Showing last known sessions.`,
1492
1534
  actionLabel: "Retry",
1493
1535
  onAction: host.onRetry
1494
- }, host.id)), canAdd && !titleAdd ? /* @__PURE__ */ jsxs(Button, {
1495
- variant: "ghost",
1496
- onPress: beginAdd,
1497
- disabled: hosts.length === 1 && hosts[0].status !== "connected",
1498
- children: [/* @__PURE__ */ jsx(PlusIcon, {
1499
- size: 18,
1500
- color: "dim"
1501
- }), "Add workspace"]
1502
- }) : null]
1536
+ }, host.id)), (canGeneral || canAdd) && !titleAdd ? createMenu : null]
1503
1537
  })
1504
1538
  }),
1505
1539
  /* @__PURE__ */ jsx(SessionMenuSheet, {
@@ -1537,7 +1571,15 @@ function AdvancedSessions({ workspaces, openSession, actions, setHeaderAction, h
1537
1571
  onOpenChange: (open) => {
1538
1572
  if (!open) setChoosing(null);
1539
1573
  },
1540
- children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: "Which computer?" }) }), /* @__PURE__ */ jsx(SheetBody, { children: choosing === "add" ? hosts.map((host) => /* @__PURE__ */ jsxs(Button, {
1574
+ children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: "Which computer?" }) }), /* @__PURE__ */ jsx(SheetBody, { children: choosing === "general" ? hosts.map((host) => /* @__PURE__ */ jsxs(Button, {
1575
+ variant: "ghost",
1576
+ disabled: host.status !== "connected" || !host.createGeneralSession,
1577
+ onPress: () => {
1578
+ setChoosing(null);
1579
+ host.createGeneralSession?.();
1580
+ },
1581
+ children: [host.label, host.status !== "connected" ? " · Unavailable" : ""]
1582
+ }, host.id)) : choosing === "add" ? hosts.map((host) => /* @__PURE__ */ jsxs(Button, {
1541
1583
  variant: "ghost",
1542
1584
  disabled: host.status !== "connected" || !host.addWorkspaceActions,
1543
1585
  onPress: () => {
@@ -1566,7 +1608,7 @@ function AdvancedSessions({ workspaces, openSession, actions, setHeaderAction, h
1566
1608
  }
1567
1609
  function sectionPath(sessionId, workspaces, sections) {
1568
1610
  const section = sections.find((entry) => entry.data.some(({ id }) => id === sessionId));
1569
- if (!section || new Set(section.members.map(({ root }) => root)).size < 2) return void 0;
1611
+ if (!section || section.workspace.kind === "session" || new Set(section.members.map(({ root }) => root)).size < 2) return void 0;
1570
1612
  return workspaces.find((workspace) => workspace.sessions.some(({ id }) => id === sessionId))?.root;
1571
1613
  }
1572
1614
  const styles = StyleSheet.create((theme) => {