@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 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';
@@ -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
- type UseFetchOptions = {
4
- query?: QueryObject | Ref<QueryObject>;
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: OptionalUrl | Ref<OptionalUrl> | (() => OptionalUrl), options?: UseFetchOptions): {
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, isRef, watch, ref, shallowRef, readonly, shallowReadonly } from 'vue';
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 = isRef(url) ? url.value : url;
10
+ let fullUrl = toValue(url);
11
11
  if (!fullUrl)
12
12
  return null;
13
- const query = isRef(options.query) ? options.query.value : options.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 declare function formatBytes(bytes: number | string, locale?: string): string;
2
- export default formatBytes;
1
+ export * from '@data-fair/lib-utils/format/bytes.js';
package/format/bytes.js CHANGED
@@ -1,22 +1,2 @@
1
- const locales = {
2
- fr: [[0, 'octet'], [1, 'octets'], [1000, 'ko'], [1000 * 1000, 'Mo'], [1000 * 1000 * 1000, 'Go'], [1000 * 1000 * 1000 * 1000, 'To'], [1000 * 1000 * 1000 * 1000 * 1000, 'Po']],
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
- import type { Field } from '@data-fair/lib-common-types/application/index.js';
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
- // TODO: use locale-dayjs for localization of date formats
2
- import dayjs from 'dayjs';
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.24.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.0.0",
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
- if (state.user == null)
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
- // check cookies.get('id_token') not state.user so that we do a keepalive on expired id tokens
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