@burdenoff/microfe-workspaces 2026.530.2 → 2026.531.1
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/WorkspacesRoutes.js +19 -15
- package/dist/WorkspacesRoutes.js.map +1 -1
- package/dist/components/ProjectCard.js +2 -2
- package/dist/components/ProjectCard.js.map +1 -1
- package/dist/components/tags/ProjectTagsWidget.js +53 -57
- package/dist/components/tags/ProjectTagsWidget.js.map +1 -1
- package/dist/generated/wspace-operations.js +24 -9
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useMemberMutations.js +2 -2
- package/dist/hooks/useMemberMutations.js.map +1 -1
- package/dist/hooks/usePendingInvitations.js +29 -0
- package/dist/hooks/usePendingInvitations.js.map +1 -0
- package/dist/hooks/useProjectMutations.js +107 -6
- package/dist/hooks/useProjectMutations.js.map +1 -1
- package/dist/hooks/useProjects.js +1 -1
- package/dist/hooks/useProjects.js.map +1 -1
- package/dist/hooks/useWorkspaceMembers.js +1 -1
- package/dist/hooks/useWorkspaceMembers.js.map +1 -1
- package/dist/index.js +20 -18
- package/dist/pages/InviteAcceptancePage.js +68 -44
- package/dist/pages/InviteAcceptancePage.js.map +1 -1
- package/dist/pages/PendingInvitesPage.js +254 -0
- package/dist/pages/PendingInvitesPage.js.map +1 -0
- package/dist/pages/ProjectDetailPage.js +187 -161
- package/dist/pages/ProjectDetailPage.js.map +1 -1
- package/dist/pages/ProjectsListPage.js +2 -2
- package/dist/pages/ProjectsListPage.js.map +1 -1
- package/dist/pages/WorkspacesListPage.js +118 -102
- package/dist/pages/WorkspacesListPage.js.map +1 -1
- package/dist/utils/projectTags.js +28 -2
- package/dist/utils/projectTags.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,100 +1,116 @@
|
|
|
1
1
|
import { useWorkspacesContext as e } from "../providers/WorkspacesProvider.js";
|
|
2
2
|
import { useWorkspacesStore as t } from "../store/workspacesStore.js";
|
|
3
3
|
import { useMyWorkspaces as n } from "../hooks/useWorkspaces.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
4
|
+
import { useMyPendingInvitations as r } from "../hooks/usePendingInvitations.js";
|
|
5
|
+
import { useScopedNavigation as i } from "../hooks/useScopedNavigation.js";
|
|
6
|
+
import { WorkspaceCard as a } from "../components/WorkspaceCard.js";
|
|
7
|
+
import { WORKSPACE_PERMISSIONS as o } from "../constants/permissions.js";
|
|
8
|
+
import { tWithFallback as s } from "../utils/i18n.js";
|
|
9
|
+
import { useWorkspacesPageView as c } from "../hooks/useWorkspacesPageView.js";
|
|
10
|
+
import { useEffect as l, useState as u } from "react";
|
|
11
|
+
import { Grid3X3 as d, List as f, Mail as p, Plus as m, Search as h } from "lucide-react";
|
|
12
|
+
import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
13
|
+
import { Badge as y, Button as b, Input as x, Skeleton as S } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { useNavigate as C } from "react-router-dom";
|
|
15
|
+
import { useDebounce as w } from "@burdenoff/fe-libs/shared/hooks";
|
|
16
|
+
import { PermissionButton as T } from "@burdenoff/fe-libs/shared/components";
|
|
17
|
+
import { useI18n as E } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
17
18
|
//#region src/pages/WorkspacesListPage.tsx
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
let { t:
|
|
21
|
-
|
|
22
|
-
}, [
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
function D() {
|
|
20
|
+
c("workspaces.list");
|
|
21
|
+
let { t: D } = E(), O = C(), { basePath: k = "/", currentUser: A } = e(), { withCurrentSearch: j } = i(), { viewMode: M, setViewMode: N, workspaceFilters: P, setWorkspaceFilters: F } = t(), I = () => {
|
|
22
|
+
O(j(`${k}/new`));
|
|
23
|
+
}, [L, R] = u(P.search || ""), z = w(L, 500);
|
|
24
|
+
l(() => {
|
|
25
|
+
z !== P.search && F({ search: z });
|
|
25
26
|
}, [
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
z,
|
|
28
|
+
P.search,
|
|
29
|
+
F
|
|
29
30
|
]);
|
|
30
|
-
let { data:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
let { data: B, isLoading: V, error: H } = n(), { data: U = [] } = r(A?.email), W = U.length, G = () => {
|
|
32
|
+
O(j(`${k}/invites`));
|
|
33
|
+
}, K = B ? {
|
|
34
|
+
...B,
|
|
35
|
+
items: z ? B.items.filter((e) => e.name.toLowerCase().includes(z.toLowerCase())) : B.items,
|
|
36
|
+
total: z ? B.items.filter((e) => e.name.toLowerCase().includes(z.toLowerCase())).length : B.total
|
|
34
37
|
} : void 0;
|
|
35
|
-
return
|
|
38
|
+
return H ? /* @__PURE__ */ _("div", {
|
|
36
39
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
37
|
-
children: /* @__PURE__ */
|
|
40
|
+
children: /* @__PURE__ */ v("div", {
|
|
38
41
|
className: "flex flex-col items-center justify-center py-12",
|
|
39
|
-
children: [/* @__PURE__ */
|
|
42
|
+
children: [/* @__PURE__ */ _("p", {
|
|
40
43
|
className: "text-destructive text-lg font-semibold",
|
|
41
|
-
children:
|
|
42
|
-
}), /* @__PURE__ */
|
|
44
|
+
children: s(D, "workspacesList.loadError", "Error loading workspaces")
|
|
45
|
+
}), /* @__PURE__ */ _("p", {
|
|
43
46
|
className: "text-muted-foreground text-sm mt-2",
|
|
44
|
-
children:
|
|
47
|
+
children: H instanceof Error ? H.message : s(D, "workspacesList.unknownError", "Unknown error")
|
|
45
48
|
})]
|
|
46
49
|
})
|
|
47
|
-
}) : /* @__PURE__ */
|
|
50
|
+
}) : /* @__PURE__ */ v("div", {
|
|
48
51
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
49
52
|
children: [
|
|
50
|
-
/* @__PURE__ */
|
|
53
|
+
/* @__PURE__ */ v("div", {
|
|
51
54
|
className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3",
|
|
52
55
|
"data-tour": "workspaces-list-header",
|
|
53
|
-
children: [/* @__PURE__ */
|
|
56
|
+
children: [/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("h1", {
|
|
54
57
|
className: "text-2xl sm:text-3xl font-bold",
|
|
55
|
-
children:
|
|
56
|
-
}), /* @__PURE__ */
|
|
58
|
+
children: s(D, "workspacesList.title", "Workspaces")
|
|
59
|
+
}), /* @__PURE__ */ _("p", {
|
|
57
60
|
className: "text-sm sm:text-base text-muted-foreground",
|
|
58
|
-
children:
|
|
59
|
-
})] }), /* @__PURE__ */
|
|
61
|
+
children: s(D, "workspacesList.description", "Manage and organize your workspaces")
|
|
62
|
+
})] }), /* @__PURE__ */ v("div", {
|
|
60
63
|
className: "flex items-center gap-2",
|
|
61
64
|
"data-tour": "workspaces-list-actions",
|
|
62
65
|
children: [
|
|
63
|
-
/* @__PURE__ */
|
|
64
|
-
variant:
|
|
66
|
+
/* @__PURE__ */ _(b, {
|
|
67
|
+
variant: M === "grid" ? "default" : "outline",
|
|
65
68
|
size: "icon",
|
|
66
|
-
onClick: () =>
|
|
69
|
+
onClick: () => N("grid"),
|
|
67
70
|
className: "hidden sm:flex",
|
|
68
|
-
"aria-label":
|
|
69
|
-
title:
|
|
70
|
-
children: /* @__PURE__ */
|
|
71
|
+
"aria-label": s(D, "workspacesList.gridViewAriaLabel", "Show workspaces in grid view"),
|
|
72
|
+
title: s(D, "workspacesList.gridViewTitle", "Grid view"),
|
|
73
|
+
children: /* @__PURE__ */ _(d, { size: 20 })
|
|
71
74
|
}),
|
|
72
|
-
/* @__PURE__ */
|
|
73
|
-
variant:
|
|
75
|
+
/* @__PURE__ */ _(b, {
|
|
76
|
+
variant: M === "list" ? "default" : "outline",
|
|
74
77
|
size: "icon",
|
|
75
|
-
onClick: () =>
|
|
78
|
+
onClick: () => N("list"),
|
|
76
79
|
className: "hidden sm:flex",
|
|
77
|
-
"aria-label":
|
|
78
|
-
title:
|
|
79
|
-
children: /* @__PURE__ */
|
|
80
|
+
"aria-label": s(D, "workspacesList.listViewAriaLabel", "Show workspaces in list view"),
|
|
81
|
+
title: s(D, "workspacesList.listViewTitle", "List view"),
|
|
82
|
+
children: /* @__PURE__ */ _(f, { size: 20 })
|
|
80
83
|
}),
|
|
81
|
-
/* @__PURE__ */
|
|
82
|
-
|
|
84
|
+
/* @__PURE__ */ v(b, {
|
|
85
|
+
variant: "outline",
|
|
86
|
+
onClick: G,
|
|
87
|
+
className: "gap-2",
|
|
88
|
+
children: [
|
|
89
|
+
/* @__PURE__ */ _(p, { size: 18 }),
|
|
90
|
+
/* @__PURE__ */ _("span", { children: s(D, "workspacesList.pendingInvitesButton", "Pending Invites") }),
|
|
91
|
+
W > 0 ? /* @__PURE__ */ _(y, {
|
|
92
|
+
variant: "secondary",
|
|
93
|
+
children: W
|
|
94
|
+
}) : null
|
|
95
|
+
]
|
|
96
|
+
}),
|
|
97
|
+
/* @__PURE__ */ _(T, {
|
|
98
|
+
permission: o.WORKSPACE_CREATE,
|
|
83
99
|
deniedBehavior: "disable",
|
|
84
|
-
deniedTooltip:
|
|
85
|
-
children: /* @__PURE__ */
|
|
86
|
-
onClick:
|
|
100
|
+
deniedTooltip: s(D, "workspacesList.createDeniedTooltip", "You don't have permission to create workspaces"),
|
|
101
|
+
children: /* @__PURE__ */ v(b, {
|
|
102
|
+
onClick: I,
|
|
87
103
|
className: "gap-2",
|
|
88
104
|
"data-tour": "workspaces-create-button",
|
|
89
105
|
children: [
|
|
90
|
-
/* @__PURE__ */
|
|
91
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ _(m, { size: 20 }),
|
|
107
|
+
/* @__PURE__ */ _("span", {
|
|
92
108
|
className: "hidden sm:inline",
|
|
93
|
-
children:
|
|
109
|
+
children: s(D, "workspacesList.createButton", "Create Workspace")
|
|
94
110
|
}),
|
|
95
|
-
/* @__PURE__ */
|
|
111
|
+
/* @__PURE__ */ _("span", {
|
|
96
112
|
className: "sm:hidden",
|
|
97
|
-
children:
|
|
113
|
+
children: s(D, "workspacesList.createButtonShort", "Create")
|
|
98
114
|
})
|
|
99
115
|
]
|
|
100
116
|
})
|
|
@@ -102,86 +118,86 @@ function w() {
|
|
|
102
118
|
]
|
|
103
119
|
})]
|
|
104
120
|
}),
|
|
105
|
-
/* @__PURE__ */
|
|
121
|
+
/* @__PURE__ */ v("div", {
|
|
106
122
|
className: "relative",
|
|
107
123
|
"data-tour": "workspaces-search-input",
|
|
108
|
-
children: [/* @__PURE__ */ h
|
|
124
|
+
children: [/* @__PURE__ */ _(h, {
|
|
109
125
|
className: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground",
|
|
110
126
|
size: 20
|
|
111
|
-
}), /* @__PURE__ */
|
|
112
|
-
placeholder:
|
|
113
|
-
value:
|
|
127
|
+
}), /* @__PURE__ */ _(x, {
|
|
128
|
+
placeholder: s(D, "workspacesList.searchPlaceholder", "Search workspaces..."),
|
|
129
|
+
value: L,
|
|
114
130
|
onChange: (e) => {
|
|
115
|
-
|
|
131
|
+
R(e.target.value);
|
|
116
132
|
},
|
|
117
133
|
className: "pl-[3.25rem]"
|
|
118
134
|
})]
|
|
119
135
|
}),
|
|
120
|
-
/* @__PURE__ */
|
|
136
|
+
/* @__PURE__ */ _("div", {
|
|
121
137
|
className: "space-y-4 sm:space-y-6",
|
|
122
138
|
"data-tour": "workspaces-view-container",
|
|
123
|
-
children:
|
|
139
|
+
children: V ? /* @__PURE__ */ _("div", {
|
|
124
140
|
className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4",
|
|
125
|
-
children: Array.from({ length: 6 }).map((e, t) => /* @__PURE__ */
|
|
141
|
+
children: Array.from({ length: 6 }).map((e, t) => /* @__PURE__ */ v("div", {
|
|
126
142
|
className: "space-y-3 p-6 border rounded-lg",
|
|
127
|
-
children: [/* @__PURE__ */
|
|
143
|
+
children: [/* @__PURE__ */ v("div", {
|
|
128
144
|
className: "flex items-center gap-3",
|
|
129
|
-
children: [/* @__PURE__ */
|
|
145
|
+
children: [/* @__PURE__ */ _(S, { className: "size-12 rounded-lg" }), /* @__PURE__ */ v("div", {
|
|
130
146
|
className: "space-y-2 flex-1",
|
|
131
|
-
children: [/* @__PURE__ */
|
|
147
|
+
children: [/* @__PURE__ */ _(S, { className: "h-4 w-3/4" }), /* @__PURE__ */ _(S, { className: "h-3 w-1/2" })]
|
|
132
148
|
})]
|
|
133
|
-
}), /* @__PURE__ */
|
|
149
|
+
}), /* @__PURE__ */ _(S, { className: "h-3 w-1/3" })]
|
|
134
150
|
}, t))
|
|
135
|
-
}) :
|
|
151
|
+
}) : K?.items.length === 0 ? /* @__PURE__ */ v("div", {
|
|
136
152
|
className: "flex flex-col items-center justify-center py-12 text-center",
|
|
137
153
|
children: [
|
|
138
|
-
/* @__PURE__ */
|
|
154
|
+
/* @__PURE__ */ _("div", {
|
|
139
155
|
className: "rounded-full bg-muted p-6 mb-4",
|
|
140
|
-
children: /* @__PURE__ */
|
|
156
|
+
children: /* @__PURE__ */ _(d, {
|
|
141
157
|
size: 48,
|
|
142
158
|
className: "text-muted-foreground"
|
|
143
159
|
})
|
|
144
160
|
}),
|
|
145
|
-
/* @__PURE__ */
|
|
161
|
+
/* @__PURE__ */ _("h3", {
|
|
146
162
|
className: "text-lg font-semibold mb-2",
|
|
147
|
-
children:
|
|
163
|
+
children: s(D, "workspacesList.emptyTitle", "No workspaces found")
|
|
148
164
|
}),
|
|
149
|
-
/* @__PURE__ */
|
|
165
|
+
/* @__PURE__ */ _("p", {
|
|
150
166
|
className: "text-muted-foreground mb-4 max-w-sm",
|
|
151
|
-
children:
|
|
167
|
+
children: P.search ? s(D, "workspacesList.emptySearchHint", "Try adjusting your search criteria") : s(D, "workspacesList.emptyCreateHint", "Get started by creating your first workspace")
|
|
152
168
|
}),
|
|
153
|
-
!
|
|
154
|
-
permission:
|
|
169
|
+
!P.search && /* @__PURE__ */ _(T, {
|
|
170
|
+
permission: o.WORKSPACE_CREATE,
|
|
155
171
|
deniedBehavior: "disable",
|
|
156
|
-
deniedTooltip:
|
|
157
|
-
children: /* @__PURE__ */
|
|
158
|
-
onClick:
|
|
172
|
+
deniedTooltip: s(D, "workspacesList.createDeniedTooltip", "You don't have permission to create workspaces"),
|
|
173
|
+
children: /* @__PURE__ */ v(b, {
|
|
174
|
+
onClick: I,
|
|
159
175
|
className: "gap-2",
|
|
160
|
-
children: [/* @__PURE__ */
|
|
176
|
+
children: [/* @__PURE__ */ _(m, { size: 20 }), s(D, "workspacesList.createFirstButton", "Create Your First Workspace")]
|
|
161
177
|
})
|
|
162
178
|
})
|
|
163
179
|
]
|
|
164
|
-
}) : /* @__PURE__ */ g
|
|
180
|
+
}) : /* @__PURE__ */ v(g, { children: [M === "list" ? /* @__PURE__ */ _("div", {
|
|
165
181
|
className: "space-y-3",
|
|
166
|
-
children:
|
|
167
|
-
}) : /* @__PURE__ */
|
|
182
|
+
children: K?.items.map((e) => /* @__PURE__ */ _(a, { workspace: e }, e.id))
|
|
183
|
+
}) : /* @__PURE__ */ _("div", {
|
|
168
184
|
className: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4",
|
|
169
|
-
children:
|
|
170
|
-
}),
|
|
185
|
+
children: K?.items.map((e) => /* @__PURE__ */ _(a, { workspace: e }, e.id))
|
|
186
|
+
}), K && K.total > 0 && /* @__PURE__ */ v("div", {
|
|
171
187
|
className: "flex items-center justify-between text-sm text-muted-foreground",
|
|
172
|
-
children: [/* @__PURE__ */
|
|
173
|
-
|
|
188
|
+
children: [/* @__PURE__ */ v("p", { children: [
|
|
189
|
+
s(D, "workspacesList.showing", "Showing"),
|
|
174
190
|
" ",
|
|
175
|
-
|
|
191
|
+
K.items.length,
|
|
176
192
|
" ",
|
|
177
|
-
|
|
193
|
+
s(D, "workspacesList.of", "of"),
|
|
178
194
|
" ",
|
|
179
|
-
|
|
195
|
+
K.total,
|
|
180
196
|
" ",
|
|
181
|
-
|
|
182
|
-
] }),
|
|
197
|
+
K.total === 1 ? s(D, "workspacesList.workspace", "workspace") : s(D, "workspacesList.workspaces", "workspaces")
|
|
198
|
+
] }), K.hasMore && /* @__PURE__ */ _("p", {
|
|
183
199
|
className: "text-xs",
|
|
184
|
-
children:
|
|
200
|
+
children: s(D, "workspacesList.moreAvailable", "More workspaces available - pagination coming soon")
|
|
185
201
|
})]
|
|
186
202
|
})] })
|
|
187
203
|
})
|
|
@@ -189,6 +205,6 @@ function w() {
|
|
|
189
205
|
});
|
|
190
206
|
}
|
|
191
207
|
//#endregion
|
|
192
|
-
export {
|
|
208
|
+
export { D as WorkspacesListPage };
|
|
193
209
|
|
|
194
210
|
//# sourceMappingURL=WorkspacesListPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspacesListPage.js","names":[],"sources":["../../src/pages/WorkspacesListPage.tsx"],"sourcesContent":["import { Plus, Grid3X3, List as ListIcon, Search } from 'lucide-react';\nimport { Button, Input, Skeleton } from '@burdenoff/fe-libs/ui';\nimport { useNavigate } from 'react-router-dom';\nimport { useWorkspacesStore } from '../store/workspacesStore';\nimport { useMyWorkspaces } from '../hooks/useWorkspaces';\nimport { WorkspaceCard } from '../components/WorkspaceCard';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useDebounce } from '@burdenoff/fe-libs/shared/hooks';\nimport { PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { WORKSPACE_PERMISSIONS } from '../constants/permissions';\nimport { useState, useEffect } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\n\nexport function WorkspacesListPage() {\n useWorkspacesPageView('workspaces.list');\n const { t } = useI18n();\n\n const navigate = useNavigate();\n const { basePath = '/' } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { viewMode, setViewMode, workspaceFilters, setWorkspaceFilters } = useWorkspacesStore();\n\n // Navigate to unified workspace creation page\n const handleCreateWorkspace = () => {\n navigate(withCurrentSearch(`${basePath}/new`));\n };\n\n const [searchValue, setSearchValue] = useState(workspaceFilters.search || '');\n const debouncedSearch = useDebounce(searchValue, 500);\n\n // Update filters when debounced search changes\n useEffect(() => {\n if (debouncedSearch !== workspaceFilters.search) {\n setWorkspaceFilters({ search: debouncedSearch });\n }\n }, [debouncedSearch, workspaceFilters.search, setWorkspaceFilters]);\n\n const { data: rawData, isLoading, error } = useMyWorkspaces();\n\n // Client-side search filtering (myWorkspaces doesn't accept filter args)\n const data = rawData\n ? {\n ...rawData,\n items: debouncedSearch\n ? rawData.items.filter((ws) =>\n ws.name.toLowerCase().includes(debouncedSearch.toLowerCase())\n )\n : rawData.items,\n total: debouncedSearch\n ? rawData.items.filter((ws) =>\n ws.name.toLowerCase().includes(debouncedSearch.toLowerCase())\n ).length\n : rawData.total,\n }\n : undefined;\n\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setSearchValue(e.target.value);\n };\n\n if (error) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <div className=\"flex flex-col items-center justify-center py-12\">\n <p className=\"text-destructive text-lg font-semibold\">\n {tWithFallback(t, 'workspacesList.loadError', 'Error loading workspaces')}\n </p>\n <p className=\"text-muted-foreground text-sm mt-2\">\n {error instanceof Error\n ? error.message\n : tWithFallback(t, 'workspacesList.unknownError', 'Unknown error')}\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 {/* Header with title + actions */}\n <div\n className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\"\n data-tour=\"workspaces-list-header\"\n >\n <div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tWithFallback(t, 'workspacesList.title', 'Workspaces')}\n </h1>\n <p className=\"text-sm sm:text-base text-muted-foreground\">\n {tWithFallback(t, 'workspacesList.description', 'Manage and organize your workspaces')}\n </p>\n </div>\n <div className=\"flex items-center gap-2\" data-tour=\"workspaces-list-actions\">\n {/* View mode toggle */}\n <Button\n variant={viewMode === 'grid' ? 'default' : 'outline'}\n size=\"icon\"\n onClick={() => setViewMode('grid')}\n className=\"hidden sm:flex\"\n aria-label={tWithFallback(\n t,\n 'workspacesList.gridViewAriaLabel',\n 'Show workspaces in grid view'\n )}\n title={tWithFallback(t, 'workspacesList.gridViewTitle', 'Grid view')}\n >\n <Grid3X3 size={20} />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'default' : 'outline'}\n size=\"icon\"\n onClick={() => setViewMode('list')}\n className=\"hidden sm:flex\"\n aria-label={tWithFallback(\n t,\n 'workspacesList.listViewAriaLabel',\n 'Show workspaces in list view'\n )}\n title={tWithFallback(t, 'workspacesList.listViewTitle', 'List view')}\n >\n <ListIcon size={20} />\n </Button>\n {/* Create button - requires workspace:create permission */}\n <PermissionButton\n permission={WORKSPACE_PERMISSIONS.WORKSPACE_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip={tWithFallback(\n t,\n 'workspacesList.createDeniedTooltip',\n \"You don't have permission to create workspaces\"\n )}\n >\n <Button\n onClick={handleCreateWorkspace}\n className=\"gap-2\"\n data-tour=\"workspaces-create-button\"\n >\n <Plus size={20} />\n <span className=\"hidden sm:inline\">\n {tWithFallback(t, 'workspacesList.createButton', 'Create Workspace')}\n </span>\n <span className=\"sm:hidden\">\n {tWithFallback(t, 'workspacesList.createButtonShort', 'Create')}\n </span>\n </Button>\n </PermissionButton>\n </div>\n </div>\n\n {/* Search */}\n <div className=\"relative\" data-tour=\"workspaces-search-input\">\n <Search\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground\"\n size={20}\n />\n <Input\n placeholder={tWithFallback(t, 'workspacesList.searchPlaceholder', 'Search workspaces...')}\n value={searchValue}\n onChange={handleSearchChange}\n className=\"pl-[3.25rem]\"\n />\n </div>\n\n {/* Content */}\n <div className=\"space-y-4 sm:space-y-6\" data-tour=\"workspaces-view-container\">\n {isLoading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div key={i} className=\"space-y-3 p-6 border rounded-lg\">\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"size-12 rounded-lg\" />\n <div className=\"space-y-2 flex-1\">\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-3 w-1/2\" />\n </div>\n </div>\n <Skeleton className=\"h-3 w-1/3\" />\n </div>\n ))}\n </div>\n ) : data?.items.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <div className=\"rounded-full bg-muted p-6 mb-4\">\n <Grid3X3 size={48} className=\"text-muted-foreground\" />\n </div>\n <h3 className=\"text-lg font-semibold mb-2\">\n {tWithFallback(t, 'workspacesList.emptyTitle', 'No workspaces found')}\n </h3>\n <p className=\"text-muted-foreground mb-4 max-w-sm\">\n {workspaceFilters.search\n ? tWithFallback(\n t,\n 'workspacesList.emptySearchHint',\n 'Try adjusting your search criteria'\n )\n : tWithFallback(\n t,\n 'workspacesList.emptyCreateHint',\n 'Get started by creating your first workspace'\n )}\n </p>\n {!workspaceFilters.search && (\n <PermissionButton\n permission={WORKSPACE_PERMISSIONS.WORKSPACE_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip={tWithFallback(\n t,\n 'workspacesList.createDeniedTooltip',\n \"You don't have permission to create workspaces\"\n )}\n >\n <Button onClick={handleCreateWorkspace} className=\"gap-2\">\n <Plus size={20} />\n {tWithFallback(\n t,\n 'workspacesList.createFirstButton',\n 'Create Your First Workspace'\n )}\n </Button>\n </PermissionButton>\n )}\n </div>\n ) : (\n <>\n {/* View */}\n {viewMode === 'list' ? (\n <div className=\"space-y-3\">\n {data?.items.map((workspace) => (\n <WorkspaceCard key={workspace.id} workspace={workspace} />\n ))}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {data?.items.map((workspace) => (\n <WorkspaceCard key={workspace.id} workspace={workspace} />\n ))}\n </div>\n )}\n\n {/* Pagination info */}\n {data && data.total > 0 && (\n <div className=\"flex items-center justify-between text-sm text-muted-foreground\">\n <p>\n {tWithFallback(t, 'workspacesList.showing', 'Showing')} {data.items.length}{' '}\n {tWithFallback(t, 'workspacesList.of', 'of')} {data.total}{' '}\n {data.total !== 1\n ? tWithFallback(t, 'workspacesList.workspaces', 'workspaces')\n : tWithFallback(t, 'workspacesList.workspace', 'workspace')}\n </p>\n {data.hasMore && (\n <p className=\"text-xs\">\n {tWithFallback(\n t,\n 'workspacesList.moreAvailable',\n 'More workspaces available - pagination coming soon'\n )}\n </p>\n )}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkspacesListPage.js","names":[],"sources":["../../src/pages/WorkspacesListPage.tsx"],"sourcesContent":["import { Plus, Grid3X3, List as ListIcon, Search, Mail } from 'lucide-react';\nimport { Badge, Button, Input, Skeleton } from '@burdenoff/fe-libs/ui';\nimport { useNavigate } from 'react-router-dom';\nimport { useWorkspacesStore } from '../store/workspacesStore';\nimport { useMyWorkspaces } from '../hooks/useWorkspaces';\nimport { useMyPendingInvitations } from '../hooks/usePendingInvitations';\nimport { WorkspaceCard } from '../components/WorkspaceCard';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useDebounce } from '@burdenoff/fe-libs/shared/hooks';\nimport { PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { WORKSPACE_PERMISSIONS } from '../constants/permissions';\nimport { useState, useEffect } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../utils/i18n';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\n\nexport function WorkspacesListPage() {\n useWorkspacesPageView('workspaces.list');\n const { t } = useI18n();\n\n const navigate = useNavigate();\n const { basePath = '/', currentUser } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { viewMode, setViewMode, workspaceFilters, setWorkspaceFilters } = useWorkspacesStore();\n\n // Navigate to unified workspace creation page\n const handleCreateWorkspace = () => {\n navigate(withCurrentSearch(`${basePath}/new`));\n };\n\n const [searchValue, setSearchValue] = useState(workspaceFilters.search || '');\n const debouncedSearch = useDebounce(searchValue, 500);\n\n // Update filters when debounced search changes\n useEffect(() => {\n if (debouncedSearch !== workspaceFilters.search) {\n setWorkspaceFilters({ search: debouncedSearch });\n }\n }, [debouncedSearch, workspaceFilters.search, setWorkspaceFilters]);\n\n const { data: rawData, isLoading, error } = useMyWorkspaces();\n const { data: pendingInvitations = [] } = useMyPendingInvitations(currentUser?.email);\n const pendingInvitesCount = pendingInvitations.length;\n\n const handleOpenPendingInvites = () => {\n navigate(withCurrentSearch(`${basePath}/invites`));\n };\n\n // Client-side search filtering (myWorkspaces doesn't accept filter args)\n const data = rawData\n ? {\n ...rawData,\n items: debouncedSearch\n ? rawData.items.filter((ws) =>\n ws.name.toLowerCase().includes(debouncedSearch.toLowerCase())\n )\n : rawData.items,\n total: debouncedSearch\n ? rawData.items.filter((ws) =>\n ws.name.toLowerCase().includes(debouncedSearch.toLowerCase())\n ).length\n : rawData.total,\n }\n : undefined;\n\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setSearchValue(e.target.value);\n };\n\n if (error) {\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <div className=\"flex flex-col items-center justify-center py-12\">\n <p className=\"text-destructive text-lg font-semibold\">\n {tWithFallback(t, 'workspacesList.loadError', 'Error loading workspaces')}\n </p>\n <p className=\"text-muted-foreground text-sm mt-2\">\n {error instanceof Error\n ? error.message\n : tWithFallback(t, 'workspacesList.unknownError', 'Unknown error')}\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 {/* Header with title + actions */}\n <div\n className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\"\n data-tour=\"workspaces-list-header\"\n >\n <div>\n <h1 className=\"text-2xl sm:text-3xl font-bold\">\n {tWithFallback(t, 'workspacesList.title', 'Workspaces')}\n </h1>\n <p className=\"text-sm sm:text-base text-muted-foreground\">\n {tWithFallback(t, 'workspacesList.description', 'Manage and organize your workspaces')}\n </p>\n </div>\n <div className=\"flex items-center gap-2\" data-tour=\"workspaces-list-actions\">\n {/* View mode toggle */}\n <Button\n variant={viewMode === 'grid' ? 'default' : 'outline'}\n size=\"icon\"\n onClick={() => setViewMode('grid')}\n className=\"hidden sm:flex\"\n aria-label={tWithFallback(\n t,\n 'workspacesList.gridViewAriaLabel',\n 'Show workspaces in grid view'\n )}\n title={tWithFallback(t, 'workspacesList.gridViewTitle', 'Grid view')}\n >\n <Grid3X3 size={20} />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'default' : 'outline'}\n size=\"icon\"\n onClick={() => setViewMode('list')}\n className=\"hidden sm:flex\"\n aria-label={tWithFallback(\n t,\n 'workspacesList.listViewAriaLabel',\n 'Show workspaces in list view'\n )}\n title={tWithFallback(t, 'workspacesList.listViewTitle', 'List view')}\n >\n <ListIcon size={20} />\n </Button>\n {/* Create button - requires workspace:create permission */}\n <Button variant=\"outline\" onClick={handleOpenPendingInvites} className=\"gap-2\">\n <Mail size={18} />\n <span>\n {tWithFallback(t, 'workspacesList.pendingInvitesButton', 'Pending Invites')}\n </span>\n {pendingInvitesCount > 0 ? (\n <Badge variant=\"secondary\">{pendingInvitesCount}</Badge>\n ) : null}\n </Button>\n <PermissionButton\n permission={WORKSPACE_PERMISSIONS.WORKSPACE_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip={tWithFallback(\n t,\n 'workspacesList.createDeniedTooltip',\n \"You don't have permission to create workspaces\"\n )}\n >\n <Button\n onClick={handleCreateWorkspace}\n className=\"gap-2\"\n data-tour=\"workspaces-create-button\"\n >\n <Plus size={20} />\n <span className=\"hidden sm:inline\">\n {tWithFallback(t, 'workspacesList.createButton', 'Create Workspace')}\n </span>\n <span className=\"sm:hidden\">\n {tWithFallback(t, 'workspacesList.createButtonShort', 'Create')}\n </span>\n </Button>\n </PermissionButton>\n </div>\n </div>\n\n {/* Search */}\n <div className=\"relative\" data-tour=\"workspaces-search-input\">\n <Search\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground\"\n size={20}\n />\n <Input\n placeholder={tWithFallback(t, 'workspacesList.searchPlaceholder', 'Search workspaces...')}\n value={searchValue}\n onChange={handleSearchChange}\n className=\"pl-[3.25rem]\"\n />\n </div>\n\n {/* Content */}\n <div className=\"space-y-4 sm:space-y-6\" data-tour=\"workspaces-view-container\">\n {isLoading ? (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div key={i} className=\"space-y-3 p-6 border rounded-lg\">\n <div className=\"flex items-center gap-3\">\n <Skeleton className=\"size-12 rounded-lg\" />\n <div className=\"space-y-2 flex-1\">\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-3 w-1/2\" />\n </div>\n </div>\n <Skeleton className=\"h-3 w-1/3\" />\n </div>\n ))}\n </div>\n ) : data?.items.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <div className=\"rounded-full bg-muted p-6 mb-4\">\n <Grid3X3 size={48} className=\"text-muted-foreground\" />\n </div>\n <h3 className=\"text-lg font-semibold mb-2\">\n {tWithFallback(t, 'workspacesList.emptyTitle', 'No workspaces found')}\n </h3>\n <p className=\"text-muted-foreground mb-4 max-w-sm\">\n {workspaceFilters.search\n ? tWithFallback(\n t,\n 'workspacesList.emptySearchHint',\n 'Try adjusting your search criteria'\n )\n : tWithFallback(\n t,\n 'workspacesList.emptyCreateHint',\n 'Get started by creating your first workspace'\n )}\n </p>\n {!workspaceFilters.search && (\n <PermissionButton\n permission={WORKSPACE_PERMISSIONS.WORKSPACE_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip={tWithFallback(\n t,\n 'workspacesList.createDeniedTooltip',\n \"You don't have permission to create workspaces\"\n )}\n >\n <Button onClick={handleCreateWorkspace} className=\"gap-2\">\n <Plus size={20} />\n {tWithFallback(\n t,\n 'workspacesList.createFirstButton',\n 'Create Your First Workspace'\n )}\n </Button>\n </PermissionButton>\n )}\n </div>\n ) : (\n <>\n {/* View */}\n {viewMode === 'list' ? (\n <div className=\"space-y-3\">\n {data?.items.map((workspace) => (\n <WorkspaceCard key={workspace.id} workspace={workspace} />\n ))}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4\">\n {data?.items.map((workspace) => (\n <WorkspaceCard key={workspace.id} workspace={workspace} />\n ))}\n </div>\n )}\n\n {/* Pagination info */}\n {data && data.total > 0 && (\n <div className=\"flex items-center justify-between text-sm text-muted-foreground\">\n <p>\n {tWithFallback(t, 'workspacesList.showing', 'Showing')} {data.items.length}{' '}\n {tWithFallback(t, 'workspacesList.of', 'of')} {data.total}{' '}\n {data.total !== 1\n ? tWithFallback(t, 'workspacesList.workspaces', 'workspaces')\n : tWithFallback(t, 'workspacesList.workspace', 'workspace')}\n </p>\n {data.hasMore && (\n <p className=\"text-xs\">\n {tWithFallback(\n t,\n 'workspacesList.moreAvailable',\n 'More workspaces available - pagination coming soon'\n )}\n </p>\n )}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -26,7 +26,33 @@ function n(n) {
|
|
|
26
26
|
}];
|
|
27
27
|
}) : [];
|
|
28
28
|
}
|
|
29
|
-
function r(
|
|
29
|
+
function r(n) {
|
|
30
|
+
return Array.isArray(n) ? n.flatMap((n) => {
|
|
31
|
+
if (!e(n)) return [];
|
|
32
|
+
let r = e(n.tag) ? n.tag : null, i = t(n.tagId), a = i ?? (r ? t(r.id) : void 0), o = r ? t(r.key) : void 0, s = r ? t(r.label) ?? t(r.name) : void 0;
|
|
33
|
+
if (!a || !i || !o || !s) return [];
|
|
34
|
+
let c = r && e(r.vocabulary) ? r.vocabulary : null;
|
|
35
|
+
return [{
|
|
36
|
+
id: a,
|
|
37
|
+
tagId: i,
|
|
38
|
+
key: o,
|
|
39
|
+
label: s,
|
|
40
|
+
value: r ? t(r.value) ?? null : null,
|
|
41
|
+
vocabularyId: r ? t(r.vocabularyId) ?? null : null,
|
|
42
|
+
vocabularyKey: c ? t(c.key) ?? null : null,
|
|
43
|
+
parentTagId: r ? t(r.parentId) ?? null : null,
|
|
44
|
+
hierarchyPath: r ? t(r.hierarchyPath) ?? null : null,
|
|
45
|
+
color: r ? t(r.color) ?? null : null,
|
|
46
|
+
icon: r ? t(r.icon) ?? null : null,
|
|
47
|
+
description: r ? t(r.description) ?? null : null,
|
|
48
|
+
metadata: e(n.metadata) ? n.metadata : null
|
|
49
|
+
}];
|
|
50
|
+
}) : [];
|
|
51
|
+
}
|
|
52
|
+
function i(e) {
|
|
53
|
+
return e?.tagAssignments === void 0 ? n(e?.tags) : r(e.tagAssignments);
|
|
54
|
+
}
|
|
55
|
+
function a(e) {
|
|
30
56
|
return {
|
|
31
57
|
id: e.id,
|
|
32
58
|
tagId: e.id,
|
|
@@ -44,6 +70,6 @@ function r(e) {
|
|
|
44
70
|
};
|
|
45
71
|
}
|
|
46
72
|
//#endregion
|
|
47
|
-
export {
|
|
73
|
+
export { i as getProjectDisplayTags, a as toProjectTag };
|
|
48
74
|
|
|
49
75
|
//# sourceMappingURL=projectTags.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectTags.js","names":[],"sources":["../../src/utils/projectTags.ts"],"sourcesContent":["import type { TagItem } from '@burdenoff/fe-libs/tag';\n\nimport type { ProjectTag } from '../types';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction asOptionalString(value: unknown): string | null | undefined {\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nexport function normalizeProjectTags(value: unknown): ProjectTag[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value.flatMap((entry) => {\n if (!isRecord(entry)) {\n return [];\n }\n\n const id = asOptionalString(entry['tagId']) ?? asOptionalString(entry['id']);\n const key = asOptionalString(entry['key']);\n const label = asOptionalString(entry['label']) ?? asOptionalString(entry['name']);\n\n if (!id || !key || !label) {\n return [];\n }\n\n return [\n {\n id,\n tagId: id,\n key,\n label,\n value: asOptionalString(entry['value']) ?? null,\n vocabularyId: asOptionalString(entry['vocabularyId']) ?? null,\n vocabularyKey: asOptionalString(entry['vocabularyKey']) ?? null,\n parentTagId: asOptionalString(entry['parentTagId']) ?? null,\n hierarchyPath: asOptionalString(entry['hierarchyPath']) ?? null,\n color: asOptionalString(entry['color']) ?? null,\n icon: asOptionalString(entry['icon']) ?? null,\n description: asOptionalString(entry['description']) ?? null,\n metadata: isRecord(entry['metadata']) ? entry['metadata'] : null,\n } satisfies ProjectTag,\n ];\n });\n}\n\nexport function toProjectTag(tag: TagItem): ProjectTag {\n return {\n id: tag.id,\n tagId: tag.id,\n key: tag.key,\n label: tag.label,\n value: tag.value ?? null,\n vocabularyId: tag.vocabularyId ?? null,\n vocabularyKey: tag.vocabularyKey ?? tag.vocabulary?.key ?? null,\n parentTagId: tag.parentId ?? null,\n hierarchyPath: tag.hierarchyPath ?? null,\n color: tag.color ?? null,\n icon: tag.icon ?? null,\n description: tag.description ?? null,\n metadata: null,\n };\n}\n"],"mappings":";AAIA,SAAS,EAAS,GAAkD;AAClE,QAAO,OAAO,KAAU,cAAY,KAAkB,CAAC,MAAM,QAAQ,EAAM;;AAG7E,SAAS,EAAiB,GAA2C;AACnE,QAAO,OAAO,KAAU,YAAY,EAAM,MAAM,CAAC,SAAS,IAAI,EAAM,MAAM,GAAG,KAAA;;AAG/E,SAAgB,EAAqB,GAA8B;AAKjE,QAJK,MAAM,QAAQ,EAAM,GAIlB,EAAM,SAAS,MAAU;AAC9B,MAAI,CAAC,EAAS,EAAM,CAClB,QAAO,EAAE;EAGX,IAAM,IAAK,EAAiB,EAAM,MAAS,IAAI,EAAiB,EAAM,GAAM,EACtE,IAAM,EAAiB,EAAM,IAAO,EACpC,IAAQ,EAAiB,EAAM,MAAS,IAAI,EAAiB,EAAM,KAAQ;AAMjF,SAJI,CAAC,KAAM,CAAC,KAAO,CAAC,IACX,EAAE,GAGJ,CACL;GACE;GACA,OAAO;GACP;GACA;GACA,OAAO,EAAiB,EAAM,MAAS,IAAI;GAC3C,cAAc,EAAiB,EAAM,aAAgB,IAAI;GACzD,eAAe,EAAiB,EAAM,cAAiB,IAAI;GAC3D,aAAa,EAAiB,EAAM,YAAe,IAAI;GACvD,eAAe,EAAiB,EAAM,cAAiB,IAAI;GAC3D,OAAO,EAAiB,EAAM,MAAS,IAAI;GAC3C,MAAM,EAAiB,EAAM,KAAQ,IAAI;GACzC,aAAa,EAAiB,EAAM,YAAe,IAAI;GACvD,UAAU,EAAS,EAAM,SAAY,GAAG,EAAM,WAAc;GAC7D,CACF;GACD,GAjCO,EAAE;;AAoCb,SAAgB,EAAa,GAA0B;AACrD,QAAO;EACL,IAAI,EAAI;EACR,OAAO,EAAI;EACX,KAAK,EAAI;EACT,OAAO,EAAI;EACX,OAAO,EAAI,SAAS;EACpB,cAAc,EAAI,gBAAgB;EAClC,eAAe,EAAI,iBAAiB,EAAI,YAAY,OAAO;EAC3D,aAAa,EAAI,YAAY;EAC7B,eAAe,EAAI,iBAAiB;EACpC,OAAO,EAAI,SAAS;EACpB,MAAM,EAAI,QAAQ;EAClB,aAAa,EAAI,eAAe;EAChC,UAAU;EACX"}
|
|
1
|
+
{"version":3,"file":"projectTags.js","names":[],"sources":["../../src/utils/projectTags.ts"],"sourcesContent":["import type { TagItem } from '@burdenoff/fe-libs/tag';\n\nimport type { Project, ProjectTag } from '../types';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction asOptionalString(value: unknown): string | null | undefined {\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n}\n\nexport function normalizeProjectTags(value: unknown): ProjectTag[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value.flatMap((entry) => {\n if (!isRecord(entry)) {\n return [];\n }\n\n const id = asOptionalString(entry['tagId']) ?? asOptionalString(entry['id']);\n const key = asOptionalString(entry['key']);\n const label = asOptionalString(entry['label']) ?? asOptionalString(entry['name']);\n\n if (!id || !key || !label) {\n return [];\n }\n\n return [\n {\n id,\n tagId: id,\n key,\n label,\n value: asOptionalString(entry['value']) ?? null,\n vocabularyId: asOptionalString(entry['vocabularyId']) ?? null,\n vocabularyKey: asOptionalString(entry['vocabularyKey']) ?? null,\n parentTagId: asOptionalString(entry['parentTagId']) ?? null,\n hierarchyPath: asOptionalString(entry['hierarchyPath']) ?? null,\n color: asOptionalString(entry['color']) ?? null,\n icon: asOptionalString(entry['icon']) ?? null,\n description: asOptionalString(entry['description']) ?? null,\n metadata: isRecord(entry['metadata']) ? entry['metadata'] : null,\n } satisfies ProjectTag,\n ];\n });\n}\n\nexport function normalizeProjectTagAssignments(value: unknown): ProjectTag[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value.flatMap((entry) => {\n if (!isRecord(entry)) {\n return [];\n }\n\n const tagRecord = isRecord(entry['tag']) ? entry['tag'] : null;\n const tagId = asOptionalString(entry['tagId']);\n const id = tagId ?? (tagRecord ? asOptionalString(tagRecord['id']) : undefined);\n const key = tagRecord ? asOptionalString(tagRecord['key']) : undefined;\n const label = tagRecord\n ? (asOptionalString(tagRecord['label']) ?? asOptionalString(tagRecord['name']))\n : undefined;\n\n if (!id || !tagId || !key || !label) {\n return [];\n }\n\n const vocabularyRecord =\n tagRecord && isRecord(tagRecord['vocabulary']) ? tagRecord['vocabulary'] : null;\n\n return [\n {\n id,\n tagId,\n key,\n label,\n value: tagRecord ? (asOptionalString(tagRecord['value']) ?? null) : null,\n vocabularyId: tagRecord ? (asOptionalString(tagRecord['vocabularyId']) ?? null) : null,\n vocabularyKey: vocabularyRecord\n ? (asOptionalString(vocabularyRecord['key']) ?? null)\n : null,\n parentTagId: tagRecord ? (asOptionalString(tagRecord['parentId']) ?? null) : null,\n hierarchyPath: tagRecord ? (asOptionalString(tagRecord['hierarchyPath']) ?? null) : null,\n color: tagRecord ? (asOptionalString(tagRecord['color']) ?? null) : null,\n icon: tagRecord ? (asOptionalString(tagRecord['icon']) ?? null) : null,\n description: tagRecord ? (asOptionalString(tagRecord['description']) ?? null) : null,\n metadata: isRecord(entry['metadata']) ? entry['metadata'] : null,\n } satisfies ProjectTag,\n ];\n });\n}\n\nexport function getProjectDisplayTags(\n project: Pick<Project, 'tags' | 'tagAssignments'> | null | undefined\n): ProjectTag[] {\n if (project?.tagAssignments !== undefined) {\n return normalizeProjectTagAssignments(project.tagAssignments);\n }\n\n return normalizeProjectTags(project?.tags);\n}\n\nexport function toProjectTag(tag: TagItem): ProjectTag {\n return {\n id: tag.id,\n tagId: tag.id,\n key: tag.key,\n label: tag.label,\n value: tag.value ?? null,\n vocabularyId: tag.vocabularyId ?? null,\n vocabularyKey: tag.vocabularyKey ?? tag.vocabulary?.key ?? null,\n parentTagId: tag.parentId ?? null,\n hierarchyPath: tag.hierarchyPath ?? null,\n color: tag.color ?? null,\n icon: tag.icon ?? null,\n description: tag.description ?? null,\n metadata: null,\n };\n}\n"],"mappings":"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"}
|