@globalbrain/sefirot 4.30.1 → 4.32.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/client.d.ts +5 -0
- package/config/nuxt.d.ts +1 -0
- package/config/nuxt.js +8 -5
- package/config/vite.js +4 -13
- package/lib/components/SActionList.vue +2 -2
- package/lib/components/SActionMenu.vue +43 -7
- package/lib/components/SAvatar.vue +1 -1
- package/lib/components/SAvatarStack.vue +12 -12
- package/lib/components/SButton.vue +5 -7
- package/lib/components/SCard.vue +2 -2
- package/lib/components/SChartBar.vue +37 -12
- package/lib/components/SChartPie.vue +13 -7
- package/lib/components/SControlActionBarCollapse.vue +2 -4
- package/lib/components/SControlInputSearch.vue +7 -2
- package/lib/components/SDataListItem.vue +1 -3
- package/lib/components/SDescAvatar.vue +1 -1
- package/lib/components/SDescDay.vue +2 -2
- package/lib/components/SDescFile.vue +2 -4
- package/lib/components/SDescItem.vue +2 -1
- package/lib/components/SDescLabel.vue +1 -1
- package/lib/components/SDescLink.vue +2 -7
- package/lib/components/SDescPill.vue +2 -4
- package/lib/components/SDescText.vue +3 -3
- package/lib/components/SDropdown.vue +1 -1
- package/lib/components/SDropdownSectionFilter.vue +11 -11
- package/lib/components/SFragment.vue +1 -1
- package/lib/components/SInputAddon.vue +13 -11
- package/lib/components/SInputBase.vue +11 -11
- package/lib/components/SInputCheckbox.vue +6 -3
- package/lib/components/SInputCheckboxes.vue +7 -3
- package/lib/components/SInputDate.vue +3 -5
- package/lib/components/SInputDropdown.vue +26 -28
- package/lib/components/SInputDropdownItem.vue +21 -11
- package/lib/components/SInputFile.vue +9 -6
- package/lib/components/SInputFileUpload.vue +9 -11
- package/lib/components/SInputFileUploadItem.vue +8 -4
- package/lib/components/SInputHMS.vue +3 -1
- package/lib/components/SInputImage.vue +4 -2
- package/lib/components/SInputNumber.vue +9 -10
- package/lib/components/SInputRadio.vue +3 -2
- package/lib/components/SInputRadios.vue +6 -5
- package/lib/components/SInputSegments.vue +5 -7
- package/lib/components/SInputSegmentsOption.vue +1 -2
- package/lib/components/SInputSelect.vue +6 -4
- package/lib/components/SInputSwitch.vue +4 -1
- package/lib/components/SInputSwitches.vue +5 -3
- package/lib/components/SInputText.vue +16 -16
- package/lib/components/SInputTextarea.vue +7 -3
- package/lib/components/SInputYMD.vue +3 -1
- package/lib/components/SLink.vue +2 -2
- package/lib/components/SLocalNav.vue +1 -1
- package/lib/components/SLocalNavActions.vue +1 -1
- package/lib/components/SLocalNavMenu.vue +2 -2
- package/lib/components/SLoginPagePasswordDialog.vue +2 -2
- package/lib/components/SM.vue +1 -1
- package/lib/components/SMFade.vue +1 -1
- package/lib/components/SMarkdown.vue +3 -2
- package/lib/components/SModal.vue +2 -2
- package/lib/components/SSnackbar.vue +2 -2
- package/lib/components/SSteps.vue +6 -6
- package/lib/components/STable.vue +70 -27
- package/lib/components/STableCell.vue +14 -17
- package/lib/components/STableCellAvatars.vue +1 -1
- package/lib/components/STableCellDay.vue +12 -5
- package/lib/components/STableCellNumber.vue +2 -3
- package/lib/components/STableCellPath.vue +2 -2
- package/lib/components/STableCellText.vue +2 -3
- package/lib/components/STableColumn.vue +38 -16
- package/lib/components/STableFooter.vue +10 -2
- package/lib/components/STableHeader.vue +0 -1
- package/lib/components/STableHeaderMenu.vue +4 -4
- package/lib/components/STableHeaderMenuItem.vue +1 -1
- package/lib/components/STooltip.vue +3 -3
- package/lib/composables/Api.ts +1 -1
- package/lib/composables/App.ts +13 -11
- package/lib/composables/Dropdown.ts +10 -1
- package/lib/composables/Error.ts +37 -37
- package/lib/composables/Grid.ts +1 -4
- package/lib/composables/Image.ts +2 -3
- package/lib/composables/Lang.ts +8 -16
- package/lib/composables/Markdown.ts +1 -1
- package/lib/composables/Table.ts +0 -2
- package/lib/composables/Theme.ts +1 -13
- package/lib/composables/Utils.ts +11 -4
- package/lib/composables/Validation.ts +1 -4
- package/lib/http/Http.ts +23 -17
- package/lib/styles/variables-deprecated.css +0 -1
- package/lib/styles/variables.css +16 -16
- package/lib/support/Chart.ts +0 -1
- package/lib/support/DateRange.ts +1 -1
- package/lib/support/Day.ts +12 -65
- package/lib/support/File.ts +7 -16
- package/lib/support/Utils.ts +7 -40
- package/lib/validation/Rule.ts +6 -21
- package/lib/validation/rules/decimal.ts +3 -3
- package/lib/validation/rules/email.ts +1 -1
- package/lib/validation/rules/index.ts +1 -1
- package/lib/validation/rules/negativeInteger.ts +1 -1
- package/lib/validation/rules/positiveInteger.ts +1 -1
- package/lib/validation/rules/requiredHms.ts +2 -2
- package/lib/validation/rules/requiredIf.ts +1 -4
- package/lib/validation/rules/requiredYmd.ts +2 -2
- package/lib/validation/rules/slackChannelName.ts +4 -1
- package/lib/validation/rules/zeroOrNegativeInteger.ts +1 -1
- package/lib/validation/rules/zeroOrPositiveInteger.ts +1 -1
- package/lib/validation/validators/after.ts +1 -5
- package/lib/validation/validators/afterOrEqual.ts +1 -5
- package/lib/validation/validators/before.ts +1 -4
- package/lib/validation/validators/beforeOrEqual.ts +1 -5
- package/lib/validation/validators/decimal.ts +7 -9
- package/lib/validation/validators/email.ts +4 -8
- package/lib/validation/validators/fileExtension.ts +7 -15
- package/lib/validation/validators/hms.ts +26 -15
- package/lib/validation/validators/index.ts +0 -2
- package/lib/validation/validators/maxFileSize.ts +3 -13
- package/lib/validation/validators/maxLength.ts +1 -7
- package/lib/validation/validators/maxTotalFileSize.ts +3 -26
- package/lib/validation/validators/maxValue.ts +2 -6
- package/lib/validation/validators/minLength.ts +1 -7
- package/lib/validation/validators/minValue.ts +2 -6
- package/lib/validation/validators/month.ts +1 -7
- package/lib/validation/validators/negativeInteger.ts +1 -7
- package/lib/validation/validators/positiveInteger.ts +1 -7
- package/lib/validation/validators/required.ts +5 -28
- package/lib/validation/validators/requiredHmsIf.ts +11 -13
- package/lib/validation/validators/requiredIf.ts +5 -11
- package/lib/validation/validators/requiredYmdIf.ts +11 -13
- package/lib/validation/validators/slackChannelName.ts +11 -11
- package/lib/validation/validators/url.ts +7 -5
- package/lib/validation/validators/ymd.ts +36 -30
- package/package.json +44 -42
- package/lib/composables/Http.ts +0 -18
- package/lib/validation/validators/requiredHms.ts +0 -9
- package/lib/validation/validators/requiredYmd.ts +0 -9
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { useElementBounding, useWindowSize } from '@vueuse/core'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
type Component,
|
|
4
|
+
type MaybeRef,
|
|
5
|
+
type MaybeRefOrGetter,
|
|
6
|
+
type Ref,
|
|
7
|
+
computed,
|
|
8
|
+
ref,
|
|
9
|
+
toValue,
|
|
10
|
+
unref
|
|
11
|
+
} from 'vue'
|
|
3
12
|
import { type ActionList } from '../components/SActionList.vue'
|
|
4
13
|
import { type DateRange } from '../support/DateRange'
|
|
5
14
|
|
package/lib/composables/Error.ts
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Adapted from
|
|
3
|
-
* @see https://github.com/vuejs/core/blob/
|
|
3
|
+
* @see https://github.com/vuejs/core/blob/b50eb68c50f3b94dca2e96f706c3e96ab864df24/packages/runtime-core/src/component.ts
|
|
4
4
|
* @see https://github.com/vuejs/core/blob/ac9e7e8bfa55432a73a10864805fdf48bda2ff73/packages/runtime-core/src/warning.ts
|
|
5
|
-
* @see https://github.com/getsentry/sentry-javascript/blob/
|
|
6
|
-
* @see https://github.com/vercel/ai/blob/d544886d4f61440bacd6e44c86144bfac7c98282/packages/provider-utils/src/get-error-message.ts
|
|
5
|
+
* @see https://github.com/getsentry/sentry-javascript/blob/fbadeb81d23c03c3d852531c2deef59a3a992def/packages/vue/src/errorhandler.ts
|
|
7
6
|
*
|
|
8
7
|
* Original licenses:
|
|
9
8
|
*
|
|
10
|
-
* (c) 2018-present Yuxi (Evan) You
|
|
9
|
+
* Copyright (c) 2018-present, Yuxi (Evan) You
|
|
11
10
|
* @license MIT
|
|
12
11
|
*
|
|
13
|
-
* (c)
|
|
12
|
+
* Copyright (c) 2019 Functional Software, Inc. dba Sentry
|
|
14
13
|
* @license MIT
|
|
15
|
-
*
|
|
16
|
-
* (c) 2023 Vercel, Inc.
|
|
17
|
-
* @license Apache-2.0
|
|
18
14
|
*/
|
|
19
15
|
|
|
20
16
|
import * as Sentry from '@sentry/browser'
|
|
@@ -22,8 +18,8 @@ import { createSentryPiniaPlugin } from '@sentry/vue'
|
|
|
22
18
|
import { pauseTracking, resetTracking } from '@vue/reactivity'
|
|
23
19
|
import { getActivePinia } from 'pinia'
|
|
24
20
|
import {
|
|
21
|
+
type Component,
|
|
25
22
|
type ComponentInternalInstance,
|
|
26
|
-
type ComponentOptions,
|
|
27
23
|
type ComponentPublicInstance,
|
|
28
24
|
type ConcreteComponent,
|
|
29
25
|
type MaybeRefOrGetter,
|
|
@@ -31,7 +27,6 @@ import {
|
|
|
31
27
|
toValue
|
|
32
28
|
} from 'vue'
|
|
33
29
|
import { useError } from '../stores/Error'
|
|
34
|
-
import { isError } from '../support/Utils'
|
|
35
30
|
|
|
36
31
|
export interface User {
|
|
37
32
|
id?: string | number
|
|
@@ -43,7 +38,7 @@ type TraceEntry = { vnode: VNode; recurseCount: number }
|
|
|
43
38
|
|
|
44
39
|
type ComponentTraceStack = TraceEntry[]
|
|
45
40
|
|
|
46
|
-
const classifyRE = /(?:^|[-_])
|
|
41
|
+
const classifyRE = /(?:^|[-_])\w/g
|
|
47
42
|
function classify(str: string): string {
|
|
48
43
|
return str.replace(classifyRE, (c) => c.toUpperCase()).replace(/[-_]/g, '')
|
|
49
44
|
}
|
|
@@ -70,19 +65,20 @@ function formatComponentName(instance: ComponentInternalInstance | null): string
|
|
|
70
65
|
}
|
|
71
66
|
}
|
|
72
67
|
|
|
73
|
-
if (!name && instance
|
|
74
|
-
const inferFromRegistry = (registry
|
|
68
|
+
if (!name && instance) {
|
|
69
|
+
const inferFromRegistry = (registry?: Record<string, Component>) => {
|
|
75
70
|
for (const key in registry) {
|
|
76
71
|
if (registry[key] === Component) {
|
|
77
72
|
return key
|
|
78
73
|
}
|
|
79
74
|
}
|
|
80
75
|
}
|
|
81
|
-
name
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
name =
|
|
77
|
+
// @ts-expect-error internal API
|
|
78
|
+
inferFromRegistry(instance.components)
|
|
79
|
+
// @ts-expect-error internal API
|
|
80
|
+
|| inferFromRegistry(instance.parent?.type.components)
|
|
81
|
+
|| inferFromRegistry(instance.appContext.components)
|
|
86
82
|
}
|
|
87
83
|
|
|
88
84
|
return name ? classify(name) : isRoot ? 'App' : 'Anonymous'
|
|
@@ -102,8 +98,8 @@ function getComponentTrace(currentVNode: VNode | null): ComponentTraceStack {
|
|
|
102
98
|
} else {
|
|
103
99
|
normalizedStack.push({ vnode: currentVNode, recurseCount: 0 })
|
|
104
100
|
}
|
|
105
|
-
const parentInstance: ComponentInternalInstance | null
|
|
106
|
-
|
|
101
|
+
const parentInstance: ComponentInternalInstance | null =
|
|
102
|
+
currentVNode.component && currentVNode.component.parent
|
|
107
103
|
currentVNode = parentInstance && parentInstance.vnode
|
|
108
104
|
}
|
|
109
105
|
|
|
@@ -147,6 +143,26 @@ const ignoreErrors = [
|
|
|
147
143
|
/\[Cloudflare Turnstile\] Error: (?:10[2-46]|1106[02]|[36]00)/
|
|
148
144
|
]
|
|
149
145
|
|
|
146
|
+
const stringifiers: readonly ((e: unknown) => string | false)[] = [
|
|
147
|
+
(e) => typeof e === 'string' && e,
|
|
148
|
+
(e) => e instanceof Error && (e.message || e.name),
|
|
149
|
+
(e) => {
|
|
150
|
+
const json = JSON.stringify(e)
|
|
151
|
+
return json !== '{}' && json
|
|
152
|
+
},
|
|
153
|
+
(e) => String(e)
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
function getErrorMessage(error: unknown | undefined): string {
|
|
157
|
+
for (const stringify of stringifiers) {
|
|
158
|
+
try {
|
|
159
|
+
const s = stringify(error)
|
|
160
|
+
if (s) { return s }
|
|
161
|
+
} catch { /* continue */ }
|
|
162
|
+
}
|
|
163
|
+
return 'unknown error'
|
|
164
|
+
}
|
|
165
|
+
|
|
150
166
|
export function useErrorHandler({
|
|
151
167
|
dsn,
|
|
152
168
|
environment,
|
|
@@ -204,7 +220,7 @@ export function useErrorHandler({
|
|
|
204
220
|
componentName: formatComponentName($),
|
|
205
221
|
lifecycleHook: info,
|
|
206
222
|
trace: formatTrace($),
|
|
207
|
-
propsData:
|
|
223
|
+
propsData: $.props
|
|
208
224
|
}
|
|
209
225
|
|
|
210
226
|
setTimeout(() => {
|
|
@@ -224,19 +240,3 @@ export function useErrorHandler({
|
|
|
224
240
|
set(e)
|
|
225
241
|
}
|
|
226
242
|
}
|
|
227
|
-
|
|
228
|
-
function getErrorMessage(error: unknown | undefined) {
|
|
229
|
-
if (error == null) {
|
|
230
|
-
return 'unknown error'
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (typeof error === 'string') {
|
|
234
|
-
return error
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (isError(error)) {
|
|
238
|
-
return error.message
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return JSON.stringify(error)
|
|
242
|
-
}
|
package/lib/composables/Grid.ts
CHANGED
|
@@ -45,9 +45,7 @@ export function useGrid(options: UseGridOptions = {}): Grid {
|
|
|
45
45
|
})
|
|
46
46
|
|
|
47
47
|
function adjustSpacer() {
|
|
48
|
-
container.value?.querySelectorAll(`${toClassSelector(spacerClass)}`)
|
|
49
|
-
.forEach((n) => n.remove())
|
|
50
|
-
|
|
48
|
+
container.value?.querySelectorAll(`${toClassSelector(spacerClass)}`).forEach((n) => n.remove())
|
|
51
49
|
const track = container.value?.firstElementChild
|
|
52
50
|
|
|
53
51
|
const containerWidth = container.value?.clientWidth ?? 0
|
|
@@ -59,7 +57,6 @@ export function useGrid(options: UseGridOptions = {}): Grid {
|
|
|
59
57
|
const lack = mod !== 0 ? perRow - mod : 0
|
|
60
58
|
|
|
61
59
|
const fragment = createSpacers(lack, spacerTag, spacerClass, type)
|
|
62
|
-
|
|
63
60
|
container.value?.appendChild(fragment)
|
|
64
61
|
}
|
|
65
62
|
|
package/lib/composables/Image.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { isClient } from '@vueuse/core'
|
|
2
2
|
import { type MaybeRefOrGetter, type Ref, ref, toValue, watchEffect } from 'vue'
|
|
3
|
-
import { isFile, isString } from '../support/Utils'
|
|
4
3
|
|
|
5
4
|
export interface ImageSrcFromFile {
|
|
6
5
|
src: Ref<string | null>
|
|
@@ -34,12 +33,12 @@ export function useImageSrcFromFile(
|
|
|
34
33
|
function read(): void {
|
|
35
34
|
const f = toValue(file)
|
|
36
35
|
|
|
37
|
-
if (
|
|
36
|
+
if (f instanceof Blob) {
|
|
38
37
|
reader.readAsDataURL(f)
|
|
39
38
|
return
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
if (
|
|
41
|
+
if (typeof f === 'string') {
|
|
43
42
|
src.value = f
|
|
44
43
|
return
|
|
45
44
|
}
|
package/lib/composables/Lang.ts
CHANGED
|
@@ -8,23 +8,11 @@ export interface Trans<T> {
|
|
|
8
8
|
|
|
9
9
|
export interface TransMessages<T> {
|
|
10
10
|
en: T
|
|
11
|
-
ja: T
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface HasLang {
|
|
15
|
-
lang: Lang
|
|
11
|
+
ja: NoInfer<T>
|
|
16
12
|
}
|
|
17
13
|
|
|
18
14
|
export const SefirotLangKey: InjectionKey<Lang> = Symbol.for('sefirot-lang-key')
|
|
19
15
|
|
|
20
|
-
export function useSetupLang(): (user?: HasLang | null) => void {
|
|
21
|
-
const browserLang = useBrowserLang()
|
|
22
|
-
|
|
23
|
-
return (user) => {
|
|
24
|
-
provideLang(user?.lang ?? browserLang)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
16
|
export function provideLang(lang: Lang) {
|
|
29
17
|
getCurrentInstance()!.appContext.app._context.provides[SefirotLangKey] = lang
|
|
30
18
|
}
|
|
@@ -33,12 +21,16 @@ export function useLang(): Lang {
|
|
|
33
21
|
return inject(SefirotLangKey, 'en')
|
|
34
22
|
}
|
|
35
23
|
|
|
36
|
-
export function
|
|
37
|
-
const lang = navigator
|
|
38
|
-
|
|
24
|
+
export function getBrowserLang(): Lang {
|
|
25
|
+
const lang = String(globalThis.navigator?.language || 'en')
|
|
39
26
|
return lang.split('-')[0] === 'ja' ? 'ja' : 'en'
|
|
40
27
|
}
|
|
41
28
|
|
|
29
|
+
/** @deprecated use `getBrowserLang` instead */
|
|
30
|
+
export function useBrowserLang(): Lang {
|
|
31
|
+
return getBrowserLang()
|
|
32
|
+
}
|
|
33
|
+
|
|
42
34
|
export function useTrans<T>(messages: TransMessages<T>): Trans<T> {
|
|
43
35
|
const lang = useLang()
|
|
44
36
|
|
package/lib/composables/Table.ts
CHANGED
|
@@ -25,11 +25,9 @@ export interface Table<
|
|
|
25
25
|
total?: MaybeRef<number | null | undefined>
|
|
26
26
|
page?: MaybeRef<number | null | undefined>
|
|
27
27
|
perPage?: MaybeRef<number | null | undefined>
|
|
28
|
-
reset?: MaybeRef<boolean | undefined>
|
|
29
28
|
borderSize?: MaybeRef<number | undefined>
|
|
30
29
|
onPrev?(): void
|
|
31
30
|
onNext?(): void
|
|
32
|
-
onReset?(): void
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
export type TableColumns<
|
package/lib/composables/Theme.ts
CHANGED
|
@@ -3,23 +3,11 @@ import { type WritableComputedRef, computed } from 'vue'
|
|
|
3
3
|
|
|
4
4
|
export type Theme = 'light' | 'dark'
|
|
5
5
|
|
|
6
|
-
export interface HasTheme {
|
|
7
|
-
theme: Theme
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function useSetupTheme(): (user?: HasTheme | null) => void {
|
|
11
|
-
const theme = useTheme()
|
|
12
|
-
|
|
13
|
-
return (user) => {
|
|
14
|
-
theme.value = user?.theme ?? 'light'
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
6
|
export function useTheme(): WritableComputedRef<Theme> {
|
|
19
7
|
const _isDark = useDark()
|
|
20
8
|
|
|
21
9
|
return computed({
|
|
22
|
-
get: () => _isDark.value ? 'dark' : 'light',
|
|
10
|
+
get: () => (_isDark.value ? 'dark' : 'light'),
|
|
23
11
|
set: (v) => { _isDark.value = v === 'dark' }
|
|
24
12
|
})
|
|
25
13
|
}
|
package/lib/composables/Utils.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
type ComputedRef,
|
|
3
|
+
type MaybeRefOrGetter,
|
|
4
|
+
computed,
|
|
5
|
+
getCurrentInstance,
|
|
6
|
+
onMounted,
|
|
7
|
+
toValue,
|
|
8
|
+
useSlots
|
|
9
|
+
} from 'vue'
|
|
3
10
|
|
|
4
11
|
export type WhenCondition<T> = MaybeRefOrGetter<T>
|
|
5
12
|
|
|
@@ -22,7 +29,7 @@ export function computedWhen<T, C, D>(
|
|
|
22
29
|
return computed(() => {
|
|
23
30
|
const c = toValue(condition)
|
|
24
31
|
|
|
25
|
-
return c ? fn(c) : whenFalse as D
|
|
32
|
+
return c ? fn(c) : (whenFalse as D)
|
|
26
33
|
})
|
|
27
34
|
}
|
|
28
35
|
|
|
@@ -68,7 +75,7 @@ export function useSlotValue(name = 'default'): ComputedRef<string | null> {
|
|
|
68
75
|
|
|
69
76
|
return computed(() => {
|
|
70
77
|
const c = slots[name]?.()[0]?.children
|
|
71
|
-
const v =
|
|
78
|
+
const v = typeof c === 'string' ? c.trim() : null
|
|
72
79
|
return v !== '' ? v : null
|
|
73
80
|
})
|
|
74
81
|
}
|
|
@@ -85,10 +85,7 @@ export function useVNotification(): VNotification {
|
|
|
85
85
|
const snackbars = useSnackbars()
|
|
86
86
|
|
|
87
87
|
function notify(message?: Snackbar): void {
|
|
88
|
-
snackbars.push(message ?? {
|
|
89
|
-
mode: 'danger',
|
|
90
|
-
text: t.notify
|
|
91
|
-
})
|
|
88
|
+
snackbars.push(message ?? { mode: 'danger', text: t.notify })
|
|
92
89
|
}
|
|
93
90
|
|
|
94
91
|
return {
|
package/lib/http/Http.ts
CHANGED
|
@@ -3,7 +3,6 @@ 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 { isBlob, isError, isFormData, isRequest, isResponse, isString } from '../support/Utils'
|
|
7
6
|
|
|
8
7
|
type Config = ReturnType<typeof import('../stores/HttpConfig').useHttpConfig>
|
|
9
8
|
|
|
@@ -31,9 +30,13 @@ export class Http {
|
|
|
31
30
|
|
|
32
31
|
private async buildRequest(url: string, _options: FetchOptions = {}): Promise<[string, FetchOptions]> {
|
|
33
32
|
const { method, params, query, ...options } = _options
|
|
34
|
-
const xsrfToken = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method || '')
|
|
33
|
+
const xsrfToken = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method || '')
|
|
34
|
+
&& (await this.ensureXsrfToken())
|
|
35
35
|
|
|
36
|
-
const queryString = stringify(
|
|
36
|
+
const queryString = stringify(
|
|
37
|
+
{ ...params, ...query },
|
|
38
|
+
{ encodeValuesOnly: true, ...this.config.stringifyOptions }
|
|
39
|
+
)
|
|
37
40
|
|
|
38
41
|
return [
|
|
39
42
|
`${url}${queryString ? `?${queryString}` : ''}`,
|
|
@@ -70,11 +73,11 @@ export class Http {
|
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
async post<T = any>(url: string, body?: any, options?: FetchOptions): Promise<T> {
|
|
73
|
-
if (body && !
|
|
76
|
+
if (body && !(body instanceof FormData)) {
|
|
74
77
|
let hasFile = false
|
|
75
78
|
|
|
76
79
|
const payload = JSON.stringify(body, (_, value) => {
|
|
77
|
-
if (
|
|
80
|
+
if (value instanceof Blob) {
|
|
78
81
|
hasFile = true
|
|
79
82
|
return undefined
|
|
80
83
|
}
|
|
@@ -120,13 +123,18 @@ export class Http {
|
|
|
120
123
|
throw new Error('No blob')
|
|
121
124
|
}
|
|
122
125
|
|
|
123
|
-
const { filename = 'download' }
|
|
124
|
-
|
|
126
|
+
const { filename = 'download' } =
|
|
127
|
+
parseContentDisposition(headers.get('Content-Disposition') || '')?.parameters || {}
|
|
125
128
|
|
|
126
129
|
FileSaver.saveAs(blob, filename as string)
|
|
127
130
|
}
|
|
128
131
|
|
|
129
|
-
private objectToFormData(
|
|
132
|
+
private objectToFormData(
|
|
133
|
+
obj: any,
|
|
134
|
+
form?: FormData,
|
|
135
|
+
namespace?: string,
|
|
136
|
+
onlyFiles = false
|
|
137
|
+
): FormData {
|
|
130
138
|
const fd = form || new FormData()
|
|
131
139
|
let formKey: string
|
|
132
140
|
|
|
@@ -141,11 +149,15 @@ export class Http {
|
|
|
141
149
|
return
|
|
142
150
|
}
|
|
143
151
|
|
|
144
|
-
if (
|
|
152
|
+
if (
|
|
153
|
+
typeof obj[property] === 'object'
|
|
154
|
+
&& !(obj[property] instanceof Blob)
|
|
155
|
+
&& obj[property] !== null
|
|
156
|
+
) {
|
|
145
157
|
this.objectToFormData(obj[property], fd, property, onlyFiles)
|
|
146
158
|
} else {
|
|
147
159
|
const value = obj[property] === null ? '' : obj[property]
|
|
148
|
-
if (onlyFiles && !
|
|
160
|
+
if (onlyFiles && !(value instanceof Blob)) {
|
|
149
161
|
return
|
|
150
162
|
}
|
|
151
163
|
fd.append(formKey, value)
|
|
@@ -157,13 +169,7 @@ export class Http {
|
|
|
157
169
|
}
|
|
158
170
|
|
|
159
171
|
export function isFetchError(e: unknown): e is FetchError {
|
|
160
|
-
return (
|
|
161
|
-
e instanceof FetchError
|
|
162
|
-
|| (isError<FetchError>(e)
|
|
163
|
-
&& (e.response === undefined || isResponse(e.response))
|
|
164
|
-
&& ((isString(e.request) && e.message.startsWith(`[${e.options?.method || 'GET'}] ${JSON.stringify(e.request || '/')}: `))
|
|
165
|
-
|| (isRequest(e.request) && e.message.startsWith(`[${e.request.method}] ${JSON.stringify(e.request.url)}: `))))
|
|
166
|
-
)
|
|
172
|
+
return e instanceof FetchError || (e instanceof Error && e.name === 'FetchError')
|
|
167
173
|
}
|
|
168
174
|
|
|
169
175
|
export { FetchError, type FetchOptions, type FetchRequest, type FetchResponse } from 'ofetch'
|
package/lib/styles/variables.css
CHANGED
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
* Color: Divider and Gutter
|
|
155
155
|
* -------------------------------------------------------------------------- */
|
|
156
156
|
|
|
157
|
-
|
|
157
|
+
:root {
|
|
158
158
|
--c-divider: #e0e0e1;
|
|
159
159
|
--c-gutter: #e2e2e3;
|
|
160
160
|
}
|
|
@@ -290,7 +290,7 @@
|
|
|
290
290
|
* Color: Border
|
|
291
291
|
* -------------------------------------------------------------------------- */
|
|
292
292
|
|
|
293
|
-
|
|
293
|
+
:root {
|
|
294
294
|
--c-border-mute-1: var(--c-gray-6);
|
|
295
295
|
--c-border-mute-2: var(--c-gray-7);
|
|
296
296
|
--c-border-mute-3: var(--c-gray-8);
|
|
@@ -316,7 +316,7 @@
|
|
|
316
316
|
* Color: Text
|
|
317
317
|
* -------------------------------------------------------------------------- */
|
|
318
318
|
|
|
319
|
-
|
|
319
|
+
:root {
|
|
320
320
|
--c-text-1: var(--c-text-light-1);
|
|
321
321
|
--c-text-2: var(--c-text-light-2);
|
|
322
322
|
--c-text-3: var(--c-text-light-3);
|
|
@@ -367,11 +367,11 @@
|
|
|
367
367
|
* -------------------------------------------------------------------------- */
|
|
368
368
|
|
|
369
369
|
:root {
|
|
370
|
-
--shadow-depth-1: 0 1px 2px rgba(0, 0, 0, .04), 0 1px 2px rgba(0, 0, 0, .06);
|
|
371
|
-
--shadow-depth-2: 0 3px 12px rgba(0, 0, 0, .07), 0 1px 4px rgba(0, 0, 0, .07);
|
|
372
|
-
--shadow-depth-3: 0 12px 32px rgba(0, 0, 0, .1), 0 2px 6px rgba(0, 0, 0, .08);
|
|
373
|
-
--shadow-depth-4: 0 14px 44px rgba(0, 0, 0, .12), 0 3px 9px rgba(0, 0, 0, .12);
|
|
374
|
-
--shadow-depth-5: 0 18px 56px rgba(0, 0, 0, .16), 0 4px 12px rgba(0, 0, 0, .16);
|
|
370
|
+
--shadow-depth-1: 0 1px 2px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
371
|
+
--shadow-depth-2: 0 3px 12px rgba(0, 0, 0, 0.07), 0 1px 4px rgba(0, 0, 0, 0.07);
|
|
372
|
+
--shadow-depth-3: 0 12px 32px rgba(0, 0, 0, 0.1), 0 2px 6px rgba(0, 0, 0, 0.08);
|
|
373
|
+
--shadow-depth-4: 0 14px 44px rgba(0, 0, 0, 0.12), 0 3px 9px rgba(0, 0, 0, 0.12);
|
|
374
|
+
--shadow-depth-5: 0 18px 56px rgba(0, 0, 0, 0.16), 0 4px 12px rgba(0, 0, 0, 0.16);
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
/**
|
|
@@ -389,15 +389,15 @@
|
|
|
389
389
|
* -------------------------------------------------------------------------- */
|
|
390
390
|
|
|
391
391
|
:root {
|
|
392
|
-
--ease-in-quint: cubic-bezier(.755, .05, .855, .06);
|
|
393
|
-
--ease-in-back: cubic-bezier(1,
|
|
392
|
+
--ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
|
393
|
+
--ease-in-back: cubic-bezier(1, -0.75, 1, 1);
|
|
394
394
|
|
|
395
|
-
--ease-out-quint: cubic-bezier(.23, 1, .32, 1);
|
|
396
|
-
--ease-out-expo: cubic-bezier(.19, 1, .22, 1);
|
|
397
|
-
--ease-out-back: cubic-bezier(.175, .885, .
|
|
398
|
-
--ease-out-back-quint: cubic-bezier(.175, .885, .
|
|
395
|
+
--ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
|
|
396
|
+
--ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
|
|
397
|
+
--ease-out-back: cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
398
|
+
--ease-out-back-quint: cubic-bezier(0.175, 0.885, 0.28, 1.5);
|
|
399
399
|
|
|
400
|
-
--ease-in-out-quint: cubic-bezier(.86, 0, .07, 1);
|
|
400
|
+
--ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);
|
|
401
401
|
--ease-in-out-expo: cubic-bezier(1, 0, 0, 1);
|
|
402
402
|
}
|
|
403
403
|
|
|
@@ -503,7 +503,7 @@
|
|
|
503
503
|
--button-fill-black-hover-text-color: var(--c-text-dark-1);
|
|
504
504
|
--button-fill-black-hover-bg-color: var(--c-neutral-light-2);
|
|
505
505
|
--button-fill-black-active-border-color: transparent;
|
|
506
|
-
--button-fill-black-active-text-color:var(--c-text-dark-1);
|
|
506
|
+
--button-fill-black-active-text-color: var(--c-text-dark-1);
|
|
507
507
|
--button-fill-black-active-bg-color: var(--c-neutral-light-3);
|
|
508
508
|
--button-fill-black-disabled-border-color: transparent;
|
|
509
509
|
--button-fill-black-disabled-text-color: var(--c-text-dark-2);
|
package/lib/support/Chart.ts
CHANGED
|
@@ -37,7 +37,6 @@ export const chartColors = {
|
|
|
37
37
|
gray: 'light-dark(#8d8d8d, #7b7b7b)'
|
|
38
38
|
} as const
|
|
39
39
|
|
|
40
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
41
40
|
export type ChartColor = keyof typeof chartColors | (string & {})
|
|
42
41
|
export type KV = { key: string; value: number; color?: ChartColor }
|
|
43
42
|
export type Margins = Partial<{ top: number; right: number; bottom: number; left: number }>
|
package/lib/support/DateRange.ts
CHANGED
|
@@ -93,7 +93,7 @@ export class DateFromTo extends DateRangePresetBase {
|
|
|
93
93
|
const f = this.getFrom()?.format('YYYY-MM-DD')
|
|
94
94
|
const t = this.getTo()?.format('YYYY-MM-DD')
|
|
95
95
|
|
|
96
|
-
return
|
|
96
|
+
return f && t ? `${f} – ${t}` : 'Error'
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
setFrom(from: Day | null): this {
|
package/lib/support/Day.ts
CHANGED
|
@@ -2,7 +2,6 @@ import dayjs, { type ConfigType, type Dayjs } from 'dayjs'
|
|
|
2
2
|
import PluginRelativeTime from 'dayjs/plugin/relativeTime'
|
|
3
3
|
import PluginTimezone from 'dayjs/plugin/timezone'
|
|
4
4
|
import PluginUtc from 'dayjs/plugin/utc'
|
|
5
|
-
import { isNumber, isObject, isString } from './Utils'
|
|
6
5
|
|
|
7
6
|
dayjs.extend(PluginUtc)
|
|
8
7
|
dayjs.extend(PluginTimezone)
|
|
@@ -22,12 +21,6 @@ export interface Ymd {
|
|
|
22
21
|
|
|
23
22
|
export type YmdType = 'y' | 'm' | 'd'
|
|
24
23
|
|
|
25
|
-
export const YmdMap = {
|
|
26
|
-
y: 'year',
|
|
27
|
-
m: 'month',
|
|
28
|
-
d: 'date'
|
|
29
|
-
} as const
|
|
30
|
-
|
|
31
24
|
/**
|
|
32
25
|
* The hour, minute, and second object interface.
|
|
33
26
|
*/
|
|
@@ -39,13 +32,13 @@ export interface Hms {
|
|
|
39
32
|
|
|
40
33
|
export type HmsType = 'h' | 'm' | 's'
|
|
41
34
|
|
|
42
|
-
export const HmsMap = {
|
|
43
|
-
h: 'hour',
|
|
44
|
-
m: 'minute',
|
|
45
|
-
s: 'second'
|
|
46
|
-
} as const
|
|
47
|
-
|
|
48
35
|
export function day(input?: Input): Day {
|
|
36
|
+
// hack for histoire
|
|
37
|
+
if (input && typeof input === 'object' && !(input instanceof Date)) {
|
|
38
|
+
const { $D, $H, $M, $m, $ms, $s, $y } = input as any
|
|
39
|
+
input = new Date($y, $M, $D, $H, $m, $s, $ms)
|
|
40
|
+
}
|
|
41
|
+
|
|
49
42
|
return dayjs(input)
|
|
50
43
|
}
|
|
51
44
|
|
|
@@ -67,19 +60,9 @@ export function createYmd(
|
|
|
67
60
|
month: number | null = null,
|
|
68
61
|
date: number | null = null
|
|
69
62
|
): Ymd {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
month,
|
|
74
|
-
date
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
year: yearOrDay.year(),
|
|
80
|
-
month: yearOrDay.month() + 1,
|
|
81
|
-
date: yearOrDay.date()
|
|
82
|
-
}
|
|
63
|
+
return isDay(yearOrDay)
|
|
64
|
+
? { year: yearOrDay.year(), month: yearOrDay.month() + 1, date: yearOrDay.date() }
|
|
65
|
+
: { year: yearOrDay, month, date }
|
|
83
66
|
}
|
|
84
67
|
|
|
85
68
|
/**
|
|
@@ -92,45 +75,9 @@ export function createHms(
|
|
|
92
75
|
minute: string | null = null,
|
|
93
76
|
second: string | null = null
|
|
94
77
|
): Hms {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
minute,
|
|
99
|
-
second
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
hour: hourOrDay.format('HH'),
|
|
105
|
-
minute: hourOrDay.format('mm'),
|
|
106
|
-
second: hourOrDay.format('ss')
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function isYmd(value: unknown, required: YmdType[] = ['y', 'm', 'd']): value is Ymd {
|
|
111
|
-
if (value == null || !isObject(value)) {
|
|
112
|
-
return false
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return required
|
|
116
|
-
.reduce<string[]>((keys, type) => {
|
|
117
|
-
keys.push(YmdMap[type])
|
|
118
|
-
return keys
|
|
119
|
-
}, [])
|
|
120
|
-
.every((key) => value[key] === null || isNumber(value[key]))
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export function isHms(value: unknown, required: HmsType[] = ['h', 'm', 's']): value is Hms {
|
|
124
|
-
if (value == null || !isObject(value)) {
|
|
125
|
-
return false
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return required
|
|
129
|
-
.reduce<string[]>((keys, type) => {
|
|
130
|
-
keys.push(HmsMap[type])
|
|
131
|
-
return keys
|
|
132
|
-
}, [])
|
|
133
|
-
.every((key) => value[key] === null || isString(value[key]))
|
|
78
|
+
return isDay(hourOrDay)
|
|
79
|
+
? { hour: hourOrDay.format('HH'), minute: hourOrDay.format('mm'), second: hourOrDay.format('ss') }
|
|
80
|
+
: { hour: hourOrDay, minute, second }
|
|
134
81
|
}
|
|
135
82
|
|
|
136
83
|
export function isDay(value: unknown): value is Day {
|
package/lib/support/File.ts
CHANGED
|
@@ -1,24 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
* Get extension of the given file.
|
|
3
|
-
*/
|
|
4
|
-
export function getExtension(file: File): string {
|
|
5
|
-
const name = file.name
|
|
6
|
-
|
|
7
|
-
return name.slice((name.lastIndexOf('.') - 1 >>> 0) + 2)
|
|
8
|
-
}
|
|
1
|
+
const units = ['B', 'kB', 'MB', 'GB'] as const
|
|
9
2
|
|
|
10
3
|
/**
|
|
11
4
|
* Formats the file size in bytes to a human-readable format. It also accepts
|
|
12
5
|
* array of files and returns the total size.
|
|
13
6
|
*/
|
|
14
7
|
export function formatSize(files: File | File[]): string {
|
|
15
|
-
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
|
|
16
8
|
files = Array.isArray(files) ? files : [files]
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
return `${size.toFixed(2)}${units[index]}`
|
|
9
|
+
|
|
10
|
+
const size = files.reduce((sum, file) => sum + file.size, 0)
|
|
11
|
+
if (size === 0) { return `0 ${units[0]}` }
|
|
12
|
+
|
|
13
|
+
const i = Math.min(Math.floor(Math.log(size) / Math.log(1000)), units.length - 1)
|
|
14
|
+
return `${(size / 1000 ** i).toFixed(2)} ${units[i]}`
|
|
24
15
|
}
|