@stoker-platform/web-app 0.5.203 → 0.5.206
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/CHANGELOG.md +21 -0
- package/package.json +4 -4
- package/src/Collection.tsx +8 -1
- package/src/Filters.tsx +9 -0
- package/src/Record.tsx +22 -0
- package/src/RecordSidebar.tsx +3 -0
- package/src/SidebarFilters.tsx +59 -0
- package/src/utils/getFilterDisjunctions.ts +18 -0
- package/src/utils/performFullTextSearch.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @stoker-platform/web-app
|
|
2
2
|
|
|
3
|
+
## 0.5.206
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- feat: update Algolia search filters to match web app filters
|
|
8
|
+
|
|
9
|
+
## 0.5.205
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- fix: fix filter clearing issue
|
|
14
|
+
|
|
15
|
+
## 0.5.204
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- feat: add record sidebar filters
|
|
20
|
+
- @stoker-platform/node-client@0.5.80
|
|
21
|
+
- @stoker-platform/utils@0.5.71
|
|
22
|
+
- @stoker-platform/web-client@0.5.84
|
|
23
|
+
|
|
3
24
|
## 0.5.203
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stoker-platform/web-app",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.206",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"scripts": {
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"@radix-ui/react-tooltip": "^1.2.8",
|
|
52
52
|
"@react-google-maps/api": "^2.20.8",
|
|
53
53
|
"@sentry/react": "^10.56.0",
|
|
54
|
-
"@stoker-platform/node-client": "0.5.
|
|
55
|
-
"@stoker-platform/utils": "0.5.
|
|
56
|
-
"@stoker-platform/web-client": "0.5.
|
|
54
|
+
"@stoker-platform/node-client": "0.5.80",
|
|
55
|
+
"@stoker-platform/utils": "0.5.71",
|
|
56
|
+
"@stoker-platform/web-client": "0.5.84",
|
|
57
57
|
"@tanstack/react-table": "^8.21.3",
|
|
58
58
|
"@types/react": "18.3.13",
|
|
59
59
|
"@types/react-dom": "18.3.1",
|
package/src/Collection.tsx
CHANGED
|
@@ -534,7 +534,11 @@ function Collection({
|
|
|
534
534
|
hitsPerPage = batchSize
|
|
535
535
|
}
|
|
536
536
|
const constraints = getFilterConstraints(latestFilters, false, true) as [string, "==" | "in", unknown][]
|
|
537
|
-
const
|
|
537
|
+
const assigning =
|
|
538
|
+
queryIsAssigning && assignable && relationList && relationCollection && relationParent?.id
|
|
539
|
+
? { collection: relationCollection.labels.collection, id: relationParent.id }
|
|
540
|
+
: undefined
|
|
541
|
+
const objectIDs = await performFullTextSearch(collection, search, hitsPerPage, constraints, assigning)
|
|
538
542
|
searchResults.current = { ...searchResults.current, [key]: objectIDs }
|
|
539
543
|
if (
|
|
540
544
|
objectIDs.length > 0 &&
|
|
@@ -1359,6 +1363,9 @@ function Collection({
|
|
|
1359
1363
|
}
|
|
1360
1364
|
}
|
|
1361
1365
|
})
|
|
1366
|
+
if (relationList.showFilters) {
|
|
1367
|
+
excluded.push(...relationList.showFilters)
|
|
1368
|
+
}
|
|
1362
1369
|
}
|
|
1363
1370
|
return excluded
|
|
1364
1371
|
}, [isPreloadCacheEnabled, cardsConfig, statusField, tab, filters])
|
package/src/Filters.tsx
CHANGED
|
@@ -58,6 +58,7 @@ interface FiltersProps {
|
|
|
58
58
|
relationParent?: StokerRecord
|
|
59
59
|
assignable?: Assignable
|
|
60
60
|
isAssigning?: boolean
|
|
61
|
+
isSidebar?: boolean
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
export function Filters({
|
|
@@ -68,6 +69,7 @@ export function Filters({
|
|
|
68
69
|
relationParent,
|
|
69
70
|
assignable,
|
|
70
71
|
isAssigning,
|
|
72
|
+
isSidebar,
|
|
71
73
|
}: FiltersProps) {
|
|
72
74
|
const { labels, fields } = collection
|
|
73
75
|
const location = useLocation()
|
|
@@ -830,6 +832,13 @@ export function Filters({
|
|
|
830
832
|
filters.forEach((filter) => {
|
|
831
833
|
if (filter.type === "status" || filter.type === "range") return
|
|
832
834
|
if (relationList && relationList.field === filter.field) return
|
|
835
|
+
if (
|
|
836
|
+
"condition" in filter &&
|
|
837
|
+
filter.condition &&
|
|
838
|
+
!filter.condition(relationCollection, relationParent, isAssigning)
|
|
839
|
+
)
|
|
840
|
+
return
|
|
841
|
+
if (isSidebar && !relationList?.showFilters?.includes(filter.field)) return
|
|
833
842
|
const field = getField(fields, filter.field)
|
|
834
843
|
if (!field) return
|
|
835
844
|
if (filter.type === "select") {
|
package/src/Record.tsx
CHANGED
|
@@ -30,6 +30,7 @@ import { serverReadOnly } from "./utils/serverReadOnly"
|
|
|
30
30
|
import { useRouteLoading } from "./providers/LoadingProvider"
|
|
31
31
|
import { getRelationFields } from "./utils/getRelationFields"
|
|
32
32
|
import { FiltersProvider } from "./providers/FiltersProvider"
|
|
33
|
+
import { SidebarFilters } from "./SidebarFilters"
|
|
33
34
|
import Collection from "./Collection"
|
|
34
35
|
import { Breadcrumbs } from "./Breadcrumbs"
|
|
35
36
|
import { Separator } from "./components/ui/separator"
|
|
@@ -82,6 +83,7 @@ export const Record = ({ collection }: { collection: CollectionSchema }) => {
|
|
|
82
83
|
|
|
83
84
|
const [isAssigning, setIsAssigning] = useState<Record<string, boolean>>({})
|
|
84
85
|
const [assignable, setAssignable] = useState<Assignable[] | undefined>(undefined)
|
|
86
|
+
const [sidebarFiltersContainer, setSidebarFiltersContainer] = useState<HTMLDivElement | null>(null)
|
|
85
87
|
|
|
86
88
|
useEffect(() => {
|
|
87
89
|
if (id && record && record.id !== id) {
|
|
@@ -213,6 +215,7 @@ export const Record = ({ collection }: { collection: CollectionSchema }) => {
|
|
|
213
215
|
customRecordPages={customRecordPages}
|
|
214
216
|
isAssigning={isAssigning}
|
|
215
217
|
setIsAssigning={setIsAssigning}
|
|
218
|
+
filtersContainerRef={setSidebarFiltersContainer}
|
|
216
219
|
/>
|
|
217
220
|
<Routes>
|
|
218
221
|
<Route
|
|
@@ -277,6 +280,25 @@ export const Record = ({ collection }: { collection: CollectionSchema }) => {
|
|
|
277
280
|
</div>
|
|
278
281
|
</>
|
|
279
282
|
)}
|
|
283
|
+
{sidebarFiltersContainer && (
|
|
284
|
+
<SidebarFilters
|
|
285
|
+
key={`${relationList.collection}-sidebar-filters`}
|
|
286
|
+
container={sidebarFiltersContainer}
|
|
287
|
+
collection={relationCollection}
|
|
288
|
+
relationList={relationList}
|
|
289
|
+
relationCollection={collection}
|
|
290
|
+
relationParent={record}
|
|
291
|
+
assignable={assignable?.find(
|
|
292
|
+
(item: Assignable) =>
|
|
293
|
+
item.collection === relationList.collection,
|
|
294
|
+
)}
|
|
295
|
+
isAssigning={
|
|
296
|
+
isAssigning?.[
|
|
297
|
+
relationList.collection.toLowerCase()
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
/>
|
|
301
|
+
)}
|
|
280
302
|
<Collection
|
|
281
303
|
key={`${relationList.collection}-collection`}
|
|
282
304
|
collection={relationCollection}
|
package/src/RecordSidebar.tsx
CHANGED
|
@@ -35,12 +35,14 @@ export const RecordSidebar = ({
|
|
|
35
35
|
customRecordPages,
|
|
36
36
|
isAssigning,
|
|
37
37
|
setIsAssigning,
|
|
38
|
+
filtersContainerRef,
|
|
38
39
|
}: {
|
|
39
40
|
record: StokerRecord
|
|
40
41
|
collection: CollectionSchema
|
|
41
42
|
customRecordPages?: CustomRecordPage[]
|
|
42
43
|
isAssigning: Record<string, boolean>
|
|
43
44
|
setIsAssigning: (isAssigning: Record<string, boolean>) => void
|
|
45
|
+
filtersContainerRef?: (element: HTMLDivElement | null) => void
|
|
44
46
|
}) => {
|
|
45
47
|
const { labels } = collection
|
|
46
48
|
const { path, id } = useParams()
|
|
@@ -308,6 +310,7 @@ export const RecordSidebar = ({
|
|
|
308
310
|
)}
|
|
309
311
|
</div>
|
|
310
312
|
</SidebarMenu>
|
|
313
|
+
<div ref={filtersContainerRef} />
|
|
311
314
|
</SidebarGroupContent>
|
|
312
315
|
</SidebarGroup>
|
|
313
316
|
</SidebarContent>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Assignable, CollectionSchema, RelationList, StokerRecord } from "@stoker-platform/types"
|
|
2
|
+
import { useMemo } from "react"
|
|
3
|
+
import { createPortal } from "react-dom"
|
|
4
|
+
import { Filters } from "./Filters"
|
|
5
|
+
import { useFilters } from "./providers/FiltersProvider"
|
|
6
|
+
import { Separator } from "./components/ui/separator"
|
|
7
|
+
|
|
8
|
+
export const SidebarFilters = ({
|
|
9
|
+
container,
|
|
10
|
+
collection,
|
|
11
|
+
relationList,
|
|
12
|
+
relationCollection,
|
|
13
|
+
relationParent,
|
|
14
|
+
assignable,
|
|
15
|
+
isAssigning,
|
|
16
|
+
}: {
|
|
17
|
+
container: HTMLElement
|
|
18
|
+
collection: CollectionSchema
|
|
19
|
+
relationList: RelationList
|
|
20
|
+
relationCollection: CollectionSchema
|
|
21
|
+
relationParent: StokerRecord
|
|
22
|
+
assignable?: Assignable
|
|
23
|
+
isAssigning?: boolean
|
|
24
|
+
}) => {
|
|
25
|
+
const { filters } = useFilters()
|
|
26
|
+
const showFilters = relationList.showFilters
|
|
27
|
+
|
|
28
|
+
const excluded = useMemo(
|
|
29
|
+
() =>
|
|
30
|
+
filters
|
|
31
|
+
.filter((filter) => filter.type !== "status" && filter.type !== "range")
|
|
32
|
+
.map((filter) => filter.field)
|
|
33
|
+
.filter((field) => !showFilters?.includes(field)),
|
|
34
|
+
[filters, showFilters],
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if (!showFilters?.length) return null
|
|
38
|
+
const hasFiltersToShow = filters.some(
|
|
39
|
+
(filter) => filter.type !== "status" && filter.type !== "range" && showFilters.includes(filter.field),
|
|
40
|
+
)
|
|
41
|
+
if (!hasFiltersToShow) return null
|
|
42
|
+
|
|
43
|
+
return createPortal(
|
|
44
|
+
<div className="flex flex-col gap-4 px-2 pt-2">
|
|
45
|
+
<Separator />
|
|
46
|
+
<Filters
|
|
47
|
+
collection={collection}
|
|
48
|
+
excluded={excluded}
|
|
49
|
+
relationList={relationList}
|
|
50
|
+
relationCollection={relationCollection}
|
|
51
|
+
relationParent={relationParent}
|
|
52
|
+
assignable={assignable}
|
|
53
|
+
isAssigning={isAssigning}
|
|
54
|
+
isSidebar={true}
|
|
55
|
+
/>
|
|
56
|
+
</div>,
|
|
57
|
+
container,
|
|
58
|
+
)
|
|
59
|
+
}
|
|
@@ -51,5 +51,23 @@ export const getFilterDisjunctions = (collection: CollectionSchema, options?: Fi
|
|
|
51
51
|
incrementDisjunctions(2)
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
+
if (
|
|
55
|
+
options?.isAssigning &&
|
|
56
|
+
options.relationList &&
|
|
57
|
+
options.relationParent?.id &&
|
|
58
|
+
options.assignable?.includeValueInFilters?.length &&
|
|
59
|
+
options.filters
|
|
60
|
+
) {
|
|
61
|
+
const activeOrCount = options.filters.filter(
|
|
62
|
+
(filter) =>
|
|
63
|
+
filter.type === "select" &&
|
|
64
|
+
filter.value &&
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
66
|
+
options.assignable!.includeValueInFilters!.some((item) => item.field === filter.field),
|
|
67
|
+
).length
|
|
68
|
+
for (let i = 0; i < activeOrCount; i++) {
|
|
69
|
+
incrementDisjunctions(2)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
54
72
|
return disjunctions
|
|
55
73
|
}
|
|
@@ -7,6 +7,7 @@ export const performFullTextSearch = async (
|
|
|
7
7
|
search: string,
|
|
8
8
|
hitsPerPage: number,
|
|
9
9
|
constraints?: [string, "==" | "in", unknown][],
|
|
10
|
+
assigning?: { collection: string; id: string },
|
|
10
11
|
) => {
|
|
11
12
|
const { labels } = collection
|
|
12
13
|
const firebaseFunctions = getFunctions(getApp(), import.meta.env.STOKER_FB_FUNCTIONS_REGION)
|
|
@@ -16,6 +17,7 @@ export const performFullTextSearch = async (
|
|
|
16
17
|
query: search,
|
|
17
18
|
hitsPerPage,
|
|
18
19
|
constraints,
|
|
20
|
+
assigning,
|
|
19
21
|
})) as { data: string[] }
|
|
20
22
|
return results.data
|
|
21
23
|
}
|