@burdenoff/microfe-workspaces 2026.625.1 → 2026.625.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.
- package/dist/components/MemberListItem.js +7 -6
- package/dist/components/MemberListItem.js.map +1 -1
- package/dist/components/ProjectCard.js +13 -12
- package/dist/components/ProjectCard.js.map +1 -1
- package/dist/components/WorkspaceCard.js +8 -7
- package/dist/components/WorkspaceCard.js.map +1 -1
- package/dist/pages/ActivityListPage.js +67 -55
- package/dist/pages/ActivityListPage.js.map +1 -1
- package/dist/pages/CreateWorkspacePage.js +5 -4
- package/dist/pages/CreateWorkspacePage.js.map +1 -1
- package/dist/pages/InviteAcceptancePage.js +45 -36
- package/dist/pages/InviteAcceptancePage.js.map +1 -1
- package/dist/pages/MembersListPage.js +2 -2
- package/dist/pages/MembersListPage.js.map +1 -1
- package/dist/pages/PendingInvitesPage.js +68 -67
- package/dist/pages/PendingInvitesPage.js.map +1 -1
- package/dist/pages/ProjectDetailPage.js +333 -302
- package/dist/pages/ProjectDetailPage.js.map +1 -1
- package/dist/pages/ProjectMembersPage.js +4 -4
- package/dist/pages/ProjectMembersPage.js.map +1 -1
- package/dist/pages/ProjectsListPage.js +234 -226
- package/dist/pages/ProjectsListPage.js.map +1 -1
- package/dist/pages/WorkspaceDetailPage.js +196 -178
- package/dist/pages/WorkspaceDetailPage.js.map +1 -1
- package/dist/pages/WorkspaceInvitePage.js +372 -353
- package/dist/pages/WorkspaceInvitePage.js.map +1 -1
- package/dist/pages/WorkspaceSettingsPage.js +98 -90
- package/dist/pages/WorkspaceSettingsPage.js.map +1 -1
- package/dist/pages/WorkspacesListPage.js +132 -121
- package/dist/pages/WorkspacesListPage.js.map +1 -1
- package/dist/pages/dashboard/WidgetWrapper.js +7 -6
- package/dist/pages/dashboard/WidgetWrapper.js.map +1 -1
- package/dist/pages/dashboard/widgets/MembersWidget.js +1 -1
- package/dist/pages/dashboard/widgets/MembersWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WelcomeWidget.js +45 -37
- package/dist/pages/dashboard/widgets/WelcomeWidget.js.map +1 -1
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js +2 -2
- package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js.map +1 -1
- package/package.json +2 -2
|
@@ -5,7 +5,7 @@ import { formatRelativeTime as i } from "../utils/formatters.js";
|
|
|
5
5
|
import { useMemo as a, useState as o } from "react";
|
|
6
6
|
import { MoreHorizontal as s, UserMinus as c } from "lucide-react";
|
|
7
7
|
import { Fragment as l, jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
8
|
-
import { AlertDialog as f, AlertDialogAction as p, AlertDialogCancel as m, AlertDialogContent as h, AlertDialogDescription as g, AlertDialogFooter as _, AlertDialogHeader as v, AlertDialogTitle as y, Badge as b, Button as x,
|
|
8
|
+
import { AlertDialog as f, AlertDialogAction as p, AlertDialogCancel as m, AlertDialogContent as h, AlertDialogDescription as g, AlertDialogFooter as _, AlertDialogHeader as v, AlertDialogTitle as y, Badge as b, Button as x, CardContent as S, DropdownMenu as C, DropdownMenuContent as w, DropdownMenuTrigger as T, GlassCard as E } from "@burdenoff/fe-libs/ui";
|
|
9
9
|
import { ActorIdentity as D, useActorProfiles as O } from "@burdenoff/fe-libs/shared";
|
|
10
10
|
//#region src/components/MemberListItem.tsx
|
|
11
11
|
function k({ member: k, selected: A = !1, onToggleSelect: j, canRemove: M = !1 }) {
|
|
@@ -18,9 +18,10 @@ function k({ member: k, selected: A = !1, onToggleSelect: j, canRemove: M = !1 }
|
|
|
18
18
|
orgId: z,
|
|
19
19
|
workspaceId: k.workspaceId
|
|
20
20
|
})[k.userId];
|
|
21
|
-
return /* @__PURE__ */ d(l, { children: [/* @__PURE__ */ u(
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
return /* @__PURE__ */ d(l, { children: [/* @__PURE__ */ u(E, {
|
|
22
|
+
treatment: "plain",
|
|
23
|
+
className: `border-border-seam ${A ? "ring-2 ring-action-primary-bg/25 border-action-primary-bg/50" : ""}`,
|
|
24
|
+
children: /* @__PURE__ */ u(S, {
|
|
24
25
|
className: "p-4",
|
|
25
26
|
children: /* @__PURE__ */ d("div", {
|
|
26
27
|
className: "flex items-center justify-between gap-4",
|
|
@@ -49,7 +50,7 @@ function k({ member: k, selected: A = !1, onToggleSelect: j, canRemove: M = !1 }
|
|
|
49
50
|
})]
|
|
50
51
|
})]
|
|
51
52
|
})]
|
|
52
|
-
}), M && /* @__PURE__ */ d(
|
|
53
|
+
}), M && /* @__PURE__ */ d(C, { children: [/* @__PURE__ */ u(T, {
|
|
53
54
|
asChild: !0,
|
|
54
55
|
children: /* @__PURE__ */ d(x, {
|
|
55
56
|
variant: "ghost",
|
|
@@ -60,7 +61,7 @@ function k({ member: k, selected: A = !1, onToggleSelect: j, canRemove: M = !1 }
|
|
|
60
61
|
children: "Open member actions"
|
|
61
62
|
})]
|
|
62
63
|
})
|
|
63
|
-
}), /* @__PURE__ */ u(
|
|
64
|
+
}), /* @__PURE__ */ u(w, {
|
|
64
65
|
align: "end",
|
|
65
66
|
children: /* @__PURE__ */ d("button", {
|
|
66
67
|
type: "button",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemberListItem.js","names":[],"sources":["../../src/components/MemberListItem.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n
|
|
1
|
+
{"version":3,"file":"MemberListItem.js","names":[],"sources":["../../src/components/MemberListItem.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n GlassCard,\n CardContent,\n Button,\n Badge,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuTrigger,\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { MoreHorizontal, UserMinus } from 'lucide-react';\nimport { ActorIdentity, useActorProfiles, type ActorInput } from '@burdenoff/fe-libs/shared';\nimport { useRemoveWorkspaceMember } from '../hooks/useMemberMutations';\nimport { nativeImpact, nativeNotify } from '../utils/nativeBridge';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport type { WorkspaceMember } from '../types';\n\nexport interface MemberListItemProps {\n member: WorkspaceMember;\n onUpdateRoles?: (memberId: string, roleIds: string[]) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n canRemove?: boolean;\n}\n\nexport function MemberListItem({\n member,\n selected = false,\n onToggleSelect,\n canRemove = false,\n}: MemberListItemProps) {\n const [showRemoveDialog, setShowRemoveDialog] = useState(false);\n const { mutate: removeMember, isPending: isRemoving } = useRemoveWorkspaceMember(\n member.workspaceId\n );\n const { apiGatewayUrl, authToken, organizationId } = useWorkspacesContext();\n\n // Resolve userId → displayName + email via the shared actor profile cache.\n // UUIDs must never headline a row — the resolved identity goes in primary\n // position; the raw ID lives in the drill-down inside ActorIdentity.\n const actors = useMemo<ActorInput[]>(\n () => [{ actorId: member.userId, actorType: 'user' }],\n [member.userId]\n );\n const profileMap = useActorProfiles(actors, {\n apiGatewayUrl,\n authToken,\n orgId: organizationId,\n workspaceId: member.workspaceId,\n });\n const profile = profileMap[member.userId];\n\n const handleRemove = () => {\n void nativeImpact('medium');\n removeMember(member.id, {\n onSuccess: () => {\n void nativeNotify('success');\n setShowRemoveDialog(false);\n },\n onError: () => {\n void nativeNotify('error');\n },\n });\n };\n\n return (\n <>\n <GlassCard\n treatment=\"plain\"\n className={`border-border-seam ${\n selected ? 'ring-2 ring-action-primary-bg/25 border-action-primary-bg/50' : ''\n }`}\n >\n <CardContent className=\"p-4\">\n <div className=\"flex items-center justify-between gap-4\">\n <div className=\"flex items-center gap-3 flex-1 min-w-0\">\n {onToggleSelect && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(event) => onToggleSelect(event.target.checked)}\n className=\"size-4 rounded border-border-default text-action-primary-bg\"\n aria-label={`Select member ${profile?.displayName ?? ''}`}\n />\n )}\n\n <div className=\"flex-1 min-w-0\">\n {profile ? <ActorIdentity profile={profile} variant=\"cell\" /> : null}\n <div className=\"mt-1 flex items-center gap-2\">\n <Badge variant=\"secondary\" className=\"text-xs\">\n Workspace member\n </Badge>\n <span className=\"text-xs text-text-secondary\">\n Joined {formatRelativeTime(member.createdAt)}\n </span>\n </div>\n </div>\n </div>\n\n {canRemove && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"size-8 flex-shrink-0\">\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">Open member actions</span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <button\n type=\"button\"\n onClick={() => setShowRemoveDialog(true)}\n className=\"flex w-full items-center rounded-sm px-2 py-1.5 text-sm text-status-danger-text outline-none transition-colors hover:bg-action-ghost-bg-hover focus:bg-action-ghost-bg-hover\"\n >\n <UserMinus className=\"mr-2 size-4\" />\n Remove Member\n </button>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n </CardContent>\n </GlassCard>\n\n <AlertDialog open={showRemoveDialog} onOpenChange={setShowRemoveDialog}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Remove Member</AlertDialogTitle>\n <AlertDialogDescription>\n Are you sure you want to remove {profile?.displayName ?? 'this member'} from the\n workspace? This action cannot be undone.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isRemoving}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={handleRemove}\n disabled={isRemoving}\n className=\"bg-status-danger-bg text-status-danger-text hover:bg-status-danger-bg/90\"\n >\n {isRemoving ? 'Removing...' : 'Remove Member'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </>\n );\n}\n"],"mappings":";;;;;;;;;;AAkCA,SAAgB,EAAe,EAC7B,WACA,cAAW,IACX,mBACA,eAAY,MACU;CACtB,IAAM,CAAC,GAAkB,KAAuB,EAAS,GAAM,EACzD,EAAE,QAAQ,GAAc,WAAW,MAAe,EACtD,EAAO,YACR,EACK,EAAE,kBAAe,cAAW,sBAAmB,GAAsB,EAerE,IANa,EAJJ,QACP,CAAC;EAAE,SAAS,EAAO;EAAQ,WAAW;EAAQ,CAAC,EACrD,CAAC,EAAO,OAAO,CAChB,EAC2C;EAC1C;EACA;EACA,OAAO;EACP,aAAa,EAAO;EACrB,CAAC,CACyB,EAAO;AAelC,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EACE,WAAU;EACV,WAAW,sBACT,IAAW,iEAAiE;YAG9E,kBAAC,GAAD;GAAa,WAAU;aACrB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,KACC,kBAAC,SAAD;MACE,MAAK;MACL,SAAS;MACT,WAAW,MAAU,EAAe,EAAM,OAAO,QAAQ;MACzD,WAAU;MACV,cAAY,iBAAiB,GAAS,eAAe;MACrD,CAAA,EAGJ,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,IAAU,kBAAC,GAAD;OAAwB;OAAS,SAAQ;OAAS,CAAA,GAAG,MAChE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;QAAY,WAAU;kBAAU;QAEvC,CAAA,EACR,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CAA8C,WACpC,EAAmB,EAAO,UAAU,CACvC;UACH;SACF;QACF;QAEL,KACC,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAqB,SAAA;eACnB,kBAAC,GAAD;MAAQ,SAAQ;MAAQ,MAAK;MAAO,WAAU;gBAA9C,CACE,kBAAC,GAAD,EAAgB,WAAU,UAAW,CAAA,EACrC,kBAAC,QAAD;OAAM,WAAU;iBAAU;OAA0B,CAAA,CAC7C;;KACW,CAAA,EACtB,kBAAC,GAAD;KAAqB,OAAM;eACzB,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAoB,GAAK;MACxC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA,EAAA,gBAE9B;;KACW,CAAA,CACT,EAAA,CAAA,CAEb;;GACM,CAAA;EACJ,CAAA,EAEZ,kBAAC,GAAD;EAAa,MAAM;EAAkB,cAAc;YACjD,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAkB,iBAAgC,CAAA,EAClD,kBAAC,GAAD,EAAA,UAAA;GAAwB;GACW,GAAS,eAAe;GAAc;GAEhD,EAAA,CAAA,CACP,EAAA,CAAA,EACpB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GAAmB,UAAU;aAAY;GAA0B,CAAA,EACnE,kBAAC,GAAD;GACE,eAnFe;AAEzB,IADK,EAAa,SAAS,EAC3B,EAAa,EAAO,IAAI;KACtB,iBAAiB;AAEf,MADK,EAAa,UAAU,EAC5B,EAAoB,GAAM;;KAE5B,eAAe;AACR,QAAa,QAAQ;;KAE7B,CAAC;;GA0EQ,UAAU;GACV,WAAU;aAET,IAAa,gBAAgB;GACZ,CAAA,CACF,EAAA,CAAA,CACD,EAAA,CAAA;EACT,CAAA,CACb,EAAA,CAAA"}
|
|
@@ -7,7 +7,7 @@ import { formatDate as c } from "../utils/formatters.js";
|
|
|
7
7
|
import { getProjectDisplayTags as l } from "../utils/projectTags.js";
|
|
8
8
|
import { Archive as u, Fingerprint as d, FolderKanban as f, MoreVertical as p } from "lucide-react";
|
|
9
9
|
import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
10
|
-
import { Badge as _, Button as v,
|
|
10
|
+
import { Badge as _, Button as v, CardContent as y, CardHeader as b, CardTitle as x, DropdownMenu as S, DropdownMenuContent as C, DropdownMenuItem as w, DropdownMenuTrigger as T, EntityIdModal as E, GlassCard as D, useEntityIdModal as O } from "@burdenoff/fe-libs/ui";
|
|
11
11
|
import { useNavigate as k } from "react-router-dom";
|
|
12
12
|
import { TagBadge as A } from "@burdenoff/fe-libs/tag";
|
|
13
13
|
//#region src/components/ProjectCard.tsx
|
|
@@ -15,8 +15,9 @@ function j({ project: j, selected: M = !1, onToggleSelect: N, onTagClick: P, can
|
|
|
15
15
|
let L = k(), { basePath: R = "/workspaces" } = e(), { withCurrentSearch: z } = n(), { mutate: B } = a(j.workspaceId), { mutate: V } = s(j.workspaceId), { mutate: H } = o(j.workspaceId), U = O(), W = l(j), G = () => {
|
|
16
16
|
L(z(`${R}/${j.workspaceId}/projects/${j.id}`));
|
|
17
17
|
};
|
|
18
|
-
return /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ g(
|
|
19
|
-
|
|
18
|
+
return /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ g(D, {
|
|
19
|
+
treatment: "insight",
|
|
20
|
+
className: `cursor-pointer relative focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50 ${M ? "ring-2 ring-primary/25 border-primary/50" : ""}`,
|
|
20
21
|
onClick: G,
|
|
21
22
|
onKeyDown: (e) => {
|
|
22
23
|
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), G());
|
|
@@ -24,7 +25,7 @@ function j({ project: j, selected: M = !1, onToggleSelect: N, onTagClick: P, can
|
|
|
24
25
|
role: "button",
|
|
25
26
|
tabIndex: 0,
|
|
26
27
|
"aria-label": `Open project ${j.name}`,
|
|
27
|
-
children: [/* @__PURE__ */ h(
|
|
28
|
+
children: [/* @__PURE__ */ h(b, { children: /* @__PURE__ */ g("div", {
|
|
28
29
|
className: "flex items-start justify-between",
|
|
29
30
|
children: [/* @__PURE__ */ g("div", {
|
|
30
31
|
className: "flex items-center gap-3 flex-1",
|
|
@@ -46,7 +47,7 @@ function j({ project: j, selected: M = !1, onToggleSelect: N, onTagClick: P, can
|
|
|
46
47
|
}),
|
|
47
48
|
/* @__PURE__ */ g("div", {
|
|
48
49
|
className: "flex-1 min-w-0",
|
|
49
|
-
children: [/* @__PURE__ */ h(
|
|
50
|
+
children: [/* @__PURE__ */ h(x, {
|
|
50
51
|
className: "truncate",
|
|
51
52
|
children: j.name
|
|
52
53
|
}), /* @__PURE__ */ h("p", {
|
|
@@ -55,7 +56,7 @@ function j({ project: j, selected: M = !1, onToggleSelect: N, onTagClick: P, can
|
|
|
55
56
|
})]
|
|
56
57
|
})
|
|
57
58
|
]
|
|
58
|
-
}), /* @__PURE__ */ g(
|
|
59
|
+
}), /* @__PURE__ */ g(S, { children: [/* @__PURE__ */ h(T, {
|
|
59
60
|
asChild: !0,
|
|
60
61
|
onClick: (e) => e.stopPropagation(),
|
|
61
62
|
children: /* @__PURE__ */ g(v, {
|
|
@@ -67,10 +68,10 @@ function j({ project: j, selected: M = !1, onToggleSelect: N, onTagClick: P, can
|
|
|
67
68
|
children: "Open project actions"
|
|
68
69
|
})]
|
|
69
70
|
})
|
|
70
|
-
}), /* @__PURE__ */ g(
|
|
71
|
+
}), /* @__PURE__ */ g(C, {
|
|
71
72
|
align: "end",
|
|
72
73
|
children: [
|
|
73
|
-
/* @__PURE__ */ g(
|
|
74
|
+
/* @__PURE__ */ g(w, {
|
|
74
75
|
onClick: (e) => {
|
|
75
76
|
e.stopPropagation(), U.show({
|
|
76
77
|
id: j.id,
|
|
@@ -90,7 +91,7 @@ function j({ project: j, selected: M = !1, onToggleSelect: N, onTagClick: P, can
|
|
|
90
91
|
className: "mr-2"
|
|
91
92
|
}), "Get ID"]
|
|
92
93
|
}),
|
|
93
|
-
F && /* @__PURE__ */ g(
|
|
94
|
+
F && /* @__PURE__ */ g(w, {
|
|
94
95
|
onClick: (e) => {
|
|
95
96
|
e.stopPropagation(), j.archived ? V(j.id) : B(j.id);
|
|
96
97
|
},
|
|
@@ -99,7 +100,7 @@ function j({ project: j, selected: M = !1, onToggleSelect: N, onTagClick: P, can
|
|
|
99
100
|
className: "mr-2"
|
|
100
101
|
}), j.archived ? "Unarchive" : "Archive"]
|
|
101
102
|
}),
|
|
102
|
-
I && /* @__PURE__ */ h(
|
|
103
|
+
I && /* @__PURE__ */ h(w, {
|
|
103
104
|
onClick: async (e) => {
|
|
104
105
|
e.stopPropagation(), i("medium");
|
|
105
106
|
let t = await r({
|
|
@@ -115,7 +116,7 @@ function j({ project: j, selected: M = !1, onToggleSelect: N, onTagClick: P, can
|
|
|
115
116
|
})
|
|
116
117
|
]
|
|
117
118
|
})] })]
|
|
118
|
-
}) }), /* @__PURE__ */ g(
|
|
119
|
+
}) }), /* @__PURE__ */ g(y, {
|
|
119
120
|
className: "space-y-3",
|
|
120
121
|
children: [
|
|
121
122
|
/* @__PURE__ */ g("div", {
|
|
@@ -167,7 +168,7 @@ function j({ project: j, selected: M = !1, onToggleSelect: N, onTagClick: P, can
|
|
|
167
168
|
})
|
|
168
169
|
]
|
|
169
170
|
})]
|
|
170
|
-
}), /* @__PURE__ */ h(
|
|
171
|
+
}), /* @__PURE__ */ h(E, { control: U })] });
|
|
171
172
|
}
|
|
172
173
|
//#endregion
|
|
173
174
|
export { j as ProjectCard };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectCard.js","names":[],"sources":["../../src/components/ProjectCard.tsx"],"sourcesContent":["import type React from 'react';\nimport { FolderKanban, Archive, MoreVertical, Fingerprint } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Badge,\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n EntityIdModal,\n useEntityIdModal,\n} from '@burdenoff/fe-libs/ui';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\n\nimport type { Project, ProjectTag } from '../types';\nimport { formatDate } from '../utils/formatters';\nimport { getProjectDisplayTags } from '../utils/projectTags';\nimport { getProjectStatusClasses } from '../utils/tokenHelpers';\nimport {\n useArchiveProject,\n useUnarchiveProject,\n useDeleteProject,\n} from '../hooks/useProjectMutations';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { nativeConfirm, nativeImpact } from '../utils/nativeBridge';\n\ninterface ProjectCardProps {\n project: Project;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n onTagClick?: (tag: ProjectTag) => void;\n canArchive?: boolean;\n canDelete?: boolean;\n}\n\nexport function ProjectCard({\n project,\n selected = false,\n onToggleSelect,\n onTagClick,\n canArchive = false,\n canDelete = false,\n}: ProjectCardProps) {\n const navigate = useNavigate();\n const { basePath = '/workspaces' } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { mutate: archiveProject } = useArchiveProject(project.workspaceId);\n const { mutate: unarchiveProject } = useUnarchiveProject(project.workspaceId);\n const { mutate: deleteProject } = useDeleteProject(project.workspaceId);\n const idModal = useEntityIdModal();\n const projectTags = getProjectDisplayTags(project);\n\n const handleCardClick = () => {\n navigate(withCurrentSearch(`${basePath}/${project.workspaceId}/projects/${project.id}`));\n };\n\n const handleArchive = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (project.archived) {\n unarchiveProject(project.id);\n } else {\n archiveProject(project.id);\n }\n };\n\n const handleDelete = async (e: React.MouseEvent) => {\n e.stopPropagation();\n void nativeImpact('medium');\n const native = await nativeConfirm({\n title: 'Delete project',\n message: `Are you sure you want to delete \"${project.name}\"?`,\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok =\n native === null ? confirm(`Are you sure you want to delete \"${project.name}\"?`) : native;\n if (ok) {\n deleteProject(project.id);\n }\n };\n\n const handleCardKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleCardClick();\n }\n };\n\n return (\n <>\n <Card\n className={`cursor-pointer relative ${\n selected ? 'ring-2 ring-primary/25 border-primary/50' : ''\n }`}\n onClick={handleCardClick}\n onKeyDown={handleCardKeyDown}\n role=\"button\"\n tabIndex={0}\n aria-label={`Open project ${project.name}`}\n >\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3 flex-1\">\n {onToggleSelect && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(event) => onToggleSelect(event.target.checked)}\n onClick={(event) => event.stopPropagation()}\n aria-label={`Select project ${project.name}`}\n className=\"mt-1 size-4 rounded border-border-subtle text-primary\"\n />\n )}\n <div className=\"p-3 rounded-lg bg-action-primary-bg/10 transition-colors\">\n <FolderKanban className=\"text-primary\" size={24} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <CardTitle className=\"truncate\">{project.name}</CardTitle>\n <p className=\"truncate text-sm text-text-secondary\">{project.key}</p>\n </div>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild onClick={(e) => e.stopPropagation()}>\n <Button variant=\"ghost\" size=\"sm\" className=\"size-8 p-0\">\n <MoreVertical size={16} />\n <span className=\"sr-only\">Open project actions</span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n onClick={(e) => {\n e.stopPropagation();\n idModal.show({\n id: project.id,\n name: project.name,\n type: 'Project',\n details: [\n { label: 'Key', value: project.key },\n { label: 'Workspace ID', value: project.workspaceId },\n ],\n });\n }}\n >\n <Fingerprint size={16} className=\"mr-2\" />\n Get ID\n </DropdownMenuItem>\n {canArchive && (\n <DropdownMenuItem onClick={handleArchive}>\n <Archive size={16} className=\"mr-2\" />\n {project.archived ? 'Unarchive' : 'Archive'}\n </DropdownMenuItem>\n )}\n {canDelete && (\n <DropdownMenuItem onClick={handleDelete} className=\"text-status-error-text\">\n Delete\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Badge className={`border ${getProjectStatusClasses(project.status)}`}>\n {project.status}\n </Badge>\n {project.archived && (\n <Badge\n variant=\"outline\"\n className=\"border-workspace-archived-border text-workspace-archived-text\"\n >\n <Archive size={12} className=\"mr-1\" />\n Archived\n </Badge>\n )}\n </div>\n <div className=\"text-xs text-text-secondary\">Created {formatDate(project.createdAt)}</div>\n {projectTags.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\" aria-label=\"Project tags\">\n {projectTags.slice(0, 4).map((tag) => (\n <span\n key={tag.tagId}\n {...(onTagClick\n ? {\n role: 'button',\n tabIndex: 0,\n onClick: (event: React.MouseEvent<HTMLSpanElement>) => {\n event.stopPropagation();\n onTagClick(tag);\n },\n onKeyDown: (event: React.KeyboardEvent<HTMLSpanElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n event.stopPropagation();\n onTagClick(tag);\n }\n },\n }\n : {})}\n >\n <TagBadge\n id={tag.tagId}\n label={tag.label}\n color={tag.color ?? undefined}\n icon={tag.icon ?? undefined}\n description={tag.description ?? undefined}\n size=\"sm\"\n className={onTagClick ? 'cursor-pointer' : undefined}\n />\n </span>\n ))}\n {projectTags.length > 4 && (\n <Badge variant=\"outline\" className=\"text-xs\">\n +{projectTags.length - 4}\n </Badge>\n )}\n </div>\n )}\n </CardContent>\n </Card>\n <EntityIdModal control={idModal} />\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProjectCard.js","names":[],"sources":["../../src/components/ProjectCard.tsx"],"sourcesContent":["import type React from 'react';\nimport { FolderKanban, Archive, MoreVertical, Fingerprint } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n GlassCard,\n CardContent,\n CardHeader,\n CardTitle,\n Badge,\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n EntityIdModal,\n useEntityIdModal,\n} from '@burdenoff/fe-libs/ui';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\n\nimport type { Project, ProjectTag } from '../types';\nimport { formatDate } from '../utils/formatters';\nimport { getProjectDisplayTags } from '../utils/projectTags';\nimport { getProjectStatusClasses } from '../utils/tokenHelpers';\nimport {\n useArchiveProject,\n useUnarchiveProject,\n useDeleteProject,\n} from '../hooks/useProjectMutations';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { nativeConfirm, nativeImpact } from '../utils/nativeBridge';\n\ninterface ProjectCardProps {\n project: Project;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n onTagClick?: (tag: ProjectTag) => void;\n canArchive?: boolean;\n canDelete?: boolean;\n}\n\nexport function ProjectCard({\n project,\n selected = false,\n onToggleSelect,\n onTagClick,\n canArchive = false,\n canDelete = false,\n}: ProjectCardProps) {\n const navigate = useNavigate();\n const { basePath = '/workspaces' } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { mutate: archiveProject } = useArchiveProject(project.workspaceId);\n const { mutate: unarchiveProject } = useUnarchiveProject(project.workspaceId);\n const { mutate: deleteProject } = useDeleteProject(project.workspaceId);\n const idModal = useEntityIdModal();\n const projectTags = getProjectDisplayTags(project);\n\n const handleCardClick = () => {\n navigate(withCurrentSearch(`${basePath}/${project.workspaceId}/projects/${project.id}`));\n };\n\n const handleArchive = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (project.archived) {\n unarchiveProject(project.id);\n } else {\n archiveProject(project.id);\n }\n };\n\n const handleDelete = async (e: React.MouseEvent) => {\n e.stopPropagation();\n void nativeImpact('medium');\n const native = await nativeConfirm({\n title: 'Delete project',\n message: `Are you sure you want to delete \"${project.name}\"?`,\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok =\n native === null ? confirm(`Are you sure you want to delete \"${project.name}\"?`) : native;\n if (ok) {\n deleteProject(project.id);\n }\n };\n\n const handleCardKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleCardClick();\n }\n };\n\n return (\n <>\n <GlassCard\n treatment=\"insight\"\n className={`cursor-pointer relative focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50 ${\n selected ? 'ring-2 ring-primary/25 border-primary/50' : ''\n }`}\n onClick={handleCardClick}\n onKeyDown={handleCardKeyDown}\n role=\"button\"\n tabIndex={0}\n aria-label={`Open project ${project.name}`}\n >\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3 flex-1\">\n {onToggleSelect && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(event) => onToggleSelect(event.target.checked)}\n onClick={(event) => event.stopPropagation()}\n aria-label={`Select project ${project.name}`}\n className=\"mt-1 size-4 rounded border-border-subtle text-primary\"\n />\n )}\n <div className=\"p-3 rounded-lg bg-action-primary-bg/10 transition-colors\">\n <FolderKanban className=\"text-primary\" size={24} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <CardTitle className=\"truncate\">{project.name}</CardTitle>\n <p className=\"truncate text-sm text-text-secondary\">{project.key}</p>\n </div>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild onClick={(e) => e.stopPropagation()}>\n <Button variant=\"ghost\" size=\"sm\" className=\"size-8 p-0\">\n <MoreVertical size={16} />\n <span className=\"sr-only\">Open project actions</span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n onClick={(e) => {\n e.stopPropagation();\n idModal.show({\n id: project.id,\n name: project.name,\n type: 'Project',\n details: [\n { label: 'Key', value: project.key },\n { label: 'Workspace ID', value: project.workspaceId },\n ],\n });\n }}\n >\n <Fingerprint size={16} className=\"mr-2\" />\n Get ID\n </DropdownMenuItem>\n {canArchive && (\n <DropdownMenuItem onClick={handleArchive}>\n <Archive size={16} className=\"mr-2\" />\n {project.archived ? 'Unarchive' : 'Archive'}\n </DropdownMenuItem>\n )}\n {canDelete && (\n <DropdownMenuItem onClick={handleDelete} className=\"text-status-error-text\">\n Delete\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Badge className={`border ${getProjectStatusClasses(project.status)}`}>\n {project.status}\n </Badge>\n {project.archived && (\n <Badge\n variant=\"outline\"\n className=\"border-workspace-archived-border text-workspace-archived-text\"\n >\n <Archive size={12} className=\"mr-1\" />\n Archived\n </Badge>\n )}\n </div>\n <div className=\"text-xs text-text-secondary\">Created {formatDate(project.createdAt)}</div>\n {projectTags.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\" aria-label=\"Project tags\">\n {projectTags.slice(0, 4).map((tag) => (\n <span\n key={tag.tagId}\n {...(onTagClick\n ? {\n role: 'button',\n tabIndex: 0,\n onClick: (event: React.MouseEvent<HTMLSpanElement>) => {\n event.stopPropagation();\n onTagClick(tag);\n },\n onKeyDown: (event: React.KeyboardEvent<HTMLSpanElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n event.stopPropagation();\n onTagClick(tag);\n }\n },\n }\n : {})}\n >\n <TagBadge\n id={tag.tagId}\n label={tag.label}\n color={tag.color ?? undefined}\n icon={tag.icon ?? undefined}\n description={tag.description ?? undefined}\n size=\"sm\"\n className={onTagClick ? 'cursor-pointer' : undefined}\n />\n </span>\n ))}\n {projectTags.length > 4 && (\n <Badge variant=\"outline\" className=\"text-xs\">\n +{projectTags.length - 4}\n </Badge>\n )}\n </div>\n )}\n </CardContent>\n </GlassCard>\n <EntityIdModal control={idModal} />\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -3,15 +3,16 @@ import { getWorkspaceStatusClasses as t } from "../utils/tokenHelpers.js";
|
|
|
3
3
|
import { useScopedNavigation as n } from "../hooks/useScopedNavigation.js";
|
|
4
4
|
import { Building2 as r, FolderKanban as i, Users as a } from "lucide-react";
|
|
5
5
|
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
6
|
-
import { Badge as c,
|
|
6
|
+
import { Badge as c, CardContent as l, CardHeader as u, CardTitle as d, GlassCard as f } from "@burdenoff/fe-libs/ui";
|
|
7
7
|
import { useNavigate as p } from "react-router-dom";
|
|
8
8
|
//#region src/components/WorkspaceCard.tsx
|
|
9
9
|
function m({ workspace: m }) {
|
|
10
10
|
let h = p(), { basePath: g = "/" } = e(), { withCurrentSearch: _ } = n(), v = () => {
|
|
11
11
|
h(_(`${g}/${m.id}`));
|
|
12
12
|
};
|
|
13
|
-
return /* @__PURE__ */ s(
|
|
14
|
-
|
|
13
|
+
return /* @__PURE__ */ s(f, {
|
|
14
|
+
treatment: "insight",
|
|
15
|
+
className: "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50",
|
|
15
16
|
onClick: v,
|
|
16
17
|
onKeyDown: (e) => {
|
|
17
18
|
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), v());
|
|
@@ -20,7 +21,7 @@ function m({ workspace: m }) {
|
|
|
20
21
|
tabIndex: 0,
|
|
21
22
|
"aria-label": `Open workspace ${m.name}`,
|
|
22
23
|
"data-tour": "workspaces-card",
|
|
23
|
-
children: [/* @__PURE__ */ o(
|
|
24
|
+
children: [/* @__PURE__ */ o(u, { children: /* @__PURE__ */ s("div", {
|
|
24
25
|
className: "flex items-center gap-3",
|
|
25
26
|
children: [/* @__PURE__ */ o("div", {
|
|
26
27
|
className: "p-3 rounded-lg bg-action-primary-bg/10 transition-colors",
|
|
@@ -30,7 +31,7 @@ function m({ workspace: m }) {
|
|
|
30
31
|
})
|
|
31
32
|
}), /* @__PURE__ */ s("div", {
|
|
32
33
|
className: "flex-1 min-w-0",
|
|
33
|
-
children: [/* @__PURE__ */ o(
|
|
34
|
+
children: [/* @__PURE__ */ o(d, {
|
|
34
35
|
className: "text-lg truncate",
|
|
35
36
|
children: m.name
|
|
36
37
|
}), /* @__PURE__ */ o("div", {
|
|
@@ -41,7 +42,7 @@ function m({ workspace: m }) {
|
|
|
41
42
|
})
|
|
42
43
|
})]
|
|
43
44
|
})]
|
|
44
|
-
}) }), /* @__PURE__ */ s(
|
|
45
|
+
}) }), /* @__PURE__ */ s(l, { children: [/* @__PURE__ */ s("div", {
|
|
45
46
|
className: "flex flex-wrap gap-4 text-sm text-text-secondary",
|
|
46
47
|
children: [typeof m.memberCount == "number" && m.memberCount > 0 && /* @__PURE__ */ s("div", {
|
|
47
48
|
className: "flex items-center gap-1",
|
|
@@ -65,7 +66,7 @@ function m({ workspace: m }) {
|
|
|
65
66
|
] })]
|
|
66
67
|
})]
|
|
67
68
|
}), m.domain && /* @__PURE__ */ o("p", {
|
|
68
|
-
className: "mt-2 truncate text-xs text-text-
|
|
69
|
+
className: "mt-2 truncate text-xs text-text-muted",
|
|
69
70
|
children: m.domain
|
|
70
71
|
})] })]
|
|
71
72
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceCard.js","names":[],"sources":["../../src/components/WorkspaceCard.tsx"],"sourcesContent":["import { Building2, Users, FolderKanban } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport {
|
|
1
|
+
{"version":3,"file":"WorkspaceCard.js","names":[],"sources":["../../src/components/WorkspaceCard.tsx"],"sourcesContent":["import { Building2, Users, FolderKanban } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { GlassCard, CardHeader, CardTitle, CardContent, Badge } from '@burdenoff/fe-libs/ui';\nimport type { Workspace } from '../types';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { getWorkspaceStatusClasses } from '../utils/tokenHelpers';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\n\ninterface WorkspaceCardProps {\n workspace: Workspace;\n}\n\nexport function WorkspaceCard({ workspace }: WorkspaceCardProps) {\n const navigate = useNavigate();\n const { basePath = '/' } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n\n const openWorkspace = () => {\n navigate(withCurrentSearch(`${basePath}/${workspace.id}`));\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n openWorkspace();\n }\n };\n\n return (\n <GlassCard\n treatment=\"insight\"\n className=\"cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50\"\n onClick={openWorkspace}\n onKeyDown={handleKeyDown}\n role=\"button\"\n tabIndex={0}\n aria-label={`Open workspace ${workspace.name}`}\n data-tour=\"workspaces-card\"\n >\n <CardHeader>\n <div className=\"flex items-center gap-3\">\n <div className=\"p-3 rounded-lg bg-action-primary-bg/10 transition-colors\">\n <Building2 className=\"text-primary\" size={24} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <CardTitle className=\"text-lg truncate\">{workspace.name}</CardTitle>\n <div className=\"flex items-center gap-2 mt-1\">\n <Badge className={`text-xs border ${getWorkspaceStatusClasses(workspace.status)}`}>\n {workspace.status}\n </Badge>\n </div>\n </div>\n </div>\n </CardHeader>\n <CardContent>\n <div className=\"flex flex-wrap gap-4 text-sm text-text-secondary\">\n {typeof workspace.memberCount === 'number' && workspace.memberCount > 0 && (\n <div className=\"flex items-center gap-1\">\n <Users size={16} aria-hidden=\"true\" />\n <span>\n {workspace.memberCount} member{workspace.memberCount === 1 ? '' : 's'}\n </span>\n </div>\n )}\n {typeof workspace.projectCount === 'number' && workspace.projectCount > 0 && (\n <div className=\"flex items-center gap-1\">\n <FolderKanban size={16} aria-hidden=\"true\" />\n <span>\n {workspace.projectCount} project{workspace.projectCount === 1 ? '' : 's'}\n </span>\n </div>\n )}\n </div>\n {workspace.domain && (\n <p className=\"mt-2 truncate text-xs text-text-muted\">{workspace.domain}</p>\n )}\n </CardContent>\n </GlassCard>\n );\n}\n"],"mappings":";;;;;;;;AAYA,SAAgB,EAAc,EAAE,gBAAiC;CAC/D,IAAM,IAAW,GAAa,EACxB,EAAE,cAAW,QAAQ,GAAsB,EAC3C,EAAE,yBAAsB,GAAqB,EAE7C,UAAsB;AAC1B,IAAS,EAAkB,GAAG,EAAS,GAAG,EAAU,KAAK,CAAC;;AAU5D,QACE,kBAAC,GAAD;EACE,WAAU;EACV,WAAU;EACV,SAAS;EACT,YAZmB,MAA+C;AACpE,IAAI,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,gBAAgB,EACtB,GAAe;;EAUf,MAAK;EACL,UAAU;EACV,cAAY,kBAAkB,EAAU;EACxC,aAAU;YARZ,CAUE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD;KAAW,WAAU;KAAe,MAAM;KAAM,CAAA;IAC5C,CAAA,EACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAW,WAAU;eAAoB,EAAU;KAAiB,CAAA,EACpE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAO,WAAW,kBAAkB,EAA0B,EAAU,OAAO;gBAC5E,EAAU;MACL,CAAA;KACJ,CAAA,CACF;MACF;MACK,CAAA,EACb,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,OAAO,EAAU,eAAgB,YAAY,EAAU,cAAc,KACpE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAO,MAAM;KAAI,eAAY;KAAS,CAAA,EACtC,kBAAC,QAAD,EAAA,UAAA;KACG,EAAU;KAAY;KAAQ,EAAU,gBAAgB,IAAI,KAAK;KAC7D,EAAA,CAAA,CACH;OAEP,OAAO,EAAU,gBAAiB,YAAY,EAAU,eAAe,KACtE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAc,MAAM;KAAI,eAAY;KAAS,CAAA,EAC7C,kBAAC,QAAD,EAAA,UAAA;KACG,EAAU;KAAa;KAAS,EAAU,iBAAiB,IAAI,KAAK;KAChE,EAAA,CAAA,CACH;MAEJ;MACL,EAAU,UACT,kBAAC,KAAD;GAAG,WAAU;aAAyC,EAAU;GAAW,CAAA,CAEjE,EAAA,CAAA,CACJ"}
|
|
@@ -5,7 +5,7 @@ import { formatDate as r } from "../utils/formatters.js";
|
|
|
5
5
|
import { useWorkspaceActivity as i } from "../hooks/useWorkspaceActivity.js";
|
|
6
6
|
import { Activity as a } from "lucide-react";
|
|
7
7
|
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
8
|
-
import {
|
|
8
|
+
import { CardContent as c, CardHeader as l, CardTitle as u, GlassCard as d, Skeleton as f } from "@burdenoff/fe-libs/ui";
|
|
9
9
|
import { useParams as p } from "react-router-dom";
|
|
10
10
|
import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
11
|
//#region src/pages/ActivityListPage.tsx
|
|
@@ -27,13 +27,21 @@ function h() {
|
|
|
27
27
|
}), /* @__PURE__ */ o("p", {
|
|
28
28
|
className: "text-text-secondary",
|
|
29
29
|
children: e(h, "activityList.description", "Track workspace activity")
|
|
30
|
-
})] }), v ? /* @__PURE__ */ o(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
})] }), v ? /* @__PURE__ */ o(d, {
|
|
31
|
+
treatment: "plain",
|
|
32
|
+
className: "border-border-seam",
|
|
33
|
+
children: /* @__PURE__ */ o(c, {
|
|
34
|
+
className: "py-8 text-sm text-text-muted",
|
|
35
|
+
children: e(h, "activityList.loading", "Loading activity…")
|
|
36
|
+
})
|
|
37
|
+
}) : y ? /* @__PURE__ */ o(d, {
|
|
38
|
+
treatment: "plain",
|
|
39
|
+
className: "border-border-seam",
|
|
40
|
+
children: /* @__PURE__ */ o(c, {
|
|
41
|
+
className: "py-8 text-sm text-status-error-text",
|
|
42
|
+
children: y instanceof Error ? y.message : e(h, "activityList.loadError", "Failed to load activity")
|
|
43
|
+
})
|
|
44
|
+
}) : (_?.length ?? 0) === 0 ? /* @__PURE__ */ s("div", {
|
|
37
45
|
className: "flex flex-col items-center justify-center py-12 text-center",
|
|
38
46
|
children: [
|
|
39
47
|
/* @__PURE__ */ o("div", {
|
|
@@ -54,53 +62,57 @@ function h() {
|
|
|
54
62
|
]
|
|
55
63
|
}) : /* @__PURE__ */ o("div", {
|
|
56
64
|
className: "space-y-3",
|
|
57
|
-
children: _?.map((t) => /* @__PURE__ */ s(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
65
|
+
children: _?.map((t) => /* @__PURE__ */ s(d, {
|
|
66
|
+
treatment: "insight",
|
|
67
|
+
className: "border-border-seam",
|
|
68
|
+
children: [/* @__PURE__ */ o(l, {
|
|
69
|
+
className: "pb-2",
|
|
70
|
+
children: /* @__PURE__ */ o(u, {
|
|
71
|
+
className: "text-base",
|
|
72
|
+
children: t.description || t.action
|
|
73
|
+
})
|
|
74
|
+
}), /* @__PURE__ */ s(c, {
|
|
75
|
+
className: "space-y-1 text-sm text-text-muted",
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ s("p", { children: [
|
|
78
|
+
e(h, "activityList.labelAction", "Action"),
|
|
79
|
+
":",
|
|
80
|
+
" ",
|
|
81
|
+
/* @__PURE__ */ o("span", {
|
|
82
|
+
className: "text-text-primary",
|
|
83
|
+
children: t.action
|
|
84
|
+
})
|
|
85
|
+
] }),
|
|
86
|
+
t.resourceType && /* @__PURE__ */ s("p", { children: [
|
|
87
|
+
e(h, "activityList.labelResource", "Resource"),
|
|
88
|
+
":",
|
|
89
|
+
" ",
|
|
90
|
+
/* @__PURE__ */ o("span", {
|
|
91
|
+
className: "text-text-primary",
|
|
92
|
+
children: t.resourceType
|
|
93
|
+
})
|
|
94
|
+
] }),
|
|
95
|
+
/* @__PURE__ */ s("p", { children: [
|
|
96
|
+
e(h, "activityList.labelWhen", "When"),
|
|
97
|
+
":",
|
|
98
|
+
" ",
|
|
99
|
+
/* @__PURE__ */ o("span", {
|
|
100
|
+
className: "text-text-primary",
|
|
101
|
+
children: r(t.timestamp)
|
|
102
|
+
})
|
|
103
|
+
] }),
|
|
104
|
+
/* @__PURE__ */ s("p", { children: [
|
|
105
|
+
e(h, "activityList.labelActor", "Actor"),
|
|
106
|
+
":",
|
|
107
|
+
" ",
|
|
108
|
+
/* @__PURE__ */ o("span", {
|
|
109
|
+
className: "break-all text-text-primary",
|
|
110
|
+
children: t.userId
|
|
111
|
+
})
|
|
112
|
+
] })
|
|
113
|
+
]
|
|
114
|
+
})]
|
|
115
|
+
}, t.id))
|
|
104
116
|
})]
|
|
105
117
|
}) : /* @__PURE__ */ o("div", {
|
|
106
118
|
className: "flex items-center justify-center min-h-[400px]",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActivityListPage.js","names":[],"sources":["../../src/pages/ActivityListPage.tsx"],"sourcesContent":["import { Activity } from 'lucide-react';\nimport { useParams } from 'react-router-dom';\nimport {
|
|
1
|
+
{"version":3,"file":"ActivityListPage.js","names":[],"sources":["../../src/pages/ActivityListPage.tsx"],"sourcesContent":["import { Activity } from 'lucide-react';\nimport { useParams } from 'react-router-dom';\nimport { GlassCard, CardContent, CardHeader, CardTitle, Skeleton } from '@burdenoff/fe-libs/ui';\nimport { useWorkspaceActivity } from '../hooks/useWorkspaceActivity';\nimport { useWorkspacePermissions } from '../hooks/useWorkspacePermissions';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\nimport { formatDate } from '../utils/formatters';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\n\nexport function ActivityListPage() {\n const { t } = useI18n();\n\n // The URL path `:workspaceId` (when present) intentionally overrides the active\n // context. WorkspaceContextPathSync rewrites this segment on a context switch so\n // the override can't point at a stale workspace. (BOFF-2805 follow-up)\n const { workspaceId } = useParams<{ workspaceId: string }>();\n useWorkspacesPageView('workspaces.activity', { workspaceId, requireParams: true });\n const { data: activities, isLoading, error } = useWorkspaceActivity(workspaceId);\n const { canViewActivity, isLoading: permissionsLoading } = useWorkspacePermissions();\n\n if (permissionsLoading) {\n return (\n <div className=\"space-y-4 p-6\">\n <Skeleton className=\"h-10 w-1/3\" />\n <Skeleton className=\"h-64\" />\n </div>\n );\n }\n\n if (!canViewActivity) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold\">\n {tWithFallback(t, 'activityList.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(\n t,\n 'activityList.accessDeniedDescription',\n \"You don't have permission to view activity.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tWithFallback(t, 'activityList.title', 'Activity')}\n </h1>\n <p className=\"text-text-secondary\">\n {tWithFallback(t, 'activityList.description', 'Track workspace activity')}\n </p>\n </div>\n\n {isLoading ? (\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\n <CardContent className=\"py-8 text-sm text-text-muted\">\n {tWithFallback(t, 'activityList.loading', 'Loading activity…')}\n </CardContent>\n </GlassCard>\n ) : error ? (\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\n <CardContent className=\"py-8 text-sm text-status-error-text\">\n {error instanceof Error\n ? error.message\n : tWithFallback(t, 'activityList.loadError', 'Failed to load activity')}\n </CardContent>\n </GlassCard>\n ) : (activities?.length ?? 0) === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <div className=\"rounded-full bg-bg-sunken p-6 mb-4\">\n <Activity size={48} className=\"text-text-secondary\" />\n </div>\n <h3 className=\"text-lg font-semibold mb-2\">\n {tWithFallback(t, 'activityList.emptyTitle', 'No recent activity')}\n </h3>\n <p className=\"text-text-secondary max-w-sm\">\n {tWithFallback(\n t,\n 'activityList.emptyDescription',\n 'Recent workspace actions will appear here as your team creates, updates, and manages work.'\n )}\n </p>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {activities?.map((item) => (\n <GlassCard key={item.id} treatment=\"insight\" className=\"border-border-seam\">\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-base\">{item.description || item.action}</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-1 text-sm text-text-muted\">\n <p>\n {tWithFallback(t, 'activityList.labelAction', 'Action')}:{' '}\n <span className=\"text-text-primary\">{item.action}</span>\n </p>\n {item.resourceType && (\n <p>\n {tWithFallback(t, 'activityList.labelResource', 'Resource')}:{' '}\n <span className=\"text-text-primary\">{item.resourceType}</span>\n </p>\n )}\n <p>\n {tWithFallback(t, 'activityList.labelWhen', 'When')}:{' '}\n <span className=\"text-text-primary\">{formatDate(item.timestamp)}</span>\n </p>\n <p>\n {tWithFallback(t, 'activityList.labelActor', 'Actor')}:{' '}\n <span className=\"break-all text-text-primary\">{item.userId}</span>\n </p>\n </CardContent>\n </GlassCard>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ import { useOrgsWithPermission as te } from "../hooks/useOrgsWithPermission.js";
|
|
|
8
8
|
import { useEffect as o, useMemo as s } from "react";
|
|
9
9
|
import { AlertCircle as c, ArrowLeft as l } from "lucide-react";
|
|
10
10
|
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
11
|
-
import { Button as f,
|
|
11
|
+
import { Button as f, CardContent as p, CardDescription as m, CardHeader as ne, CardTitle as h, GlassCard as g, Skeleton as _ } from "@burdenoff/fe-libs/ui";
|
|
12
12
|
import { Link as v, useNavigate as y } from "react-router-dom";
|
|
13
13
|
import { useUpgradePrompt as b } from "@burdenoff/fe-libs/shared/hooks";
|
|
14
14
|
import { AccessDenied as x, UpgradeInlineBanner as S } from "@burdenoff/fe-libs/shared/components";
|
|
@@ -95,9 +95,10 @@ function E() {
|
|
|
95
95
|
message: j ? t(E, "createWorkspace.upgradeCapMessage", `You've used all workspaces in the ${k?.planName ?? "free"} plan.`) : t(E, "createWorkspace.upgradeApproachingMessage", "Upgrade to create more workspaces.")
|
|
96
96
|
})
|
|
97
97
|
}),
|
|
98
|
-
/* @__PURE__ */ d(
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
/* @__PURE__ */ d(g, {
|
|
99
|
+
treatment: "plain",
|
|
100
|
+
className: "max-w-2xl mx-auto border-border-seam",
|
|
101
|
+
children: [/* @__PURE__ */ d(ne, { children: [/* @__PURE__ */ u(h, { children: t(E, "createWorkspace.title", "Create New Workspace") }), /* @__PURE__ */ u(m, { children: t(E, "createWorkspace.subtitle", "Set up a new workspace for your team") })] }), /* @__PURE__ */ d(p, { children: [Z && /* @__PURE__ */ d("div", {
|
|
101
102
|
role: "alert",
|
|
102
103
|
className: "mb-4 flex items-start gap-2 rounded-md border border-warning/30 bg-warning/10 p-3 text-sm text-text-primary",
|
|
103
104
|
children: [/* @__PURE__ */ u(c, {
|