@data-fair/lib-vue 1.24.1 → 1.25.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.d.ts +1 -1
- package/edit-fetch.d.ts +26 -0
- package/edit-fetch.js +37 -0
- package/fetch.d.ts +5 -3
- package/fetch.js +4 -3
- package/format/bytes.d.ts +1 -2
- package/format/bytes.js +2 -22
- package/format/field.d.ts +1 -3
- package/format/field.js +2 -28
- package/package.json +2 -2
- package/session.d.ts +2 -1
- package/session.js +7 -5
- package/vite.d.ts +1 -0
- package/vite.js +1 -0
package/async-action.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Ref } from 'vue';
|
|
2
2
|
import { type PartialUiNotif, type UiNotif } from './ui-notif.js';
|
|
3
3
|
type Finally = () => Promise<void> | void;
|
|
4
|
-
type AsyncActionOptions = {
|
|
4
|
+
export type AsyncActionOptions = {
|
|
5
5
|
error?: string;
|
|
6
6
|
success?: PartialUiNotif;
|
|
7
7
|
catch?: 'error' | 'success' | 'all';
|
package/edit-fetch.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Ref } from 'vue';
|
|
2
|
+
import { type UseFetchOptions } from './fetch.js';
|
|
3
|
+
import { AsyncActionOptions } from './async-action.js';
|
|
4
|
+
type UseEditFetchOptions = UseFetchOptions & {
|
|
5
|
+
patch?: boolean;
|
|
6
|
+
saveOptions?: AsyncActionOptions;
|
|
7
|
+
};
|
|
8
|
+
type OptionalUrl = string | null | undefined;
|
|
9
|
+
export declare function useEditFetch<T extends Record<string, any>>(url: OptionalUrl | Ref<OptionalUrl> | (() => OptionalUrl), options?: UseEditFetchOptions): {
|
|
10
|
+
fetch: {
|
|
11
|
+
data: Ref<T | null, T | null>;
|
|
12
|
+
fullUrl: Ref<string | null>;
|
|
13
|
+
loading: Ref<boolean>;
|
|
14
|
+
initialized: Ref<boolean>;
|
|
15
|
+
error: Ref<any>;
|
|
16
|
+
refresh: () => Promise<T | null>;
|
|
17
|
+
};
|
|
18
|
+
data: [T | null] extends [Ref<any, any>] ? import("@vue/shared").IfAny<Ref<any, any> & T, Ref<Ref<any, any> & T, Ref<any, any> & T>, Ref<any, any> & T> : Ref<import("vue").UnwrapRef<T> | null, T | import("vue").UnwrapRef<T> | null>;
|
|
19
|
+
save: {
|
|
20
|
+
execute: () => Promise<void>;
|
|
21
|
+
notif: Ref<import("./ui-notif.js").UiNotif | undefined>;
|
|
22
|
+
loading: Ref<boolean>;
|
|
23
|
+
error: Ref<string | undefined>;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export default useEditFetch;
|
package/edit-fetch.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ref, watch } from 'vue';
|
|
2
|
+
import { ofetch } from 'ofetch';
|
|
3
|
+
import { useFetch } from './fetch.js';
|
|
4
|
+
import useAsyncAction from './async-action.js';
|
|
5
|
+
import equal from 'fast-deep-equal';
|
|
6
|
+
export function useEditFetch(url, options = {}) {
|
|
7
|
+
const fetch = useFetch(url, options);
|
|
8
|
+
const data = ref(null);
|
|
9
|
+
watch(fetch.data, () => {
|
|
10
|
+
// TODO: check for local changes before overwriting ?
|
|
11
|
+
data.value = fetch.data.value;
|
|
12
|
+
});
|
|
13
|
+
const save = useAsyncAction(async () => {
|
|
14
|
+
if (!data.value || !fetch.data.value)
|
|
15
|
+
throw new Error('cannot save data that has not been fetched yet');
|
|
16
|
+
if (options.patch) {
|
|
17
|
+
const patch = {};
|
|
18
|
+
for (const key of Object.keys(data.value)) {
|
|
19
|
+
if (!equal(data.value[key], fetch.data.value[key]))
|
|
20
|
+
patch[key] = data.value[key];
|
|
21
|
+
}
|
|
22
|
+
if (!Object.keys(patch).length)
|
|
23
|
+
return;
|
|
24
|
+
await ofetch(fetch.fullUrl.value, { method: 'PATCH', body: patch });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// TODO: add if-unmodified-since header ?
|
|
28
|
+
await ofetch(fetch.fullUrl.value, { method: 'PUT', body: data.value });
|
|
29
|
+
}
|
|
30
|
+
}, options.saveOptions);
|
|
31
|
+
return {
|
|
32
|
+
fetch,
|
|
33
|
+
data,
|
|
34
|
+
save
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export default useEditFetch;
|
package/fetch.d.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import type { QueryObject } from 'ufo';
|
|
2
2
|
import type { Ref } from 'vue';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { MaybeRefOrGetter } from 'vue';
|
|
4
|
+
export type UseFetchOptions = {
|
|
5
|
+
query?: MaybeRefOrGetter<QueryObject>;
|
|
5
6
|
watch?: Boolean;
|
|
6
7
|
notifError?: Boolean;
|
|
7
8
|
immediate?: Boolean;
|
|
8
9
|
};
|
|
9
10
|
type OptionalUrl = string | null | undefined;
|
|
10
|
-
export declare function useFetch<T>(url:
|
|
11
|
+
export declare function useFetch<T>(url: MaybeRefOrGetter<OptionalUrl>, options?: UseFetchOptions): {
|
|
11
12
|
data: Ref<T | null>;
|
|
13
|
+
fullUrl: Ref<string | null>;
|
|
12
14
|
loading: Ref<boolean>;
|
|
13
15
|
initialized: Ref<boolean>;
|
|
14
16
|
error: Ref<any>;
|
package/fetch.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { ofetch } from 'ofetch';
|
|
2
2
|
import { withQuery } from 'ufo';
|
|
3
|
-
import { computed,
|
|
3
|
+
import { computed, watch, ref, shallowRef, readonly, shallowReadonly, toValue } from 'vue';
|
|
4
4
|
import { useUiNotif } from '@data-fair/lib-vue/ui-notif.js';
|
|
5
5
|
export function useFetch(url, options = {}) {
|
|
6
6
|
const { sendUiNotif } = useUiNotif();
|
|
7
7
|
if (typeof url === 'function')
|
|
8
8
|
url = computed(url);
|
|
9
9
|
const fullUrl = computed(() => {
|
|
10
|
-
let fullUrl =
|
|
10
|
+
let fullUrl = toValue(url);
|
|
11
11
|
if (!fullUrl)
|
|
12
12
|
return null;
|
|
13
|
-
const query =
|
|
13
|
+
const query = toValue(options.query);
|
|
14
14
|
if (query)
|
|
15
15
|
fullUrl = withQuery(fullUrl, query);
|
|
16
16
|
return fullUrl;
|
|
@@ -51,6 +51,7 @@ export function useFetch(url, options = {}) {
|
|
|
51
51
|
}
|
|
52
52
|
return {
|
|
53
53
|
initialized: readonly(initialized),
|
|
54
|
+
fullUrl: readonly(fullUrl),
|
|
54
55
|
data: shallowReadonly(data),
|
|
55
56
|
loading: readonly(loading),
|
|
56
57
|
error: shallowReadonly(error),
|
package/format/bytes.d.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export default formatBytes;
|
|
1
|
+
export * from '@data-fair/lib-utils/format/bytes.js';
|
package/format/bytes.js
CHANGED
|
@@ -1,22 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
en: [[0, 'byte'], [1, 'bytes'], [1000, 'kb'], [1000 * 1000, 'Mb'], [1000 * 1000 * 1000, 'Gb'], [1000 * 1000 * 1000 * 1000, 'Tb'], [1000 * 1000 * 1000 * 1000 * 1000, 'Pb']]
|
|
4
|
-
};
|
|
5
|
-
export function formatBytes(bytes, locale = 'fr') {
|
|
6
|
-
const bytesInt = Math.abs(typeof bytes === 'string' ? parseInt(bytes, 10) : bytes);
|
|
7
|
-
const def = locales[locale] ?? locales.en;
|
|
8
|
-
for (let i = 0; i < def.length; i++) {
|
|
9
|
-
const step = def[i][0];
|
|
10
|
-
if (bytesInt < step || i === def.length - 1) {
|
|
11
|
-
const value = bytesInt / (def[i - 1][0] || 1);
|
|
12
|
-
let digits = 2;
|
|
13
|
-
if (value > 1)
|
|
14
|
-
digits = 1;
|
|
15
|
-
if (value > 10)
|
|
16
|
-
digits = 0;
|
|
17
|
-
return value.toLocaleString(locale, { maximumFractionDigits: digits }) + ' ' + def[i - 1][1];
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return ''; // this is only for strict typing, but the code cannot go there, the return in the loop is always called
|
|
21
|
-
}
|
|
22
|
-
export default formatBytes;
|
|
1
|
+
// re-export for retro-compatiblity
|
|
2
|
+
export * from '@data-fair/lib-utils/format/bytes.js';
|
package/format/field.d.ts
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function formatField(item: Record<string, string | null | undefined | number | boolean>, field: Field): string;
|
|
3
|
-
export declare function getFieldLabel(field: Field): string;
|
|
1
|
+
export * from '@data-fair/lib-utils/format/field.js';
|
package/format/field.js
CHANGED
|
@@ -1,28 +1,2 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
export function formatField(item, field) {
|
|
4
|
-
const value = item[field.key];
|
|
5
|
-
if (value === undefined || value === null || value === '')
|
|
6
|
-
return '';
|
|
7
|
-
if (field['x-labels']?.['' + item[field.key]])
|
|
8
|
-
return field['x-labels']['' + item[field.key]];
|
|
9
|
-
if (field.type === 'number' || field.type === 'integer')
|
|
10
|
-
return value.toLocaleString('fr');
|
|
11
|
-
if (typeof value === 'boolean')
|
|
12
|
-
return value ? 'Oui' : 'Non';
|
|
13
|
-
if (typeof value === 'string') {
|
|
14
|
-
if (field['x-refersTo'] === 'http://schema.org/Date' ||
|
|
15
|
-
field['x-refersTo'] === 'https://schema.org/startDate' ||
|
|
16
|
-
field['x-refersTo'] === 'https://schema.org/endDate' ||
|
|
17
|
-
field['x-refersTo'] === 'http://schema.org/dateCreated') {
|
|
18
|
-
if (field.format === 'date-time')
|
|
19
|
-
return dayjs(value).format('DD/MM/YYYY, HH[h]mm');
|
|
20
|
-
else
|
|
21
|
-
return dayjs(value).format('DD/MM/YYYY');
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return '' + value;
|
|
25
|
-
}
|
|
26
|
-
export function getFieldLabel(field) {
|
|
27
|
-
return field.title || field['x-originalName'] || field.key;
|
|
28
|
-
}
|
|
1
|
+
// re-export for retro-compatiblity
|
|
2
|
+
export * from '@data-fair/lib-utils/format/field.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@data-fair/lib-vue",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "Composables and other utilities for Vue applications in the data-fair stack.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@data-fair/lib-common-types": "^1.7.1",
|
|
32
|
-
"@data-fair/lib-utils": "^1.
|
|
32
|
+
"@data-fair/lib-utils": "^1.9.0",
|
|
33
33
|
"fast-deep-equal": "^3.1.3",
|
|
34
34
|
"jwt-decode": "^4.0.0",
|
|
35
35
|
"universal-cookie": "^7.2.0"
|
package/session.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type IncomingMessage } from 'node:http';
|
|
|
2
2
|
import { type Ref, type ComputedRef, type App } from 'vue';
|
|
3
3
|
import { type RouteLocation } from 'vue-router';
|
|
4
4
|
import { type fetch } from 'ofetch';
|
|
5
|
-
import { type SessionState, type SessionStateAuthenticated } from '@data-fair/lib-common-types/session/index.js';
|
|
5
|
+
import { type AccountKeys, type SessionState, type SessionStateAuthenticated } from '@data-fair/lib-common-types/session/index.js';
|
|
6
6
|
export * from '@data-fair/lib-common-types/session/index.js';
|
|
7
7
|
interface GenericCookies {
|
|
8
8
|
get: (key: string) => string | undefined;
|
|
@@ -63,6 +63,7 @@ export interface SiteInfo {
|
|
|
63
63
|
logo?: string;
|
|
64
64
|
dark?: boolean;
|
|
65
65
|
colors: Colors;
|
|
66
|
+
owner: AccountKeys;
|
|
66
67
|
}
|
|
67
68
|
type Theme = 'default' | 'dark' | 'hc' | 'hc-dark';
|
|
68
69
|
export interface Session {
|
package/session.js
CHANGED
|
@@ -269,7 +269,9 @@ export async function getSession(initOptions) {
|
|
|
269
269
|
goTo(null);
|
|
270
270
|
};
|
|
271
271
|
const keepalive = async () => {
|
|
272
|
-
|
|
272
|
+
// check cookies.get('id_token') not state.user so that we do a keepalive on expired id tokens
|
|
273
|
+
// as we might have an exchange token
|
|
274
|
+
if (!cookies.get('id_token'))
|
|
273
275
|
return;
|
|
274
276
|
if (!ssr) {
|
|
275
277
|
window.localStorage.setItem('sd-keepalive' + options.sitePath, `${new Date().getTime()}`);
|
|
@@ -284,8 +286,8 @@ export async function getSession(initOptions) {
|
|
|
284
286
|
else {
|
|
285
287
|
throw err;
|
|
286
288
|
}
|
|
287
|
-
readState();
|
|
288
289
|
}
|
|
290
|
+
readState();
|
|
289
291
|
};
|
|
290
292
|
const refreshSiteInfo = async () => {
|
|
291
293
|
console.warn('@data-fair/lib-vue/session refreshSiteInfo is deprecated');
|
|
@@ -301,7 +303,8 @@ export async function getSession(initOptions) {
|
|
|
301
303
|
logo: siteInfo.theme.logo,
|
|
302
304
|
colors: siteInfo.theme.colors,
|
|
303
305
|
authMode: siteInfo.authMode,
|
|
304
|
-
authOnlyOtherSite: siteInfo.authOnlyOtherSite
|
|
306
|
+
authOnlyOtherSite: siteInfo.authOnlyOtherSite,
|
|
307
|
+
owner: siteInfo.owner
|
|
305
308
|
};
|
|
306
309
|
if (theme.value == null)
|
|
307
310
|
theme.value = getDefaultTheme(siteInfo);
|
|
@@ -331,8 +334,7 @@ export async function getSession(initOptions) {
|
|
|
331
334
|
// also run an auto-refresh loop
|
|
332
335
|
if (!ssr && !inIframe && !('triggerCapture' in window)) {
|
|
333
336
|
const lastKeepalive = window.localStorage.getItem('sd-keepalive' + options.sitePath);
|
|
334
|
-
|
|
335
|
-
if (cookies.get('id_token') && (!lastKeepalive || (new Date().getTime() - Number(lastKeepalive)) > 10000)) {
|
|
337
|
+
if (!lastKeepalive || (new Date().getTime() - Number(lastKeepalive)) > 10000) {
|
|
336
338
|
await keepalive();
|
|
337
339
|
}
|
|
338
340
|
const refreshLoopDelay = 10 * 60 * 1000; // 10 minutes
|
package/vite.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare const autoImports: (string | {
|
|
|
8
8
|
'@data-fair/lib-vue/ws.js': string[];
|
|
9
9
|
'@data-fair/lib-vue/async-action.js': string[];
|
|
10
10
|
'@data-fair/lib-vue/deep-diff.js': string[];
|
|
11
|
+
'@data-fair/lib-vue/format/bytes.js': string[];
|
|
11
12
|
})[];
|
|
12
13
|
export declare function ClosePlugin(): {
|
|
13
14
|
name: string;
|
package/vite.js
CHANGED
|
@@ -13,6 +13,7 @@ export const autoImports = [
|
|
|
13
13
|
'@data-fair/lib-vue/ws.js': ['useWS'],
|
|
14
14
|
'@data-fair/lib-vue/async-action.js': ['useAsyncAction'],
|
|
15
15
|
'@data-fair/lib-vue/deep-diff.js': ['computedDeepDiff', 'watchDeepDiff'],
|
|
16
|
+
'@data-fair/lib-vue/format/bytes.js': ['formatBytes'],
|
|
16
17
|
}
|
|
17
18
|
];
|
|
18
19
|
// cf https://stackoverflow.com/questions/75839993/vite-build-hangs-forever/76920975#76920975
|