From 0e9db032ae79f8460d1e194fb6581d9c6edce8ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Bj=C3=A4reholt?= Date: Thu, 19 Oct 2023 13:41:36 +0200 Subject: [PATCH 1/3] feat: save settings to server --- src/main.js | 14 +++++++++---- src/queries.ts | 2 ++ src/stores/activity.ts | 1 - src/stores/settings.ts | 45 +++++++++++++++++++++++------------------- src/util/awclient.ts | 6 +++++- 5 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/main.js b/src/main.js index 5c2d70b3..00abd2f0 100644 --- a/src/main.js +++ b/src/main.js @@ -72,6 +72,12 @@ Vue.prototype.COMMIT_HASH = COMMIT_HASH; // Set the $isAndroid constant Vue.prototype.$isAndroid = process.env.VUE_APP_ON_ANDROID; +// Create an instance of AWClient as this.$aw +// NOTE: needs to be created before the Vue app is created, +// since stores rely on it having been run. +import { createClient, getClient, configureClient } from './util/awclient'; +createClient(); + // Setup Vue app import App from './App'; new Vue({ @@ -81,8 +87,8 @@ new Vue({ pinia, }); -// Create an instance of AWClient as this.$aw -import { createClient, getClient } from './util/awclient'; - -createClient(); +// Set the $aw global Vue.prototype.$aw = getClient(); + +// Must be run after vue init since it relies on the settings store +configureClient(); diff --git a/src/queries.ts b/src/queries.ts index 42a06ee9..b1902bed 100644 --- a/src/queries.ts +++ b/src/queries.ts @@ -411,6 +411,8 @@ export function editorActivityQuery(editorbuckets: string[]): string[] { // Returns a query that yields a single event with the duration set to // the sum of all non-afk time in the queried period // TODO: Would ideally account for `filter_afk` and `always_active_pattern` +// TODO: rename to something like `activeDurationQuery` +// FIXME: Doesn't respect audible-as-active and always-active-pattern export function activityQuery(afkbuckets: string[]): string[] { let q = ['not_afk = [];']; for (const afkbucket of afkbuckets) { diff --git a/src/stores/activity.ts b/src/stores/activity.ts index eeaeb623..e4f0031f 100644 --- a/src/stores/activity.ts +++ b/src/stores/activity.ts @@ -214,7 +214,6 @@ export const useActivityStore = defineStore('activity', { if (!this.category.top) { return null; } - console.log(this.category.top); const uncategorized = this.category.top.filter(e => { return _.isEqual(e.data['$category'], ['Uncategorized']); }); diff --git a/src/stores/settings.ts b/src/stores/settings.ts index 6f90c861..0e5e723e 100644 --- a/src/stores/settings.ts +++ b/src/stores/settings.ts @@ -1,5 +1,6 @@ import { defineStore } from 'pinia'; import moment, { Moment } from 'moment'; +import { getClient } from '~/util/awclient'; // Backoffs for NewReleaseNotification export const SHORT_BACKOFF_PERIOD = 24 * 60 * 60; @@ -74,22 +75,29 @@ export const useSettingsStore = defineStore('settings', { await this.load(); } }, - async load() { + async load({ save }: { save?: boolean } = {}) { if (typeof localStorage === 'undefined') { console.error('localStorage is not supported'); return; } - // Fetch from localStorage first, if exists + const client = getClient(); + + // Fetch from server, fall back to localStorage + const server_settings = await client.get_settings(); + const all_keys = Object.assign({}, localStorage, server_settings); + const storage = {}; - for (const key in localStorage) { + for (const key in all_keys) { // Skip built-in properties like length, setItem, etc. // Also skip keys starting with underscore, as they are local to the vuex store. if (Object.prototype.hasOwnProperty.call(localStorage, key) && !key.startsWith('_')) { - const value = localStorage.getItem(key); + // Fetch from server if not in localStorage + const value = server_settings[key] || localStorage.getItem(key); + const set_in_server = server_settings[key] !== undefined; //console.log(`${key}: ${value}`); // Keys ending with 'Data' are JSON-serialized objects - if (key.includes('Data')) { + if (key.includes('Data') && !set_in_server) { try { storage[key] = JSON.parse(value); } catch (e) { @@ -104,14 +112,14 @@ export const useSettingsStore = defineStore('settings', { } this.$patch({ ...storage, _loaded: true }); - // TODO: Then fetch from server - //const getSettingsFromServer = async () => { - // const { data } = await this.$aw._get('/0/settings'); - // return data; - //}; + if (save) { + await this.save(); + } }, async save() { - // First save to localStorage + // Save to localStorage and backend + // NOTE: localStorage deprecated, will be removed in future + const client = getClient(); for (const key of Object.keys(this.$state)) { const value = this.$state[key]; if (typeof value === 'object') { @@ -119,18 +127,15 @@ export const useSettingsStore = defineStore('settings', { } else { localStorage.setItem(key, value); } + await client.req.post('/0/settings/' + key, value, { + headers: { + 'Content-Type': 'application/json', + }, + }); } - // TODO: Save to backend - //const updateSettingOnServer = async (key: string, value: string) => { - // console.log({ key, value }); - // const headers = { 'Content-Type': 'application/json' }; - // const { data } = await this.$aw._post('/0/settings', { key, value }, headers); - // return data; - //}; - // After save, reload from localStorage - await this.load(); + await this.load({ save: false }); }, async update(new_state: Record) { console.log('Updating state', new_state); diff --git a/src/util/awclient.ts b/src/util/awclient.ts index a3107721..053ecbd5 100644 --- a/src/util/awclient.ts +++ b/src/util/awclient.ts @@ -20,7 +20,6 @@ export function createClient(force?: boolean): AWClient { _client = new AWClient('aw-webui', { testing: !production, baseURL, - timeout: 1000 * useSettingsStore().requestTimeout, }); } else { throw 'Tried to instantiate global AWClient twice!'; @@ -28,6 +27,11 @@ export function createClient(force?: boolean): AWClient { return _client; } +export function configureClient(): void { + const settings = useSettingsStore(); + _client.req.defaults.timeout = 1000 * settings.requestTimeout; +} + export function getClient(): AWClient { if (!_client) { throw 'Tried to get global AWClient before instantiating it!'; From 52fac3d483664c568b995abf27d945fdd8aca814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Bj=C3=A4reholt?= Date: Thu, 19 Oct 2023 13:45:23 +0200 Subject: [PATCH 2/3] format: applied eslint fix --- src/queries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/queries.ts b/src/queries.ts index b1902bed..422b315f 100644 --- a/src/queries.ts +++ b/src/queries.ts @@ -273,7 +273,7 @@ const browser_appnames = { 'Microsoft-edge', ], arc: [ - "Arc" // macOS + 'Arc', // macOS ], vivaldi: ['Vivaldi-stable', 'Vivaldi-snapshot', 'vivaldi.exe'], orion: ['Orion'], From 7c9794a2036e9ee4da1bbfb37b0f74ff3d21b0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Bj=C3=A4reholt?= Date: Thu, 19 Oct 2023 14:39:40 +0200 Subject: [PATCH 3/3] fix: removed browser-side settings notice, fixed server-side settings bugs --- src/App.vue | 16 +++-- src/components/SelectableVisualization.vue | 2 + src/stores/settings.ts | 70 ++++++++++++++-------- src/views/settings/Settings.vue | 2 - 4 files changed, 53 insertions(+), 37 deletions(-) diff --git a/src/App.vue b/src/App.vue index 0cca5afc..90dcc399 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,5 +1,5 @@