From 1fe46e605a5fcac193db7e7649f0547bddf23cf1 Mon Sep 17 00:00:00 2001 From: Amir Raminfar Date: Fri, 27 Oct 2023 12:53:42 -0700 Subject: [PATCH] feat: syncs settings to disk for authenticated users (#2445) --- .gitignore | 1 + assets/auto-imports.d.ts | 87 ++++++++-------- .../LogViewer/LogEventSource.spec.ts | 3 +- assets/composables/eventsource.ts | 4 +- assets/layouts/default.vue | 2 +- assets/modules/router.ts | 3 +- assets/pages/login.vue | 4 +- assets/pages/settings.vue | 2 +- assets/stores/config.ts | 7 +- assets/stores/container.ts | 2 +- assets/{composables => stores}/settings.ts | 14 ++- internal/auth/proxy.go | 26 ++--- internal/profile/settings.go | 99 +++++++++++++++++++ internal/web/index.go | 78 +++++++++------ internal/web/profile.go | 32 ++++++ internal/web/routes.go | 12 ++- main.go | 10 +- public/favicon.ico | 0 vite.config.ts | 3 + 19 files changed, 288 insertions(+), 101 deletions(-) rename assets/{composables => stores}/settings.ts (76%) create mode 100644 internal/profile/settings.go create mode 100644 internal/web/profile.go create mode 100644 public/favicon.ico diff --git a/.gitignore b/.gitignore index 8b9483e0..e9f99b36 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ certs +data dist node_modules .cache diff --git a/assets/auto-imports.d.ts b/assets/auto-imports.d.ts index 362e22d2..8df58545 100644 --- a/assets/auto-imports.d.ts +++ b/assets/auto-imports.d.ts @@ -12,14 +12,14 @@ declare global { const $ref: typeof import('vue/macros')['$ref'] const $shallowRef: typeof import('vue/macros')['$shallowRef'] const $toRef: typeof import('vue/macros')['$toRef'] - const DEFAULT_SETTINGS: typeof import('./composables/settings')['DEFAULT_SETTINGS'] + const DEFAULT_SETTINGS: typeof import('./stores/settings')['DEFAULT_SETTINGS'] const EffectScope: typeof import('vue')['EffectScope'] const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate'] const arrayEquals: typeof import('./utils/index')['arrayEquals'] const asyncComputed: typeof import('@vueuse/core')['asyncComputed'] const autoResetRef: typeof import('@vueuse/core')['autoResetRef'] - const automaticRedirect: typeof import('./composables/settings')['automaticRedirect'] - const collapseNav: typeof import('./composables/settings')['collapseNav'] + const automaticRedirect: typeof import('./stores/settings')['automaticRedirect'] + const collapseNav: typeof import('./stores/settings')['collapseNav'] const computed: typeof import('vue')['computed'] const computedAsync: typeof import('@vueuse/core')['computedAsync'] const computedEager: typeof import('@vueuse/core')['computedEager'] @@ -58,7 +58,7 @@ declare global { const getDeep: typeof import('./utils/index')['getDeep'] const globalShowPopup: typeof import('./composables/popup')['globalShowPopup'] const h: typeof import('vue')['h'] - const hourStyle: typeof import('./composables/settings')['hourStyle'] + const hourStyle: typeof import('./stores/settings')['hourStyle'] const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch'] const inject: typeof import('vue')['inject'] const injectLocal: typeof import('@vueuse/core')['injectLocal'] @@ -69,7 +69,7 @@ declare global { const isReactive: typeof import('vue')['isReactive'] const isReadonly: typeof import('vue')['isReadonly'] const isRef: typeof import('vue')['isRef'] - const lightTheme: typeof import('./composables/settings')['lightTheme'] + const lightTheme: typeof import('./stores/settings')['lightTheme'] const logicAnd: typeof import('@vueuse/math')['logicAnd'] const logicNot: typeof import('@vueuse/math')['logicNot'] const logicOr: typeof import('@vueuse/math')['logicOr'] @@ -80,7 +80,7 @@ declare global { const mapStores: typeof import('pinia')['mapStores'] const mapWritableState: typeof import('pinia')['mapWritableState'] const markRaw: typeof import('vue')['markRaw'] - const menuWidth: typeof import('./composables/settings')['menuWidth'] + const menuWidth: typeof import('./stores/settings')['menuWidth'] const nextTick: typeof import('vue')['nextTick'] const onActivated: typeof import('vue')['onActivated'] const onBeforeMount: typeof import('vue')['onBeforeMount'] @@ -123,21 +123,21 @@ declare global { const resolveComponent: typeof import('vue')['resolveComponent'] const resolveRef: typeof import('@vueuse/core')['resolveRef'] const resolveUnref: typeof import('@vueuse/core')['resolveUnref'] - const search: typeof import('./composables/settings')['search'] + const search: typeof import('./stores/settings')['search'] const sessionHost: typeof import('./composables/storage')['sessionHost'] const setActivePinia: typeof import('pinia')['setActivePinia'] const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix'] const setTitle: typeof import('./composables/title')['setTitle'] - const settings: typeof import('./composables/settings')['settings'] + const settings: typeof import('./stores/settings')['settings'] const shallowReactive: typeof import('vue')['shallowReactive'] const shallowReadonly: typeof import('vue')['shallowReadonly'] const shallowRef: typeof import('vue')['shallowRef'] - const showAllContainers: typeof import('./composables/settings')['showAllContainers'] - const showStd: typeof import('./composables/settings')['showStd'] - const showTimestamp: typeof import('./composables/settings')['showTimestamp'] - const size: typeof import('./composables/settings')['size'] - const smallerScrollbars: typeof import('./composables/settings')['smallerScrollbars'] - const softWrap: typeof import('./composables/settings')['softWrap'] + const showAllContainers: typeof import('./stores/settings')['showAllContainers'] + const showStd: typeof import('./stores/settings')['showStd'] + const showTimestamp: typeof import('./stores/settings')['showTimestamp'] + const size: typeof import('./stores/settings')['size'] + const smallerScrollbars: typeof import('./stores/settings')['smallerScrollbars'] + const softWrap: typeof import('./stores/settings')['softWrap'] const storeToRefs: typeof import('pinia')['storeToRefs'] const stripVersion: typeof import('./utils/index')['stripVersion'] const syncRef: typeof import('@vueuse/core')['syncRef'] @@ -358,6 +358,7 @@ declare global { const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable'] const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter'] const whenever: typeof import('@vueuse/core')['whenever'] + const withBase: typeof import('./stores/config')['withBase'] } // for type re-export declare global { @@ -375,14 +376,14 @@ declare module 'vue' { readonly $ref: UnwrapRef readonly $shallowRef: UnwrapRef readonly $toRef: UnwrapRef - readonly DEFAULT_SETTINGS: UnwrapRef + readonly DEFAULT_SETTINGS: UnwrapRef readonly EffectScope: UnwrapRef readonly acceptHMRUpdate: UnwrapRef readonly arrayEquals: UnwrapRef readonly asyncComputed: UnwrapRef readonly autoResetRef: UnwrapRef - readonly automaticRedirect: UnwrapRef - readonly collapseNav: UnwrapRef + readonly automaticRedirect: UnwrapRef + readonly collapseNav: UnwrapRef readonly computed: UnwrapRef readonly computedAsync: UnwrapRef readonly computedEager: UnwrapRef @@ -419,7 +420,7 @@ declare module 'vue' { readonly getDeep: UnwrapRef readonly globalShowPopup: UnwrapRef readonly h: UnwrapRef - readonly hourStyle: UnwrapRef + readonly hourStyle: UnwrapRef readonly ignorableWatch: UnwrapRef readonly inject: UnwrapRef readonly injectLocal: UnwrapRef @@ -430,7 +431,7 @@ declare module 'vue' { readonly isReactive: UnwrapRef readonly isReadonly: UnwrapRef readonly isRef: UnwrapRef - readonly lightTheme: UnwrapRef + readonly lightTheme: UnwrapRef readonly makeDestructurable: UnwrapRef readonly mapActions: UnwrapRef readonly mapGetters: UnwrapRef @@ -438,7 +439,7 @@ declare module 'vue' { readonly mapStores: UnwrapRef readonly mapWritableState: UnwrapRef readonly markRaw: UnwrapRef - readonly menuWidth: UnwrapRef + readonly menuWidth: UnwrapRef readonly nextTick: UnwrapRef readonly onActivated: UnwrapRef readonly onBeforeMount: UnwrapRef @@ -481,21 +482,21 @@ declare module 'vue' { readonly resolveComponent: UnwrapRef readonly resolveRef: UnwrapRef readonly resolveUnref: UnwrapRef - readonly search: UnwrapRef + readonly search: UnwrapRef readonly sessionHost: UnwrapRef readonly setActivePinia: UnwrapRef readonly setMapStoreSuffix: UnwrapRef readonly setTitle: UnwrapRef - readonly settings: UnwrapRef + readonly settings: UnwrapRef readonly shallowReactive: UnwrapRef readonly shallowReadonly: UnwrapRef readonly shallowRef: UnwrapRef - readonly showAllContainers: UnwrapRef - readonly showStd: UnwrapRef - readonly showTimestamp: UnwrapRef - readonly size: UnwrapRef - readonly smallerScrollbars: UnwrapRef - readonly softWrap: UnwrapRef + readonly showAllContainers: UnwrapRef + readonly showStd: UnwrapRef + readonly showTimestamp: UnwrapRef + readonly size: UnwrapRef + readonly smallerScrollbars: UnwrapRef + readonly softWrap: UnwrapRef readonly storeToRefs: UnwrapRef readonly stripVersion: UnwrapRef readonly syncRef: UnwrapRef @@ -703,6 +704,7 @@ declare module 'vue' { readonly watchTriggerable: UnwrapRef readonly watchWithFilter: UnwrapRef readonly whenever: UnwrapRef + readonly withBase: UnwrapRef } } declare module '@vue/runtime-core' { @@ -714,14 +716,14 @@ declare module '@vue/runtime-core' { readonly $ref: UnwrapRef readonly $shallowRef: UnwrapRef readonly $toRef: UnwrapRef - readonly DEFAULT_SETTINGS: UnwrapRef + readonly DEFAULT_SETTINGS: UnwrapRef readonly EffectScope: UnwrapRef readonly acceptHMRUpdate: UnwrapRef readonly arrayEquals: UnwrapRef readonly asyncComputed: UnwrapRef readonly autoResetRef: UnwrapRef - readonly automaticRedirect: UnwrapRef - readonly collapseNav: UnwrapRef + readonly automaticRedirect: UnwrapRef + readonly collapseNav: UnwrapRef readonly computed: UnwrapRef readonly computedAsync: UnwrapRef readonly computedEager: UnwrapRef @@ -758,7 +760,7 @@ declare module '@vue/runtime-core' { readonly getDeep: UnwrapRef readonly globalShowPopup: UnwrapRef readonly h: UnwrapRef - readonly hourStyle: UnwrapRef + readonly hourStyle: UnwrapRef readonly ignorableWatch: UnwrapRef readonly inject: UnwrapRef readonly injectLocal: UnwrapRef @@ -769,7 +771,7 @@ declare module '@vue/runtime-core' { readonly isReactive: UnwrapRef readonly isReadonly: UnwrapRef readonly isRef: UnwrapRef - readonly lightTheme: UnwrapRef + readonly lightTheme: UnwrapRef readonly makeDestructurable: UnwrapRef readonly mapActions: UnwrapRef readonly mapGetters: UnwrapRef @@ -777,7 +779,7 @@ declare module '@vue/runtime-core' { readonly mapStores: UnwrapRef readonly mapWritableState: UnwrapRef readonly markRaw: UnwrapRef - readonly menuWidth: UnwrapRef + readonly menuWidth: UnwrapRef readonly nextTick: UnwrapRef readonly onActivated: UnwrapRef readonly onBeforeMount: UnwrapRef @@ -820,21 +822,21 @@ declare module '@vue/runtime-core' { readonly resolveComponent: UnwrapRef readonly resolveRef: UnwrapRef readonly resolveUnref: UnwrapRef - readonly search: UnwrapRef + readonly search: UnwrapRef readonly sessionHost: UnwrapRef readonly setActivePinia: UnwrapRef readonly setMapStoreSuffix: UnwrapRef readonly setTitle: UnwrapRef - readonly settings: UnwrapRef + readonly settings: UnwrapRef readonly shallowReactive: UnwrapRef readonly shallowReadonly: UnwrapRef readonly shallowRef: UnwrapRef - readonly showAllContainers: UnwrapRef - readonly showStd: UnwrapRef - readonly showTimestamp: UnwrapRef - readonly size: UnwrapRef - readonly smallerScrollbars: UnwrapRef - readonly softWrap: UnwrapRef + readonly showAllContainers: UnwrapRef + readonly showStd: UnwrapRef + readonly showTimestamp: UnwrapRef + readonly size: UnwrapRef + readonly smallerScrollbars: UnwrapRef + readonly softWrap: UnwrapRef readonly storeToRefs: UnwrapRef readonly stripVersion: UnwrapRef readonly syncRef: UnwrapRef @@ -1042,5 +1044,6 @@ declare module '@vue/runtime-core' { readonly watchTriggerable: UnwrapRef readonly watchWithFilter: UnwrapRef readonly whenever: UnwrapRef + readonly withBase: UnwrapRef } } diff --git a/assets/components/LogViewer/LogEventSource.spec.ts b/assets/components/LogViewer/LogEventSource.spec.ts index bcd5aeef..58f6c65c 100644 --- a/assets/components/LogViewer/LogEventSource.spec.ts +++ b/assets/components/LogViewer/LogEventSource.spec.ts @@ -4,7 +4,7 @@ import { createTestingPinia } from "@pinia/testing"; import EventSource, { sources } from "eventsourcemock"; import LogEventSource from "./LogEventSource.vue"; import LogViewer from "./LogViewer.vue"; -import { settings } from "@/composables/settings"; +import { settings } from "@/stores/settings"; import { useSearchFilter } from "@/composables/search"; import { vi, describe, expect, beforeEach, test, afterEach } from "vitest"; import { computed, nextTick } from "vue"; @@ -14,6 +14,7 @@ import { containerContext } from "@/composables/containerContext"; vi.mock("@/stores/config", () => ({ __esModule: true, default: { base: "", hosts: [{ name: "localhost", id: "localhost" }] }, + withBase: (path: string) => path, })); /** diff --git a/assets/composables/eventsource.ts b/assets/composables/eventsource.ts index 21b74d6d..41b9edb4 100644 --- a/assets/composables/eventsource.ts +++ b/assets/composables/eventsource.ts @@ -85,7 +85,7 @@ export function useLogStream() { console.debug(`Connecting to ${containerId} with params`, params); es = new EventSource( - `${config.base}/api/logs/stream/${container.value.host}/${containerId}?${new URLSearchParams(params).toString()}`, + withBase(`/api/logs/stream/${container.value.host}/${containerId}?${new URLSearchParams(params).toString()}`), ); es.addEventListener("container-stopped", () => { close(); @@ -118,7 +118,7 @@ export function useLogStream() { const logs = await ( await fetch( - `${config.base}/api/logs/${container.value.host}/${containerId}?${new URLSearchParams(params).toString()}`, + withBase(`/api/logs/${container.value.host}/${containerId}?${new URLSearchParams(params).toString()}`), ) ).text(); if (logs) { diff --git a/assets/layouts/default.vue b/assets/layouts/default.vue index 31eb8ad5..b61b5e0b 100644 --- a/assets/layouts/default.vue +++ b/assets/layouts/default.vue @@ -65,7 +65,7 @@