Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
Tim Gröger | 122f313342 | |
Tim Gröger | 096c190946 | |
Tim Gröger | a807d9c809 | |
Tim Gröger | a080a90f2c | |
Tim Gröger | 58544c7563 | |
Tim Gröger | f777e36b7c | |
Tim Gröger | 5bd837c11f | |
Tim Gröger | 0cc0b8053c |
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"name": "@flaschengeist/api",
|
"name": "@flaschengeist/api",
|
||||||
"author": "Tim Gröger <flaschengeist@wu5.de>",
|
"author": "Tim Gröger <flaschengeist@wu5.de>",
|
||||||
"homepage": "https://flaschengeist.dev/Flaschengeist",
|
"homepage": "https://flaschengeist.dev/Flaschengeist",
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { api } from '../internal';
|
||||||
|
import { isAxiosError, useMainStore } from '.';
|
||||||
|
|
||||||
|
export const useApiKeyStore = defineStore({
|
||||||
|
id: 'apiKeys',
|
||||||
|
|
||||||
|
state: () => ({
|
||||||
|
apiKeys: [] as FG.ApiKey[],
|
||||||
|
}),
|
||||||
|
|
||||||
|
getters: {},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
async getApiKeys(): Promise<FG.ApiKey[]> {
|
||||||
|
try {
|
||||||
|
const mainStore = useMainStore();
|
||||||
|
const { data } = await api.get<FG.ApiKey[]>(
|
||||||
|
`/users/${mainStore.currentUser.userid}/api_keys`
|
||||||
|
);
|
||||||
|
|
||||||
|
this.apiKeys = data;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
return [] as FG.ApiKey[];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async deleteApiKey(id: number): Promise<boolean> {
|
||||||
|
const mainStore = useMainStore();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await api.delete(`/users/${mainStore.currentUser.userid}/api_keys/${id}`);
|
||||||
|
this.apiKeys = this.apiKeys.filter((apiKey: FG.ApiKey) => apiKey.id !== id);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore 401, as this means we are already logged out, throw all other
|
||||||
|
if (!isAxiosError(error, 401)) throw error;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
async createApiKey(apiKey: FG.ApiKey): Promise<FG.ApiKey> {
|
||||||
|
const mainStore = useMainStore();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data } = await api.post<FG.ApiKey>(
|
||||||
|
`/users/${mainStore.currentUser.userid}/api_keys`,
|
||||||
|
apiKey
|
||||||
|
);
|
||||||
|
|
||||||
|
this.apiKeys.push(data);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
|
@ -21,3 +21,4 @@ export function isAxiosError(error: unknown, status?: number) {
|
||||||
export * from './main';
|
export * from './main';
|
||||||
export * from './session';
|
export * from './session';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
|
export * from './apiKeys';
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { api } from '../internal';
|
import { api } from '../internal';
|
||||||
import { isAxiosError, useMainStore } from '.';
|
import { isAxiosError, useMainStore } from '.';
|
||||||
|
import { DisplayNameMode } from '@flaschengeist/users';
|
||||||
|
|
||||||
export function fixUser(u?: FG.User) {
|
export function fixUser(u?: FG.User) {
|
||||||
return !u ? u : Object.assign(u, { birthday: u.birthday ? new Date(u.birthday) : undefined });
|
return !u ? u : Object.assign(u, { birthday: u.birthday ? new Date(u.birthday) : undefined });
|
||||||
|
@ -22,6 +23,7 @@ export const useUserStore = defineStore({
|
||||||
state: () => ({
|
state: () => ({
|
||||||
roles: [] as FG.Role[],
|
roles: [] as FG.Role[],
|
||||||
permissions: [] as FG.Permission[],
|
permissions: [] as FG.Permission[],
|
||||||
|
userSettings: {} as FG.UserSettings,
|
||||||
// list of all users, include deleted ones, use `users` getter for list of active ones
|
// list of all users, include deleted ones, use `users` getter for list of active ones
|
||||||
_users: [] as FG.User[],
|
_users: [] as FG.User[],
|
||||||
// Internal flags for deciding if lists need to force-loaded
|
// Internal flags for deciding if lists need to force-loaded
|
||||||
|
@ -31,7 +33,42 @@ export const useUserStore = defineStore({
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
users(state) {
|
users(state) {
|
||||||
return state._users.filter((u) => !u.deleted);
|
const u = state._users.filter((u) => !u.deleted);
|
||||||
|
|
||||||
|
switch (this.userSettings['display_name']) {
|
||||||
|
case DisplayNameMode.FIRSTNAME_LASTNAME || DisplayNameMode.FIRSTNAME:
|
||||||
|
u.sort((a, b) => {
|
||||||
|
const a_lastname = a.lastname.toLowerCase();
|
||||||
|
const b_lastname = b.lastname.toLowerCase();
|
||||||
|
const a_firstname = a.firstname.toLowerCase();
|
||||||
|
const b_firstname = b.firstname.toLowerCase();
|
||||||
|
if (a_firstname === b_firstname) {
|
||||||
|
return a_lastname < b_lastname ? -1 : 1;
|
||||||
|
}
|
||||||
|
return a_firstname < b_firstname ? -1 : 1;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case <string>DisplayNameMode.DISPLAYNAME:
|
||||||
|
u.sort((a, b) => {
|
||||||
|
const a_displayname = a.display_name.toLowerCase();
|
||||||
|
const b_displayname = b.display_name.toLowerCase();
|
||||||
|
return a_displayname < b_displayname ? -1 : 1;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
u.sort((a, b) => {
|
||||||
|
const a_lastname = a.lastname.toLowerCase();
|
||||||
|
const b_lastname = b.lastname.toLowerCase();
|
||||||
|
const a_firstname = a.firstname.toLowerCase();
|
||||||
|
const b_firstname = b.firstname.toLowerCase();
|
||||||
|
if (a_lastname === b_lastname) {
|
||||||
|
return a_firstname < b_firstname ? -1 : 1;
|
||||||
|
}
|
||||||
|
return a_lastname < b_lastname ? -1 : 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return u;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -207,5 +244,35 @@ export const useUserStore = defineStore({
|
||||||
await api.delete(`/roles/${role}`);
|
await api.delete(`/roles/${role}`);
|
||||||
this.roles = this.roles.filter((r) => r.id !== role);
|
this.roles = this.roles.filter((r) => r.id !== role);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** Get Settings for display name mode
|
||||||
|
* @param force If set to true a fresh list is loaded from backend even when a local copy is available
|
||||||
|
* @throws Probably an AxiosError if request failed
|
||||||
|
* @returns Settings for display name mode
|
||||||
|
*/
|
||||||
|
async getDisplayNameModeSetting(force = false): Promise<string> {
|
||||||
|
const mainStore = useMainStore();
|
||||||
|
if (force) {
|
||||||
|
const { data } = await api.get<{ data: string }>(
|
||||||
|
`users/${mainStore.currentUser.userid}/setting/display_name_mode`
|
||||||
|
);
|
||||||
|
this.userSettings['display_name'] = data.data;
|
||||||
|
}
|
||||||
|
return this.userSettings['display_name'];
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Set Settings for display name mode
|
||||||
|
* @param mode New display name mode
|
||||||
|
* @throws Probably an AxiosError if request failed
|
||||||
|
* @returns Settings for display name mode
|
||||||
|
*/
|
||||||
|
async setDisplayNameModeSetting(mode: string): Promise<string> {
|
||||||
|
const mainStore = useMainStore();
|
||||||
|
await api.put(`users/${mainStore.currentUser.userid}/setting/display_name_mode`, {
|
||||||
|
data: mode,
|
||||||
|
});
|
||||||
|
this.userSettings['display_name'] = mode;
|
||||||
|
return mode;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "2.0.0",
|
"version": "2.1.0",
|
||||||
"productName": "flaschengeist-frontend",
|
"productName": "flaschengeist-frontend",
|
||||||
"name": "flaschengeist",
|
"name": "flaschengeist",
|
||||||
"author": "Tim Gröger <flaschengeist@wu5.de>",
|
"author": "Tim Gröger <flaschengeist@wu5.de>",
|
||||||
|
|
|
@ -3,4 +3,4 @@ module.exports = [
|
||||||
// '@flaschengeist/balance',
|
// '@flaschengeist/balance',
|
||||||
// '@flaschengeist/schedule',
|
// '@flaschengeist/schedule',
|
||||||
// '@flaschengeist/pricelist',
|
// '@flaschengeist/pricelist',
|
||||||
]
|
'@flaschengeist/schedule',
|
||||||
|
|
|
@ -15,12 +15,18 @@ const { configure } = require('quasar/wrappers');
|
||||||
const operation = () => {
|
const operation = () => {
|
||||||
const custom_plgns = require('./plugin.config.js');
|
const custom_plgns = require('./plugin.config.js');
|
||||||
const required_plgns = require('./src/vendor-plugin.config.js');
|
const required_plgns = require('./src/vendor-plugin.config.js');
|
||||||
const plugins = [...custom_plgns, ...required_plgns].map((v) => `import("${v}").catch(() => "${v}")`);
|
const plugins = [...custom_plgns, ...required_plgns].map(
|
||||||
const replace = new ReplaceOperation('all', `\\/\\* *INSERT_PLUGIN_LIST *\\*\\/`, `${plugins.join(', ')}`);
|
(v) => `import("${v}").catch(() => "${v}")`
|
||||||
|
);
|
||||||
|
const replace = new ReplaceOperation(
|
||||||
|
'all',
|
||||||
|
`\\/\\* *INSERT_PLUGIN_LIST *\\*\\/`,
|
||||||
|
`${plugins.join(', ')}`
|
||||||
|
);
|
||||||
return replace;
|
return replace;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = configure(function(/* ctx */) {
|
module.exports = configure(function (/* ctx */) {
|
||||||
return {
|
return {
|
||||||
// https://quasar.dev/quasar-cli/supporting-ts
|
// https://quasar.dev/quasar-cli/supporting-ts
|
||||||
supportTS: {
|
supportTS: {
|
||||||
|
@ -50,7 +56,7 @@ module.exports = configure(function(/* ctx */) {
|
||||||
// 'ionicons-v5',
|
// 'ionicons-v5',
|
||||||
// 'line-awesome',
|
// 'line-awesome',
|
||||||
// 'material-icons',
|
// 'material-icons',
|
||||||
'mdi-v6',
|
'mdi-v7',
|
||||||
// 'themify',
|
// 'themify',
|
||||||
|
|
||||||
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
||||||
|
@ -60,7 +66,7 @@ module.exports = configure(function(/* ctx */) {
|
||||||
// Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
|
// Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
|
||||||
build: {
|
build: {
|
||||||
vueRouterMode: 'history', // available values: 'hash', 'history'
|
vueRouterMode: 'history', // available values: 'hash', 'history'
|
||||||
|
//publicPath: 'flaschengeist2',
|
||||||
// transpile: false,
|
// transpile: false,
|
||||||
|
|
||||||
// Add dependencies for transpiling with Babel (Array of string/regex)
|
// Add dependencies for transpiling with Babel (Array of string/regex)
|
||||||
|
@ -214,5 +220,8 @@ module.exports = configure(function(/* ctx */) {
|
||||||
// chainWebpack also available besides this extendWebpack
|
// chainWebpack also available besides this extendWebpack
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
bin: {
|
||||||
|
linuxAndroidStudio: '/home/crimsen/.local/share/JetBrains/Toolbox/scripts/studio',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -234,6 +234,12 @@ function loadPlugin(
|
||||||
Array.prototype.push.apply(loadedPlugins.widgets, plugin.widgets);
|
Array.prototype.push.apply(loadedPlugins.widgets, plugin.widgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!plugin.settingWidgets) plugin.settingWidgets = [];
|
||||||
|
if (plugin.settingWidgets.length > 0) {
|
||||||
|
plugin.settingWidgets.forEach((widget) => (widget.name = plugin.id + '.' + widget.name));
|
||||||
|
Array.prototype.push.apply(loadedPlugins.settingWidgets, plugin.settingWidgets);
|
||||||
|
}
|
||||||
|
|
||||||
loadedPlugins.plugins.push({
|
loadedPlugins.plugins.push({
|
||||||
id: plugin.id,
|
id: plugin.id,
|
||||||
name: plugin.name,
|
name: plugin.name,
|
||||||
|
@ -252,6 +258,7 @@ export async function loadPlugins(backend: FG.Backend, baseRoutes: RouteRecordRa
|
||||||
shortcuts: [],
|
shortcuts: [],
|
||||||
outerShortcuts: [],
|
outerShortcuts: [],
|
||||||
widgets: [],
|
widgets: [],
|
||||||
|
settingWidgets: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wait for all plugins to be loaded
|
// Wait for all plugins to be loaded
|
||||||
|
|
Loading…
Reference in New Issue