Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template lang="pug">
div#wrapper
div#wrapper(v-if="loaded")
aw-header

div(:class="{'container': !fullContainer, 'container-fluid': fullContainer}").px-0.px-md-2
Expand All @@ -21,6 +21,7 @@ export default {
return {
activityViews: [],
isNewReleaseCheckEnabled: !process.env.VUE_APP_ON_ANDROID,
loaded: false,
};
},

Expand All @@ -30,9 +31,11 @@ export default {
},
},

beforeCreate() {
async beforeCreate() {
// Get Theme From LocalStorage
const theme = localStorage.getItem('theme');
const settingsStore = useSettingsStore();
await settingsStore.ensureLoaded();
const theme = settingsStore.theme;
// Check Application Mode (Light | Dark)
if (theme !== null && theme === 'dark') {
// Create Dark Theme Element
Expand All @@ -42,15 +45,10 @@ export default {
// Append Dark Theme Element If Selected Mode Is Dark
theme === 'dark' ? document.querySelector('head').appendChild(themeLink) : '';
}
this.loaded = true;
},

mounted: async function () {
// Load settings
// TODO: Move fetch of server-side settings to after getInfo

const settingsStore = useSettingsStore();
await settingsStore.ensureLoaded();

const serverStore = useServerStore();
await serverStore.getInfo();
},
Expand Down
2 changes: 2 additions & 0 deletions src/components/SelectableVisualization.vue
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ export default {
return date;
},
timeline_daterange: function () {
if (this.activityStore.query_options === null) return null;

let date = this.activityStore.query_options.date;
if (!date) {
date = this.activityStore.query_options.timeperiod.start;
Expand Down
14 changes: 10 additions & 4 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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();
4 changes: 3 additions & 1 deletion src/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ const browser_appnames = {
'Microsoft-edge',
],
arc: [
"Arc" // macOS
'Arc', // macOS
],
vivaldi: ['Vivaldi-stable', 'Vivaldi-snapshot', 'vivaldi.exe'],
orion: ['Orion'],
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 0 additions & 1 deletion src/stores/activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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']);
});
Expand Down
103 changes: 63 additions & 40 deletions src/stores/settings.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -74,63 +75,85 @@ 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.keys(localStorage).filter(key => {
// Skip built-in properties like length, setItem, etc.
return Object.prototype.hasOwnProperty.call(localStorage, key);
}),
...Object.keys(server_settings),
].filter(key => {
// Skip keys starting with underscore, as they are local to the vuex store.
return !key.startsWith('_');
});
console.log('all_keys', all_keys);

const storage = {};
for (const key in localStorage) {
// 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);
//console.log(`${key}: ${value}`);

// Keys ending with 'Data' are JSON-serialized objects
if (key.includes('Data')) {
try {
storage[key] = JSON.parse(value);
} catch (e) {
console.error('failed to parse', key, value);
}
} else if (value === 'true' || value === 'false') {
storage[key] = value === 'true';
} else {
storage[key] = value;
for (const key of all_keys) {
// If key is set in server, use that value, otherwise use localStorage
const set_in_server = server_settings[key] !== undefined;
const value = set_in_server ? server_settings[key] : localStorage.getItem(key);
const locstr = set_in_server ? '[server]' : '[localStorage]';
console.log(`${locstr} ${key}:`, value);

// Keys ending with 'Data' are JSON-serialized objects
if (key.includes('Data') && !set_in_server) {
try {
storage[key] = JSON.parse(value);
} catch (e) {
console.error('failed to parse', key, value);
}
} else if (value === 'true' || value === 'false') {
storage[key] = value === 'true';
} else {
storage[key] = value;
}
}
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
// We want to avoid saving to localStorage to not accidentally mess up pre-migration data
// For example, if the user is using several browsers, and opened in their non-main browser on first run after upgrade.
const saveToLocalStorage = false;

// 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') {
localStorage.setItem(key, JSON.stringify(value));
} else {
localStorage.setItem(key, value);

// Save to localStorage
if (saveToLocalStorage) {
if (typeof value === 'object') {
localStorage.setItem(key, JSON.stringify(value));
} else {
localStorage.setItem(key, value);
}
}
}

// 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;
//};
// Save to backend
await client.req.post('/0/settings/' + key, value, {
headers: {
'Content-Type': 'application/json',
},
});
}

// After save, reload from localStorage
await this.load();
// After save, reload
await this.load({ save: false });
},
async update(new_state: Record<string, any>) {
console.log('Updating state', new_state);
Expand Down
6 changes: 5 additions & 1 deletion src/util/awclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ 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!';
}
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!';
Expand Down
2 changes: 0 additions & 2 deletions src/views/settings/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
div
h3 Settings

b-alert(variant="warning", show) #[b Note:] These settings are only saved in your browser and will not remain if you switch browser. We are working on getting this fixed, see #[a(href="https://github.com/ActivityWatch/aw-server-rust/issues/394", target="_blank") issue #394].

hr

DaystartSettings
Expand Down