diff --git a/.eslintrc.js b/.eslintrc.js index 22daaf384e..a880776549 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -171,7 +171,6 @@ module.exports = { 'vue/no-empty-component-block': 'error', 'vue/no-multiple-objects-in-class': 'error', 'vue/no-ref-object-reactivity-loss': 'error', - 'vue/no-required-prop-with-default': 'error', 'vue/no-static-inline-styles': 'error', 'vue/no-template-target-blank': 'error', 'vue/no-undef-components': ['error', { ignorePatterns: ['RouterLink', 'RouterView', 'I18nT'] }], diff --git a/@xen-orchestra/web-core/lib/packages/request/define-request.ts b/@xen-orchestra/web-core/lib/packages/request/define-request.ts new file mode 100644 index 0000000000..6916e01032 --- /dev/null +++ b/@xen-orchestra/web-core/lib/packages/request/define-request.ts @@ -0,0 +1,64 @@ +import { useTimeoutPoll } from '@vueuse/core' +import type { MaybeRefOrGetter } from '@vueuse/shared' +// eslint-disable-next-line import/namespace,import/default,import/no-named-as-default,import/no-named-as-default-member -- https://github.com/pamelafox/ndjson-readablestream/pull/13 +import readNDJSONStream from 'ndjson-readablestream' +import { computed, isRef, toValue, watch } from 'vue' + +export function defineRequest(options: { + url: string + state: () => TState + onDataReceived: (state: TState, data: unknown) => void +}): () => TState + +export function defineRequest(options: { + url: (...args: TArgs) => string + state: () => TState + onDataReceived: (state: TState, data: unknown) => void + onUrlChange: (state: TState) => void +}): (...args: { [K in keyof TArgs]: MaybeRefOrGetter }) => TState + +export function defineRequest(options: { + url: string | ((...args: TArgs) => string) + state: () => TState + onDataReceived: (state: TState, data: unknown) => void + onUrlChange?: (state: TState) => void +}) { + return function useRequest(...args: { [K in keyof TArgs]: MaybeRefOrGetter }) { + const urlOption = options.url + + const url = typeof urlOption === 'function' ? computed(() => urlOption(...(args.map(toValue) as TArgs))) : urlOption + + const state = options.state() + + async function execute() { + const response = await fetch(toValue(url)) + + if (!response.ok) { + throw new Error(`Failed to fetch: ${response.statusText}`) + } + + if (!response.body) { + throw new Error('Response body is empty') + } + + for await (const event of readNDJSONStream(response.body)) { + options.onDataReceived(state, event) + } + } + + const { resume, pause } = useTimeoutPoll(execute, 10000, { + immediate: true, + immediateCallback: true, + }) + + if (isRef(url)) { + watch(url, () => { + pause() + options.onUrlChange?.(state) + resume() + }) + } + + return state + } +} diff --git a/@xen-orchestra/web-core/package.json b/@xen-orchestra/web-core/package.json index a3ffd207ae..95fe6f5f30 100644 --- a/@xen-orchestra/web-core/package.json +++ b/@xen-orchestra/web-core/package.json @@ -26,6 +26,7 @@ "human-format": "^1.2.1", "iterable-backoff": "^0.1.0", "lodash-es": "^4.17.21", + "ndjson-readablestream": "^1.2.0", "placement.js": "^1.0.0-beta.5", "simple-icons": "^14.14.0", "vue-echarts": "^6.6.8" diff --git a/@xen-orchestra/web/package.json b/@xen-orchestra/web/package.json index 55d0b469d7..fe032f30ca 100644 --- a/@xen-orchestra/web/package.json +++ b/@xen-orchestra/web/package.json @@ -36,6 +36,7 @@ "d3-time-format": "^4.1.0", "human-format": "^1.2.1", "lodash-es": "^4.17.21", + "ndjson-readablestream": "^1.2.0", "npm-run-all2": "^7.0.2", "pinia": "^3.0.1", "postcss": "^8.5.3", diff --git a/@xen-orchestra/web/src/components/site/dashboard/BackupIssues.vue b/@xen-orchestra/web/src/components/site/dashboard/BackupIssues.vue index 6594ddaa96..aa1f1f7c7d 100644 --- a/@xen-orchestra/web/src/components/site/dashboard/BackupIssues.vue +++ b/@xen-orchestra/web/src/components/site/dashboard/BackupIssues.vue @@ -45,7 +45,7 @@ diff --git a/@xen-orchestra/web/src/components/site/dashboard/Backups.vue b/@xen-orchestra/web/src/components/site/dashboard/Backups.vue index f56d851560..59c9f3a8c6 100644 --- a/@xen-orchestra/web/src/components/site/dashboard/Backups.vue +++ b/@xen-orchestra/web/src/components/site/dashboard/Backups.vue @@ -2,10 +2,10 @@ {{ t('backups') }} - + @@ -13,7 +13,7 @@ diff --git a/@xen-orchestra/web/src/components/site/dashboard/ResourcesOverview.vue b/@xen-orchestra/web/src/components/site/dashboard/ResourcesOverview.vue index 70cd0f51b4..831f54f501 100644 --- a/@xen-orchestra/web/src/components/site/dashboard/ResourcesOverview.vue +++ b/@xen-orchestra/web/src/components/site/dashboard/ResourcesOverview.vue @@ -18,7 +18,7 @@