@globalbrain/sefirot 4.37.1 → 4.38.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/lib/blocks/lens/components/LensCatalog.vue +12 -2
- package/lib/blocks/lens/components/LensCatalogControl.vue +1 -1
- package/lib/blocks/lens/components/LensTable.vue +5 -3
- package/lib/components/STable.vue +17 -8
- package/lib/components/STableCell.vue +6 -2
- package/lib/http/Http.ts +3 -40
- package/lib/support/Http.ts +42 -0
- package/package.json +9 -9
|
@@ -97,7 +97,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
97
97
|
canSort: true
|
|
98
98
|
})
|
|
99
99
|
|
|
100
|
-
const selected = defineModel<
|
|
100
|
+
const selected = defineModel<any[]>('selected')
|
|
101
101
|
const hideConditions = defineModel<boolean>('hideConditions', { default: false })
|
|
102
102
|
|
|
103
103
|
const emit = defineEmits<{
|
|
@@ -320,7 +320,7 @@ function onViewUpdated(newSelect: string[], newSelectable: string[], overrides:
|
|
|
320
320
|
emit('overrides-updated', _overrides.value)
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
-
function onUpdateSelected(value:
|
|
323
|
+
function onUpdateSelected(value: any[]) {
|
|
324
324
|
selected.value = value
|
|
325
325
|
}
|
|
326
326
|
|
|
@@ -339,6 +339,16 @@ function onNext() {
|
|
|
339
339
|
}
|
|
340
340
|
|
|
341
341
|
defineExpose({
|
|
342
|
+
/**
|
|
343
|
+
* Retrieve the current records in the catalog. This method is required when
|
|
344
|
+
* the parent component needs to access the records directly, for example, to
|
|
345
|
+
* handle mapping for selected records. Like `updateRecords`, this is also a
|
|
346
|
+
* hacky method and should be avoided if possible.
|
|
347
|
+
*/
|
|
348
|
+
records(): Record<string, any>[] {
|
|
349
|
+
return result.value?.data ?? []
|
|
350
|
+
},
|
|
351
|
+
|
|
342
352
|
/**
|
|
343
353
|
* Mutates the fetched records directly. This exposed method can be used to
|
|
344
354
|
* do in-place updates of records from the parent component. However, it's
|
|
@@ -14,11 +14,12 @@ const props = defineProps<{
|
|
|
14
14
|
result?: LensResult
|
|
15
15
|
overrides?: Record<string, Partial<FieldData>>
|
|
16
16
|
loading: boolean
|
|
17
|
-
selected?:
|
|
17
|
+
selected?: any[]
|
|
18
|
+
indexField?: string
|
|
18
19
|
}>()
|
|
19
20
|
|
|
20
21
|
const emit = defineEmits<{
|
|
21
|
-
'update:selected': [value:
|
|
22
|
+
'update:selected': [value: any[]]
|
|
22
23
|
'filter-updated': [filter: any[]]
|
|
23
24
|
'sort-updated': [sort: LensQuerySort]
|
|
24
25
|
'cell-clicked': [value: any, record: any]
|
|
@@ -87,10 +88,11 @@ const table = useTable({
|
|
|
87
88
|
records,
|
|
88
89
|
orders,
|
|
89
90
|
columns,
|
|
91
|
+
indexField: props.indexField,
|
|
90
92
|
borderless: true
|
|
91
93
|
})
|
|
92
94
|
|
|
93
|
-
function onSelect(value?:
|
|
95
|
+
function onSelect(value?: any[]) {
|
|
94
96
|
emit('update:selected', value ?? [])
|
|
95
97
|
}
|
|
96
98
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts" generic="S extends any = undefined">
|
|
2
2
|
import { useVirtualizer } from '@tanstack/vue-virtual'
|
|
3
3
|
import { useResizeObserver } from '@vueuse/core'
|
|
4
|
-
import
|
|
4
|
+
import isEqual from 'lodash-es/isEqual'
|
|
5
5
|
import { type CSSProperties, computed, nextTick, reactive, ref, toValue, unref, useTemplateRef, watch } from 'vue'
|
|
6
6
|
import { type Table } from '../composables/Table'
|
|
7
7
|
import { type VirtualRow, useTableAnimation } from '../composables/TableAnimation'
|
|
@@ -185,10 +185,9 @@ const control = computed({
|
|
|
185
185
|
}
|
|
186
186
|
})
|
|
187
187
|
|
|
188
|
-
watch(indexes, (newValue
|
|
188
|
+
watch(indexes, (newValue) => {
|
|
189
189
|
if (Array.isArray(selected.value)) {
|
|
190
|
-
|
|
191
|
-
updateSelected(selected.value.filter((item) => !removed.includes(item)))
|
|
190
|
+
updateSelected(newValue.filter((item) => includesSelection(selected.value as any[], item)))
|
|
192
191
|
}
|
|
193
192
|
})
|
|
194
193
|
|
|
@@ -431,6 +430,10 @@ function getCell(key: string, index: number) {
|
|
|
431
430
|
return isSummary(index) && col?.summaryCell ? col?.summaryCell : col?.cell
|
|
432
431
|
}
|
|
433
432
|
|
|
433
|
+
function includesSelection(items: unknown[], target: unknown): boolean {
|
|
434
|
+
return items.some((item) => isEqual(item, target))
|
|
435
|
+
}
|
|
436
|
+
|
|
434
437
|
function updateSelected(items: any) {
|
|
435
438
|
if (Array.isArray(selected.value)) {
|
|
436
439
|
selected.value = [...items] as any
|
|
@@ -440,11 +443,17 @@ function updateSelected(items: any) {
|
|
|
440
443
|
}
|
|
441
444
|
|
|
442
445
|
function addSelected(item: any) {
|
|
443
|
-
|
|
446
|
+
const items = selected.value as any[]
|
|
447
|
+
|
|
448
|
+
if (includesSelection(items, item)) {
|
|
449
|
+
return
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
updateSelected([...items, item])
|
|
444
453
|
}
|
|
445
454
|
|
|
446
455
|
function removeSelected(item: any) {
|
|
447
|
-
updateSelected((selected.value as any[]).filter((i) => i
|
|
456
|
+
updateSelected((selected.value as any[]).filter((i) => !isEqual(i, item)))
|
|
448
457
|
}
|
|
449
458
|
|
|
450
459
|
function getColWidth(key: string) {
|
|
@@ -603,13 +612,13 @@ function onResizeEnd(data: { columnName: string; finalWidth: string }) {
|
|
|
603
612
|
<template v-if="key === '__select' && !isSummary(item.index)">
|
|
604
613
|
<SInputCheckbox
|
|
605
614
|
v-if="Array.isArray(selected)"
|
|
606
|
-
:model-value="selected
|
|
615
|
+
:model-value="includesSelection(selected, indexes[item.index])"
|
|
607
616
|
:disabled="options.disableSelection?.(recordsWithSummary[item.index]) === true"
|
|
608
617
|
@update:model-value="(c) => (c ? addSelected : removeSelected)(indexes[item.index])"
|
|
609
618
|
/>
|
|
610
619
|
<SInputRadio
|
|
611
620
|
v-else
|
|
612
|
-
:model-value="selected
|
|
621
|
+
:model-value="isEqual(selected, indexes[item.index])"
|
|
613
622
|
:disabled="options.disableSelection?.(recordsWithSummary[item.index]) === true"
|
|
614
623
|
@update:model-value="(c) => updateSelected(c ? indexes[item.index] : null)"
|
|
615
624
|
/>
|
|
@@ -26,6 +26,10 @@ const props = defineProps<{
|
|
|
26
26
|
const computedCell = computed<TableCell | undefined>(() =>
|
|
27
27
|
typeof props.cell === 'function' ? props.cell(props.value, props.record) : props.cell
|
|
28
28
|
)
|
|
29
|
+
|
|
30
|
+
const valueIsImagePath = computed(() => {
|
|
31
|
+
return typeof props.value === 'string' && props.value.includes('/')
|
|
32
|
+
})
|
|
29
33
|
</script>
|
|
30
34
|
|
|
31
35
|
<template>
|
|
@@ -89,8 +93,8 @@ const computedCell = computed<TableCell | undefined>(() =>
|
|
|
89
93
|
v-else-if="computedCell.type === 'avatar'"
|
|
90
94
|
:value
|
|
91
95
|
:record
|
|
92
|
-
:image="computedCell.image ?? (
|
|
93
|
-
:name="computedCell.name ?? (
|
|
96
|
+
:image="computedCell.image ?? (valueIsImagePath ? value : null)"
|
|
97
|
+
:name="computedCell.name ?? (valueIsImagePath ? null : value)"
|
|
94
98
|
:link="computedCell.link"
|
|
95
99
|
:color="computedCell.color"
|
|
96
100
|
:on-click="computedCell.onClick"
|
package/lib/http/Http.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { parse as parseCookie } from '@tinyhttp/cookie'
|
|
|
3
3
|
import FileSaver from 'file-saver'
|
|
4
4
|
import { FetchError, type FetchOptions, type FetchResponse } from 'ofetch'
|
|
5
5
|
import { stringify } from 'qs'
|
|
6
|
+
import { objectToFormData } from '../support/Http'
|
|
6
7
|
|
|
7
8
|
type Config = ReturnType<typeof import('../stores/HttpConfig').useHttpConfig>
|
|
8
9
|
|
|
@@ -87,7 +88,7 @@ export class Http {
|
|
|
87
88
|
})
|
|
88
89
|
|
|
89
90
|
if (hasFile) {
|
|
90
|
-
const formData =
|
|
91
|
+
const formData = objectToFormData(body, undefined, undefined, true)
|
|
91
92
|
formData.append(this.config.payloadKey, payload)
|
|
92
93
|
body = formData
|
|
93
94
|
} else {
|
|
@@ -111,7 +112,7 @@ export class Http {
|
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
async upload<T = any>(url: string, body?: any, options?: FetchOptions): Promise<T> {
|
|
114
|
-
return this.post<T>(url,
|
|
115
|
+
return this.post<T>(url, objectToFormData(body), options)
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
async download(url: string, options?: FetchOptions): Promise<void> {
|
|
@@ -130,44 +131,6 @@ export class Http {
|
|
|
130
131
|
|
|
131
132
|
FileSaver.saveAs(blob, filename as string)
|
|
132
133
|
}
|
|
133
|
-
|
|
134
|
-
private objectToFormData(
|
|
135
|
-
obj: any,
|
|
136
|
-
form?: FormData,
|
|
137
|
-
namespace?: string,
|
|
138
|
-
onlyFiles = false
|
|
139
|
-
): FormData {
|
|
140
|
-
const fd = form || new FormData()
|
|
141
|
-
let formKey: string
|
|
142
|
-
|
|
143
|
-
Object.keys(obj).forEach((property) => {
|
|
144
|
-
if (namespace) {
|
|
145
|
-
formKey = `${namespace}[${property}]`
|
|
146
|
-
} else {
|
|
147
|
-
formKey = property
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (obj[property] === undefined) {
|
|
151
|
-
return
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
typeof obj[property] === 'object'
|
|
156
|
-
&& !(obj[property] instanceof Blob)
|
|
157
|
-
&& obj[property] !== null
|
|
158
|
-
) {
|
|
159
|
-
this.objectToFormData(obj[property], fd, property, onlyFiles)
|
|
160
|
-
} else {
|
|
161
|
-
const value = obj[property] === null ? '' : obj[property]
|
|
162
|
-
if (onlyFiles && !(value instanceof Blob)) {
|
|
163
|
-
return
|
|
164
|
-
}
|
|
165
|
-
fd.append(formKey, value)
|
|
166
|
-
}
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
return fd
|
|
170
|
-
}
|
|
171
134
|
}
|
|
172
135
|
|
|
173
136
|
export function isFetchError(e: unknown): e is FetchError {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export function objectToFormData(
|
|
2
|
+
obj: any,
|
|
3
|
+
form?: FormData,
|
|
4
|
+
namespace?: string,
|
|
5
|
+
onlyFiles = false
|
|
6
|
+
): FormData {
|
|
7
|
+
const fd = form || new FormData()
|
|
8
|
+
|
|
9
|
+
if (obj == null) {
|
|
10
|
+
return fd
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let formKey: string
|
|
14
|
+
|
|
15
|
+
Object.keys(obj).forEach((property) => {
|
|
16
|
+
if (namespace) {
|
|
17
|
+
formKey = `${namespace}[${property}]`
|
|
18
|
+
} else {
|
|
19
|
+
formKey = property
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (obj[property] === undefined) {
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (
|
|
27
|
+
typeof obj[property] === 'object'
|
|
28
|
+
&& !(obj[property] instanceof Blob)
|
|
29
|
+
&& obj[property] !== null
|
|
30
|
+
) {
|
|
31
|
+
objectToFormData(obj[property], fd, formKey, onlyFiles)
|
|
32
|
+
} else {
|
|
33
|
+
const value = obj[property] === null ? '' : obj[property]
|
|
34
|
+
if (onlyFiles && !(value instanceof Blob)) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
fd.append(formKey, value)
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
return fd
|
|
42
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalbrain/sefirot",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.38.1",
|
|
4
4
|
"description": "Vue Components for Global Brain Design System.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"components",
|
|
@@ -53,14 +53,14 @@
|
|
|
53
53
|
"coverage": "vitest run --coverage",
|
|
54
54
|
"test": "pnpm run type && pnpm run lint && pnpm run coverage",
|
|
55
55
|
"test:fail": "pnpm run type && pnpm run lint:fail && pnpm run coverage",
|
|
56
|
-
"release": "release-it"
|
|
56
|
+
"release": "pnpm whoami >/dev/null 2>&1 || pnpm login && release-it"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"@iconify-json/ph": "^1.2.2",
|
|
60
60
|
"@iconify-json/ri": "^1.2.10",
|
|
61
61
|
"@popperjs/core": "^2.11.8",
|
|
62
|
-
"@sentry/browser": "^10.
|
|
63
|
-
"@sentry/vue": "^10.
|
|
62
|
+
"@sentry/browser": "^10.40.0",
|
|
63
|
+
"@sentry/vue": "^10.40.0",
|
|
64
64
|
"@tanstack/vue-virtual": "3.0.0-beta.62",
|
|
65
65
|
"@tinyhttp/content-disposition": "^2.2.4",
|
|
66
66
|
"@tinyhttp/cookie": "^2.1.1",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@types/markdown-it": "^14.1.2",
|
|
73
73
|
"@types/qs": "^6.14.0",
|
|
74
74
|
"@vitejs/plugin-vue": "^6.0.4",
|
|
75
|
-
"@vue/reactivity": "^3.5.
|
|
75
|
+
"@vue/reactivity": "^3.5.29",
|
|
76
76
|
"@vuelidate/core": "^2.0.3",
|
|
77
77
|
"@vuelidate/validators": "^2.0.4",
|
|
78
78
|
"@vueuse/core": "^14.2.1",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"unplugin-icons": "^23.0.1",
|
|
98
98
|
"v-calendar": "3.0.1",
|
|
99
99
|
"vite": "^7.3.1",
|
|
100
|
-
"vue": "^3.5.
|
|
100
|
+
"vue": "^3.5.29",
|
|
101
101
|
"vue-draggable-plus": "^0.6.1",
|
|
102
102
|
"vue-router": "^4.6.4"
|
|
103
103
|
},
|
|
@@ -105,8 +105,8 @@
|
|
|
105
105
|
"@globalbrain/eslint-config": "^3.0.1",
|
|
106
106
|
"@histoire/plugin-vue": "1.0.0-beta.1",
|
|
107
107
|
"@release-it/conventional-changelog": "^10.0.5",
|
|
108
|
-
"@types/jsdom": "^
|
|
109
|
-
"@types/node": "^25.3.
|
|
108
|
+
"@types/jsdom": "^28.0.0",
|
|
109
|
+
"@types/node": "^25.3.3",
|
|
110
110
|
"@vitest/coverage-v8": "^4.0.18",
|
|
111
111
|
"@vue/test-utils": "^2.4.6",
|
|
112
112
|
"eslint": "^9.39.3",
|
|
@@ -118,5 +118,5 @@
|
|
|
118
118
|
"vitest": "^4.0.18",
|
|
119
119
|
"vue-tsc": "^3.2.5"
|
|
120
120
|
},
|
|
121
|
-
"packageManager": "pnpm@10.30.
|
|
121
|
+
"packageManager": "pnpm@10.30.3"
|
|
122
122
|
}
|