@data-fair/lib-vue 1.21.0 → 1.22.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/async-action.js +43 -40
- package/computed-deep-diff.js +9 -0
- package/concept-filters.js +22 -20
- package/deep-diff.d.ts +3 -0
- package/deep-diff.js +14 -0
- package/fetch.js +57 -50
- package/locale-dayjs-global.js +4 -4
- package/locale-dayjs.js +33 -32
- package/package.json +2 -1
- package/reactive-search-params-global.js +3 -3
- package/reactive-search-params.js +140 -124
- package/session.js +369 -325
- package/ui-notif.js +80 -63
- package/vite.d.ts +1 -0
- package/vite.js +15 -14
- package/ws.js +62 -58
package/async-action.js
CHANGED
|
@@ -1,44 +1,47 @@
|
|
|
1
1
|
// similar to withUiNotif but more powerful
|
|
2
|
-
import { ref, readonly, shallowReadonly, shallowRef } from 'vue'
|
|
3
|
-
import { useUiNotif, getFullNotif, getErrorMsg } from './ui-notif.js'
|
|
4
|
-
export function useAsyncAction
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
2
|
+
import { ref, readonly, shallowReadonly, shallowRef } from 'vue';
|
|
3
|
+
import { useUiNotif, getFullNotif, getErrorMsg } from './ui-notif.js';
|
|
4
|
+
export function useAsyncAction(fn, options) {
|
|
5
|
+
if (typeof options === 'function') {
|
|
6
|
+
options = { finally: options };
|
|
7
|
+
}
|
|
8
|
+
const { sendUiNotif } = useUiNotif();
|
|
9
|
+
const notif = shallowRef();
|
|
10
|
+
const loading = ref(false);
|
|
11
|
+
const error = ref();
|
|
12
|
+
const execute = async function (...args) {
|
|
13
|
+
loading.value = true;
|
|
14
|
+
notif.value = undefined;
|
|
15
|
+
error.value = undefined;
|
|
16
|
+
try {
|
|
17
|
+
const result = await fn(...args);
|
|
18
|
+
if (options?.success) {
|
|
19
|
+
const successNotif = getFullNotif(options?.success, 'success');
|
|
20
|
+
notif.value = successNotif;
|
|
21
|
+
if (options?.catch !== 'success' && options?.catch !== 'all') {
|
|
22
|
+
sendUiNotif(successNotif);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
loading.value = false;
|
|
26
|
+
if (options?.finally)
|
|
27
|
+
await options?.finally();
|
|
28
|
+
return result;
|
|
23
29
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
catch (err) {
|
|
31
|
+
const abortError = err.name === 'AbortError' || err.cause?.name === 'AbortError';
|
|
32
|
+
if (!abortError) {
|
|
33
|
+
error.value = getErrorMsg(err);
|
|
34
|
+
const errorNotif = getFullNotif({ msg: options?.error ?? '', error: err });
|
|
35
|
+
notif.value = errorNotif;
|
|
36
|
+
if (options?.catch !== 'error' && options?.catch !== 'all') {
|
|
37
|
+
sendUiNotif(errorNotif);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
loading.value = false;
|
|
41
|
+
if (options?.finally && !abortError)
|
|
42
|
+
await options?.finally();
|
|
36
43
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (options?.finally && !abortError) { await options?.finally() }
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return { execute, notif: shallowReadonly(notif), loading: readonly(loading), error: readonly(error) }
|
|
44
|
+
};
|
|
45
|
+
return { execute, notif: shallowReadonly(notif), loading: readonly(loading), error: readonly(error) };
|
|
43
46
|
}
|
|
44
|
-
export default useAsyncAction
|
|
47
|
+
export default useAsyncAction;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { computed } from 'vue';
|
|
2
|
+
import equal from 'fast-deep-equal';
|
|
3
|
+
export const computedDeepDiff = (getter, options) => {
|
|
4
|
+
return computed((oldValue) => {
|
|
5
|
+
const newValue = getter();
|
|
6
|
+
return (oldValue !== undefined && equal(newValue, oldValue)) ? oldValue : newValue;
|
|
7
|
+
}, options);
|
|
8
|
+
};
|
|
9
|
+
export default computedDeepDiff;
|
package/concept-filters.js
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
// filter reactiveSearchParams to conceptFilters (params prefixed by _c_)
|
|
2
|
-
import { reactive, watch } from 'vue'
|
|
3
|
-
export function useConceptFilters
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
2
|
+
import { reactive, watch } from 'vue';
|
|
3
|
+
export function useConceptFilters(reactiveSearchParams, datasetId) {
|
|
4
|
+
const conceptFilters = reactive({});
|
|
5
|
+
const datasetFiltersPrefix = datasetId && `_d_${datasetId}_`;
|
|
6
|
+
watch(reactiveSearchParams, () => {
|
|
7
|
+
for (const key of Object.keys(reactiveSearchParams)) {
|
|
8
|
+
if (key.startsWith('_c_'))
|
|
9
|
+
conceptFilters[key] = reactiveSearchParams[key];
|
|
10
|
+
if (datasetFiltersPrefix && key.startsWith(datasetFiltersPrefix)) {
|
|
11
|
+
conceptFilters[key.replace(datasetFiltersPrefix, '')] = reactiveSearchParams[key];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
for (const key of Object.keys(conceptFilters)) {
|
|
15
|
+
if (key.startsWith('_c_') && reactiveSearchParams[key] === undefined)
|
|
16
|
+
delete conceptFilters[key];
|
|
17
|
+
if (datasetFiltersPrefix && !key.startsWith('_c_') && reactiveSearchParams[datasetFiltersPrefix + key] === undefined) {
|
|
18
|
+
delete conceptFilters[key];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}, { immediate: true });
|
|
22
|
+
return conceptFilters;
|
|
21
23
|
}
|
|
22
|
-
export default useConceptFilters
|
|
24
|
+
export default useConceptFilters;
|
package/deep-diff.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type ComputedGetter, type ComputedOptions, type WatchSource, type WatchCallback, type WatchOptions } from 'vue';
|
|
2
|
+
export declare const computedDeepDiff: <Type>(getter: ComputedGetter<Type>, options: ComputedOptions) => import("vue").ComputedRef<Type>;
|
|
3
|
+
export declare const watchDeepDiff: (source: WatchSource, callback: WatchCallback, options: WatchOptions) => import("vue").WatchHandle;
|
package/deep-diff.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { computed, watch } from 'vue';
|
|
2
|
+
import equal from 'fast-deep-equal';
|
|
3
|
+
export const computedDeepDiff = (getter, options) => {
|
|
4
|
+
return computed((oldValue) => {
|
|
5
|
+
const newValue = getter();
|
|
6
|
+
return (oldValue !== undefined && equal(newValue, oldValue)) ? oldValue : newValue;
|
|
7
|
+
}, options);
|
|
8
|
+
};
|
|
9
|
+
export const watchDeepDiff = (source, callback, options) => {
|
|
10
|
+
return watch(source, (newValue, oldValue, onCleanup) => {
|
|
11
|
+
if (!equal(newValue, oldValue))
|
|
12
|
+
callback(newValue, oldValue, onCleanup);
|
|
13
|
+
}, options);
|
|
14
|
+
};
|
package/fetch.js
CHANGED
|
@@ -1,53 +1,60 @@
|
|
|
1
|
-
import { ofetch } from 'ofetch'
|
|
2
|
-
import { withQuery } from 'ufo'
|
|
3
|
-
import { computed, isRef, watch, ref, shallowRef, readonly, shallowReadonly } from 'vue'
|
|
4
|
-
import { useUiNotif } from '@data-fair/lib-vue/ui-notif.js'
|
|
5
|
-
export function useFetch
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
import { ofetch } from 'ofetch';
|
|
2
|
+
import { withQuery } from 'ufo';
|
|
3
|
+
import { computed, isRef, watch, ref, shallowRef, readonly, shallowReadonly } from 'vue';
|
|
4
|
+
import { useUiNotif } from '@data-fair/lib-vue/ui-notif.js';
|
|
5
|
+
export function useFetch(url, options = {}) {
|
|
6
|
+
const { sendUiNotif } = useUiNotif();
|
|
7
|
+
if (typeof url === 'function')
|
|
8
|
+
url = computed(url);
|
|
9
|
+
const fullUrl = computed(() => {
|
|
10
|
+
let fullUrl = isRef(url) ? url.value : url;
|
|
11
|
+
if (!fullUrl)
|
|
12
|
+
return null;
|
|
13
|
+
const query = isRef(options.query) ? options.query.value : options.query;
|
|
14
|
+
if (query)
|
|
15
|
+
fullUrl = withQuery(fullUrl, query);
|
|
16
|
+
return fullUrl;
|
|
17
|
+
});
|
|
18
|
+
const data = shallowRef(null);
|
|
19
|
+
const loading = ref(false);
|
|
20
|
+
const initialized = ref(false);
|
|
21
|
+
const error = shallowRef(null);
|
|
22
|
+
let abortController;
|
|
23
|
+
const refresh = async () => {
|
|
24
|
+
initialized.value = true;
|
|
25
|
+
if (!fullUrl.value)
|
|
26
|
+
return null;
|
|
27
|
+
error.value = null;
|
|
28
|
+
if (abortController)
|
|
29
|
+
abortController.abort();
|
|
30
|
+
loading.value = true;
|
|
31
|
+
abortController = new AbortController();
|
|
32
|
+
try {
|
|
33
|
+
data.value = await ofetch(fullUrl.value, { signal: abortController.signal });
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
catch (err) {
|
|
36
|
+
if (err.name !== 'AbortError' && err.cause?.name !== 'AbortError') {
|
|
37
|
+
error.value = err;
|
|
38
|
+
if (options.notifError !== false) {
|
|
39
|
+
sendUiNotif({ msg: '', error: err });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
loading.value = false;
|
|
44
|
+
return data.value;
|
|
45
|
+
};
|
|
46
|
+
if (options.watch !== false) {
|
|
47
|
+
watch(fullUrl, () => {
|
|
48
|
+
if (options.immediate !== false || initialized.value)
|
|
49
|
+
refresh();
|
|
50
|
+
}, { immediate: true });
|
|
36
51
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
initialized: readonly(initialized),
|
|
47
|
-
data: shallowReadonly(data),
|
|
48
|
-
loading: readonly(loading),
|
|
49
|
-
error: shallowReadonly(error),
|
|
50
|
-
refresh,
|
|
51
|
-
}
|
|
52
|
+
return {
|
|
53
|
+
initialized: readonly(initialized),
|
|
54
|
+
data: shallowReadonly(data),
|
|
55
|
+
loading: readonly(loading),
|
|
56
|
+
error: shallowReadonly(error),
|
|
57
|
+
refresh,
|
|
58
|
+
};
|
|
52
59
|
}
|
|
53
|
-
export default useFetch
|
|
60
|
+
export default useFetch;
|
package/locale-dayjs-global.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// same as locale-dayjs but in a module level singleton for convenience when not using SSR
|
|
2
|
-
import { getLocaleDayjs } from './locale-dayjs.js'
|
|
2
|
+
import { getLocaleDayjs } from './locale-dayjs.js';
|
|
3
3
|
// @ts-ignore
|
|
4
4
|
if (import.meta.env?.SSR) {
|
|
5
|
-
|
|
5
|
+
throw new Error('this module uses a module level singleton, it cannot be used in SSR mode');
|
|
6
6
|
}
|
|
7
|
-
console.error('locale-dayjs-global is deprecated, please use create + use')
|
|
8
|
-
export const { locale, dayjs } = getLocaleDayjs()
|
|
7
|
+
console.error('locale-dayjs-global is deprecated, please use create + use');
|
|
8
|
+
export const { locale, dayjs } = getLocaleDayjs();
|
package/locale-dayjs.js
CHANGED
|
@@ -1,38 +1,39 @@
|
|
|
1
|
-
import { inject } from 'vue'
|
|
2
|
-
import dayjs from 'dayjs'
|
|
3
|
-
import 'dayjs/locale/fr'
|
|
4
|
-
import 'dayjs/locale/en'
|
|
5
|
-
import localizedFormat from 'dayjs/plugin/localizedFormat.js'
|
|
6
|
-
import relativeTime from 'dayjs/plugin/relativeTime.js'
|
|
7
|
-
import duration from 'dayjs/plugin/duration.js'
|
|
8
|
-
dayjs.extend(localizedFormat)
|
|
9
|
-
dayjs.extend(relativeTime)
|
|
10
|
-
dayjs.extend(duration)
|
|
1
|
+
import { inject } from 'vue';
|
|
2
|
+
import dayjs from 'dayjs';
|
|
3
|
+
import 'dayjs/locale/fr';
|
|
4
|
+
import 'dayjs/locale/en';
|
|
5
|
+
import localizedFormat from 'dayjs/plugin/localizedFormat.js';
|
|
6
|
+
import relativeTime from 'dayjs/plugin/relativeTime.js';
|
|
7
|
+
import duration from 'dayjs/plugin/duration.js';
|
|
8
|
+
dayjs.extend(localizedFormat);
|
|
9
|
+
dayjs.extend(relativeTime);
|
|
10
|
+
dayjs.extend(duration);
|
|
11
11
|
// main functionality, use through the createLocaleDayjs plugin and useLocaleDayjs composable
|
|
12
12
|
// or as a global singleton through ./locale-dayjs-global.js
|
|
13
|
-
export function getLocaleDayjs
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
export function getLocaleDayjs(locale) {
|
|
14
|
+
locale = locale ?? 'fr';
|
|
15
|
+
return {
|
|
16
|
+
locale,
|
|
17
|
+
duration: ((...args) => {
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
return dayjs.duration(...args).locale(locale);
|
|
20
|
+
}),
|
|
21
|
+
dayjs: ((...args) => {
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
return dayjs(...args).locale(locale);
|
|
24
|
+
})
|
|
25
|
+
};
|
|
26
26
|
}
|
|
27
27
|
// uses pattern for SSR friendly plugin/composable, cf https://antfu.me/posts/composable-vue-vueday-2021#shared-state-ssr-friendly
|
|
28
|
-
export const localeDayjsKey = Symbol('localeDayjs')
|
|
29
|
-
export function createLocaleDayjs
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
export const localeDayjsKey = Symbol('localeDayjs');
|
|
29
|
+
export function createLocaleDayjs(locale) {
|
|
30
|
+
const localeDayjs = getLocaleDayjs(locale);
|
|
31
|
+
return { install(app) { app.provide(localeDayjsKey, localeDayjs); } };
|
|
32
32
|
}
|
|
33
|
-
export function useLocaleDayjs
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
export function useLocaleDayjs() {
|
|
34
|
+
const localeDayjs = inject(localeDayjsKey);
|
|
35
|
+
if (!localeDayjs)
|
|
36
|
+
throw new Error('useLocaleDayjs requires using the plugin createLocaleDayjs');
|
|
37
|
+
return localeDayjs;
|
|
37
38
|
}
|
|
38
|
-
export default useLocaleDayjs
|
|
39
|
+
export default useLocaleDayjs;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@data-fair/lib-vue",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.0",
|
|
4
4
|
"description": "Composables and other utilities for Vue applications in the data-fair stack.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@data-fair/lib-common-types": "^1.7.1",
|
|
32
32
|
"@data-fair/lib-utils": "^1.0.0",
|
|
33
|
+
"fast-deep-equal": "^3.1.3",
|
|
33
34
|
"jwt-decode": "^4.0.0",
|
|
34
35
|
"universal-cookie": "^7.2.0"
|
|
35
36
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// same as use-reactive-search-params.js but in a module level singleton for convenience when not using SSR
|
|
2
|
-
import { getReactiveSearchParams } from './reactive-search-params.js'
|
|
2
|
+
import { getReactiveSearchParams } from './reactive-search-params.js';
|
|
3
3
|
// @ts-ignore
|
|
4
4
|
if (import.meta.env?.SSR) {
|
|
5
|
-
|
|
5
|
+
throw new Error('this module uses a module level singleton, it cannot be used in SSR mode');
|
|
6
6
|
}
|
|
7
|
-
export default getReactiveSearchParams()
|
|
7
|
+
export default getReactiveSearchParams();
|