@globalbrain/sefirot 4.46.0 → 4.48.0
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/FieldData.ts +27 -0
- package/lib/blocks/lens/ResourceFetcher.ts +5 -1
- package/lib/blocks/lens/Rule.ts +10 -0
- package/lib/blocks/lens/components/LensCatalog.vue +826 -39
- package/lib/blocks/lens/components/LensSheet.vue +465 -0
- package/lib/blocks/lens/components/LensSheetField.vue +210 -0
- package/lib/blocks/lens/components/LensTable.vue +79 -5
- package/lib/blocks/lens/components/LensTableEditableCell.vue +285 -0
- package/lib/blocks/lens/composables/CatalogUrlQuerySync.ts +146 -0
- package/lib/blocks/lens/composables/LensEdit.ts +59 -0
- package/lib/blocks/lens/composables/LensInlineEdit.ts +36 -0
- package/lib/blocks/lens/composables/ResourceFetcher.ts +20 -7
- package/lib/blocks/lens/composables/SetupLens.ts +2 -0
- package/lib/blocks/lens/fields/AvatarField.ts +43 -0
- package/lib/blocks/lens/fields/ContentField.ts +21 -10
- package/lib/blocks/lens/fields/Field.ts +26 -1
- package/lib/blocks/lens/fields/FileUploadField.ts +8 -0
- package/lib/blocks/lens/fields/RelatedManyField.ts +44 -7
- package/lib/blocks/lens/fields/RelatedOneField.ts +42 -7
- package/lib/blocks/lens/validation/RuleMapper.ts +22 -3
- package/lib/blocks/lens/validation/ServerErrors.ts +25 -0
- package/lib/components/SInputSwitches.vue +2 -2
- package/lib/components/SSheet.vue +104 -0
- package/lib/composables/Api.ts +18 -10
- package/lib/composables/Url.ts +19 -2
- package/lib/styles/variables.css +1 -0
- package/lib/validation/rules/index.ts +1 -0
- package/lib/validation/rules/slackChannelLink.ts +15 -0
- package/lib/validation/validators/index.ts +1 -0
- package/lib/validation/validators/slackChannelLink.ts +52 -0
- package/package.json +17 -17
package/lib/composables/Url.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { type LocationQuery, useRoute, useRouter } from 'vue-router'
|
|
|
4
4
|
|
|
5
5
|
export interface UseUrlQuerySyncOptions {
|
|
6
6
|
casts?: Record<string, (value: any) => any>
|
|
7
|
+
serializers?: Record<string, (value: any) => string>
|
|
7
8
|
exclude?: string[]
|
|
8
9
|
}
|
|
9
10
|
|
|
@@ -16,7 +17,7 @@ export interface UseUrlQuerySyncOptions {
|
|
|
16
17
|
*/
|
|
17
18
|
export function useUrlQuerySync(
|
|
18
19
|
state: MaybeRef<Record<string, any>>,
|
|
19
|
-
{ casts = {}, exclude = [] }: UseUrlQuerySyncOptions = {}
|
|
20
|
+
{ casts = {}, serializers = {}, exclude = [] }: UseUrlQuerySyncOptions = {}
|
|
20
21
|
): void {
|
|
21
22
|
const route = useRoute()
|
|
22
23
|
const router = useRouter()
|
|
@@ -78,11 +79,27 @@ export function useUrlQuerySync(
|
|
|
78
79
|
|
|
79
80
|
const currentQuery = normalizeQuery(route.query)
|
|
80
81
|
|
|
82
|
+
// Both sides of this comparison hold deserialized values: `newQuery`
|
|
83
|
+
// carries raw state values and `normalizeQuery` runs `casts` on the
|
|
84
|
+
// URL params. Serialization must therefore only happen on the final
|
|
85
|
+
// write below — serializing before the comparison would make a
|
|
86
|
+
// round-tripped value always look different from the state and cause
|
|
87
|
+
// an endless replace loop.
|
|
81
88
|
if (!isEqual(newQuery, currentQuery)) {
|
|
82
|
-
await router.replace({ query: unflattenObject(newQuery) })
|
|
89
|
+
await router.replace({ query: unflattenObject(serializeQuery(newQuery)) })
|
|
83
90
|
}
|
|
84
91
|
}
|
|
85
92
|
|
|
93
|
+
function serializeQuery(query: Record<string, any>): Record<string, any> {
|
|
94
|
+
const result: Record<string, any> = {}
|
|
95
|
+
|
|
96
|
+
for (const key in query) {
|
|
97
|
+
result[key] = serializers[key] ? serializers[key](query[key]) : query[key]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return result
|
|
101
|
+
}
|
|
102
|
+
|
|
86
103
|
function normalizeQuery(query: LocationQuery): Record<string, any> {
|
|
87
104
|
const flattenedQuery = flattenObject(query)
|
|
88
105
|
const result: Record<string, any> = {}
|
package/lib/styles/variables.css
CHANGED
|
@@ -24,6 +24,7 @@ export { requiredIf } from './requiredIf'
|
|
|
24
24
|
export { requiredYmd } from './requiredYmd'
|
|
25
25
|
export { requiredYmdIf } from './requiredYmdIf'
|
|
26
26
|
export { rule } from './rule'
|
|
27
|
+
export { slackChannelLink } from './slackChannelLink'
|
|
27
28
|
export { slackChannelName } from './slackChannelName'
|
|
28
29
|
export { url } from './url'
|
|
29
30
|
export { ymd } from './ymd'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createRule } from '../Rule'
|
|
2
|
+
import { slackChannelLink as baseSlackChannelLink } from '../validators'
|
|
3
|
+
|
|
4
|
+
export const message = {
|
|
5
|
+
en: 'The slack channel link is invalid.',
|
|
6
|
+
ja: 'Slackチャンネルリンクの形式が正しくありません。'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function slackChannelLink(msg?: string) {
|
|
10
|
+
return createRule({
|
|
11
|
+
message: ({ lang }) => msg ?? message[lang],
|
|
12
|
+
optional: true,
|
|
13
|
+
validation: baseSlackChannelLink
|
|
14
|
+
})
|
|
15
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const channelIdRE = /^[CG][A-Z0-9]{6,}$/
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks that the value identifies a Slack channel. Accepts a channel link as
|
|
5
|
+
* copied from Slack (`https://<workspace>.slack.com/archives/<id>`, with or
|
|
6
|
+
* without a trailing message path), a browser URL
|
|
7
|
+
* (`https://app.slack.com/client/<team-id>/<id>`), or a raw channel ID.
|
|
8
|
+
* Mirrors the backend `slack_channel_link` rule definition.
|
|
9
|
+
*/
|
|
10
|
+
export function slackChannelLink(value: unknown): boolean {
|
|
11
|
+
return typeof value === 'string' && extractChannelId(value) !== null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function extractChannelId(value: string): string | null {
|
|
15
|
+
const trimmed = value.trim()
|
|
16
|
+
|
|
17
|
+
if (channelIdRE.test(trimmed)) {
|
|
18
|
+
return trimmed
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return extractChannelIdFromUrl(trimmed)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function extractChannelIdFromUrl(value: string): string | null {
|
|
25
|
+
let url: URL
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
url = new URL(value)
|
|
29
|
+
} catch {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (url.protocol !== 'https:') {
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (url.hostname !== 'slack.com' && !url.hostname.endsWith('.slack.com')) {
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const segments = url.pathname.split('/').filter((segment) => segment !== '')
|
|
42
|
+
|
|
43
|
+
let candidate: string | undefined
|
|
44
|
+
|
|
45
|
+
if (segments[0] === 'archives') {
|
|
46
|
+
candidate = segments[1]
|
|
47
|
+
} else if (url.hostname === 'app.slack.com' && segments[0] === 'client') {
|
|
48
|
+
candidate = segments[2]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return candidate !== undefined && channelIdRE.test(candidate) ? candidate : null
|
|
52
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalbrain/sefirot",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.48.0",
|
|
4
4
|
"description": "Vue Components for Global Brain Design System.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"components",
|
|
@@ -53,14 +53,14 @@
|
|
|
53
53
|
"test:coverage": "vitest run --coverage",
|
|
54
54
|
"check": "pnpm run --aggregate-output '/^(type|lint|test:fail)$/'",
|
|
55
55
|
"check:fail": "pnpm run --aggregate-output '/^(type|lint:fail|test:fail)$/'",
|
|
56
|
-
"release": "
|
|
56
|
+
"release": "npm whoami >/dev/null 2>&1 || npm 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.58.0",
|
|
63
|
+
"@sentry/vue": "^10.58.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",
|
|
@@ -71,15 +71,15 @@
|
|
|
71
71
|
"@types/markdown-it": "^14.1.2",
|
|
72
72
|
"@types/qs": "^6.15.1",
|
|
73
73
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
74
|
-
"@vue/reactivity": "^3.5.
|
|
74
|
+
"@vue/reactivity": "^3.5.38",
|
|
75
75
|
"@vuelidate/core": "^2.0.3",
|
|
76
76
|
"@vuelidate/validators": "^2.0.4",
|
|
77
77
|
"@vueuse/core": "^14.3.0",
|
|
78
78
|
"body-scroll-lock": "4.0.0-beta.0",
|
|
79
79
|
"d3": "^7.9.0",
|
|
80
80
|
"dayjs": "^1.11.21",
|
|
81
|
-
"dompurify": "^3.4.
|
|
82
|
-
"fuse.js": "^7.
|
|
81
|
+
"dompurify": "^3.4.11",
|
|
82
|
+
"fuse.js": "^7.4.2",
|
|
83
83
|
"html2canvas": "^1.4.1",
|
|
84
84
|
"jsdom": "^29.1.1",
|
|
85
85
|
"lodash-es": "^4.18.1",
|
|
@@ -94,8 +94,8 @@
|
|
|
94
94
|
"qs": "^6.15.2",
|
|
95
95
|
"unplugin-icons": "^23.0.1",
|
|
96
96
|
"v-calendar": "3.0.1",
|
|
97
|
-
"vite": "^7.3.
|
|
98
|
-
"vue": "^3.5.
|
|
97
|
+
"vite": "^7.3.5",
|
|
98
|
+
"vue": "^3.5.38",
|
|
99
99
|
"vue-draggable-plus": "^0.6.1",
|
|
100
100
|
"vue-router": "^5.1.0"
|
|
101
101
|
},
|
|
@@ -104,18 +104,18 @@
|
|
|
104
104
|
"@histoire/plugin-vue": "1.0.0-beta.1",
|
|
105
105
|
"@release-it/conventional-changelog": "^11.0.1",
|
|
106
106
|
"@types/jsdom": "^28.0.3",
|
|
107
|
-
"@types/node": "^
|
|
108
|
-
"@typescript-eslint/rule-tester": "^8.
|
|
109
|
-
"@vitest/coverage-v8": "^4.1.
|
|
110
|
-
"@vue/test-utils": "^2.4.
|
|
107
|
+
"@types/node": "^26.0.0",
|
|
108
|
+
"@typescript-eslint/rule-tester": "^8.61.1",
|
|
109
|
+
"@vitest/coverage-v8": "^4.1.9",
|
|
110
|
+
"@vue/test-utils": "^2.4.11",
|
|
111
111
|
"eslint": "^9.39.4",
|
|
112
|
-
"happy-dom": "^20.
|
|
112
|
+
"happy-dom": "^20.10.5",
|
|
113
113
|
"histoire": "1.0.0-beta.1",
|
|
114
114
|
"release-it": "^20.2.0",
|
|
115
115
|
"typescript": "~6.0.3",
|
|
116
116
|
"vitepress": "^2.0.0-alpha.17",
|
|
117
|
-
"vitest": "^4.1.
|
|
118
|
-
"vue-tsc": "^3.3.
|
|
117
|
+
"vitest": "^4.1.9",
|
|
118
|
+
"vue-tsc": "^3.3.5"
|
|
119
119
|
},
|
|
120
|
-
"packageManager": "pnpm@11.
|
|
120
|
+
"packageManager": "pnpm@11.7.0"
|
|
121
121
|
}
|