Compare commits
	
		
			5 Commits
		
	
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | d50a0bcc3b | |
|  | c03fa689ba | |
|  | 6a738dc77e | |
|  | f5a875007b | |
|  | d8d89f0475 | 
|  | @ -1,6 +1,6 @@ | |||
| { | ||||
|   "license": "MIT", | ||||
|   "version": "1.1.0", | ||||
|   "version": "1.2.0", | ||||
|   "name": "@flaschengeist/users", | ||||
|   "author": "Ferdinand Thiessen <rpm@fthiessen.de>", | ||||
|   "homepage": "https://flaschengeist.dev/Flaschengeist", | ||||
|  | @ -18,8 +18,8 @@ | |||
|     "lint": "eslint --ext .js,.ts,.vue ./src" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@flaschengeist/api": "^1.0.0", | ||||
|     "@flaschengeist/types": "^1.0.0", | ||||
|     "@flaschengeist/api": "^1.1.0", | ||||
|     "@flaschengeist/types": "^1.2.0", | ||||
|     "@quasar/app-webpack": "^3.7.2", | ||||
|     "@typescript-eslint/eslint-plugin": "^5.8.0", | ||||
|     "@typescript-eslint/parser": "^5.8.0", | ||||
|  |  | |||
|  | @ -0,0 +1,64 @@ | |||
| <template> | ||||
|   <q-card class="col-12"> | ||||
|     <q-card-section class="fit row justify-start content-center items-center"> | ||||
|       <div class="col-12 text-center text-h6">{{ apiKey.name }}</div> | ||||
|       <q-btn | ||||
|         class="absolute-top-right q-ma-sm" | ||||
|         color="negative" | ||||
|         icon="mdi-delete" | ||||
|         round | ||||
|         @click="deleteKey" | ||||
|       /> | ||||
|     </q-card-section> | ||||
|     <q-card-section | ||||
|       v-if="apiKey.token" | ||||
|       class="fit row justify-start content-center items-center q-gutter-sm" | ||||
|     > | ||||
|       <q-input class="col" outlined label="API Key" :model-value="apiKey.token" /> | ||||
|       <div class="row justify-end content-end items-end"> | ||||
|         <q-btn color="primary" icon="mdi-content-copy" round @click="copyApiKey" /> | ||||
|       </div> | ||||
|       <q-banner class="fit bg-primary text-white" inline dense rounded> | ||||
|         ApiKey wird nur einmalig angezeigt. Bitte kopieren! | ||||
|       </q-banner> | ||||
|     </q-card-section> | ||||
|     <q-card-section class="fit row justify-start content-center items-center q-gutter-sm"> | ||||
|       <q-input | ||||
|         class="fit" | ||||
|         type="textarea" | ||||
|         outlined | ||||
|         label="Description" | ||||
|         readonly | ||||
|         :model-value="apiKey.description" | ||||
|       /> | ||||
|     </q-card-section> | ||||
|   </q-card> | ||||
| </template> | ||||
| <script lang="ts"> | ||||
| import { defineComponent, PropType } from 'vue'; | ||||
| export default defineComponent({ | ||||
|   name: 'ApiKey', | ||||
|   props: { | ||||
|     apiKey: { | ||||
|       type: Object as PropType<FG.ApiKey>, | ||||
|       required: true, | ||||
|     }, | ||||
|   }, | ||||
|   emits: { | ||||
|     delete: (apiKey: FG.ApiKey) => !!apiKey, | ||||
|   }, | ||||
|   setup(props, { emit }) { | ||||
|     async function copyApiKey() { | ||||
|       await navigator.clipboard.writeText(<string>props.apiKey.token); | ||||
|       console.log('copying api key', props.apiKey.token); | ||||
|     } | ||||
|     function deleteKey() { | ||||
|       emit('delete', props.apiKey); | ||||
|     } | ||||
|     return { | ||||
|       deleteKey, | ||||
|       copyApiKey, | ||||
|     }; | ||||
|   }, | ||||
| }); | ||||
| </script> | ||||
|  | @ -0,0 +1,42 @@ | |||
| <template> | ||||
|   <q-card> | ||||
|     <q-card-section class="fit row justify-start content-center items-center"> | ||||
|       <div class="col-12 text-center text-h6">API Key</div> | ||||
|     </q-card-section> | ||||
|     <q-card-section class="fit row justify-start content-center items-center q-gutter-sm"> | ||||
|       <q-input | ||||
|         v-model="name" | ||||
|         class="fit" | ||||
|         outlined | ||||
|         label="API Key Name" | ||||
|         :rules="[(val) => !!val || 'API Key is required']" | ||||
|       /> | ||||
|       <q-input v-model="description" class="fit" type="textarea" outlined label="Description" /> | ||||
|     </q-card-section> | ||||
|     <q-card-actions align="right"> | ||||
|       <q-btn color="secondary" label="Abbrechen" @click="$emit('close')" /> | ||||
|       <q-btn color="primary" label="Erstellen" @click="createApiKey" /> | ||||
|     </q-card-actions> | ||||
|   </q-card> | ||||
| </template> | ||||
| <script lang="ts"> | ||||
| import { defineComponent, ref } from 'vue'; | ||||
| import { useApiKeyStore } from '@flaschengeist/api'; | ||||
| export default defineComponent({ | ||||
|   name: 'ApiKeyForm', | ||||
|   emits: ['close'], | ||||
|   setup(_, { emit }) { | ||||
|     const apiKeyStore = useApiKeyStore(); | ||||
|     const name = ref(''); | ||||
|     const description = ref(''); | ||||
| 
 | ||||
|     async function createApiKey() { | ||||
|       await apiKeyStore.createApiKey({ id: -1, name: name.value, description: description.value }); | ||||
|       name.value = ''; | ||||
|       description.value = ''; | ||||
|       emit('close'); | ||||
|     } | ||||
|     return { name, description, createApiKey }; | ||||
|   }, | ||||
| }); | ||||
| </script> | ||||
|  | @ -16,7 +16,7 @@ | |||
| <script lang="ts"> | ||||
| import { computed, defineComponent, PropType, onBeforeMount, ref } from 'vue'; | ||||
| import { useUserStore } from '@flaschengeist/api'; | ||||
| import { DisplayNameMode } from '../models'; | ||||
| import { showName } from '../utils'; | ||||
| 
 | ||||
| export default defineComponent({ | ||||
|   name: 'UserSelector', | ||||
|  | @ -68,20 +68,6 @@ export default defineComponent({ | |||
|       get: () => props.modelValue, | ||||
|       set: (value: FG.User | undefined) => (value ? emit('update:modelValue', value) : undefined), | ||||
|     }); | ||||
|     function showName(user: FG.User) { | ||||
|       switch (userStore.userSettings.display_name) { | ||||
|         case DisplayNameMode.DISPLAYNAME: | ||||
|           return user.display_name; | ||||
|         case DisplayNameMode.FIRSTNAME: | ||||
|           return user.firstname; | ||||
|         case DisplayNameMode.LASTNAME: | ||||
|           return user.lastname; | ||||
|         case DisplayNameMode.FIRSTNAME_LASTNAME: | ||||
|           return `${user.firstname} ${user.lastname}`; | ||||
|         case DisplayNameMode.LASTNAME_FIRSTNAME: | ||||
|           return `${user.lastname}, ${user.firstname}`; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     return { | ||||
|       selected, | ||||
|  |  | |||
|  | @ -7,8 +7,8 @@ const plugin: FG_Plugin.Plugin = { | |||
|   id: 'users', | ||||
|   name: 'User', | ||||
|   innerRoutes: routes, | ||||
|   requiredModules: [['auth'], ['users'], ['roles']], | ||||
|   version: '0.0.1', | ||||
|   requiredModules: [['auth'], ['users', '2.2.0'], ['roles']], | ||||
|   version: '1.2.0', | ||||
|   widgets: [ | ||||
|     { | ||||
|       priority: 1, | ||||
|  | @ -29,3 +29,4 @@ const plugin: FG_Plugin.Plugin = { | |||
| 
 | ||||
| export default plugin; | ||||
| export { DisplayNameMode }; | ||||
| export * from './utils'; | ||||
|  |  | |||
|  | @ -17,30 +17,61 @@ | |||
|         v-model="sessions[index]" | ||||
|         @delete="removeSession(session)" | ||||
|       /> | ||||
|       <q-btn label="List Widgets" @click="listWidgets" /> | ||||
|       <div class="col-12 text-left text-h6">API Keys</div> | ||||
|       <api-key | ||||
|         v-for="apiKey in apiKeys" | ||||
|         :key="apiKey.id" | ||||
|         :api-key="apiKey" | ||||
|         @delete="deleteApiKey" | ||||
|       /> | ||||
|       <div class="fit row justify-end content-end items-end"> | ||||
|         <q-btn | ||||
|           @click="showApiKeyForm = true" | ||||
|           class="q-mb-md" | ||||
|           color="primary" | ||||
|           icon="mdi-plus" | ||||
|           round | ||||
|         /> | ||||
|       </div> | ||||
|     </q-page> | ||||
|     <q-dialog v-model="showApiKeyForm" persistent> | ||||
|       <api-key-form @close="showApiKeyForm = false" /> | ||||
|     </q-dialog> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import { useMainStore, useUserStore, useSessionStore, hasPermissions } from '@flaschengeist/api'; | ||||
| import { | ||||
|   useMainStore, | ||||
|   useUserStore, | ||||
|   useSessionStore, | ||||
|   hasPermissions, | ||||
|   useApiKeyStore, | ||||
| } from '@flaschengeist/api'; | ||||
| import MainUserSettings from '../components/settings/MainUserSettings.vue'; | ||||
| import { defineComponent, onBeforeMount, ref, computed, inject } from 'vue'; | ||||
| import UserSession from '../components/settings/UserSession.vue'; | ||||
| import { FG_Plugin } from '@flaschengeist/types'; | ||||
| import { Notify } from 'quasar'; | ||||
| import ApiKeyForm from '../components/ApiKeyForm.vue'; | ||||
| import ApiKey from '../components/ApiKey.vue'; | ||||
| 
 | ||||
| export default defineComponent({ | ||||
|   name: 'UserSettings', | ||||
|   components: { MainUserSettings, UserSession }, | ||||
|   components: { MainUserSettings, UserSession, ApiKeyForm, ApiKey }, | ||||
|   setup() { | ||||
|     const mainStore = useMainStore(); | ||||
|     const sessionStore = useSessionStore(); | ||||
|     const userStore = useUserStore(); | ||||
|     const apiKeyStore = useApiKeyStore(); | ||||
| 
 | ||||
|     onBeforeMount(() => sessionStore.getSessions().then((s) => (sessions.value = s))); | ||||
|     onBeforeMount(() => { | ||||
|       sessionStore.getSessions().then((s) => (sessions.value = s)); | ||||
|       apiKeyStore.getApiKeys(); | ||||
|     }); | ||||
|     const currentUser = ref(mainStore.currentUser); | ||||
|     const sessions = ref([] as FG.Session[]); | ||||
|     const apiKeys = computed(() => apiKeyStore.apiKeys); | ||||
| 
 | ||||
|     async function updateUser(value: FG.User) { | ||||
|       await userStore.updateUser(value); | ||||
|  | @ -68,6 +99,13 @@ export default defineComponent({ | |||
|       console.log(widgets); | ||||
|     } | ||||
| 
 | ||||
|     const showApiKeyForm = ref(false); | ||||
| 
 | ||||
|     async function deleteApiKey(apiKey: FG.ApiKey) { | ||||
|       console.log('deleteApiKey', apiKey); | ||||
|       await apiKeyStore.deleteApiKey(apiKey.id); | ||||
|     } | ||||
| 
 | ||||
|     return { | ||||
|       currentUser, | ||||
|       sessions, | ||||
|  | @ -75,6 +113,9 @@ export default defineComponent({ | |||
|       removeSession, | ||||
|       widgets, | ||||
|       listWidgets, | ||||
|       showApiKeyForm, | ||||
|       apiKeys, | ||||
|       deleteApiKey, | ||||
|     }; | ||||
|   }, | ||||
| }); | ||||
|  |  | |||
|  | @ -0,0 +1,18 @@ | |||
| import { DisplayNameMode } from '../models'; | ||||
| import { useUserStore } from '@flaschengeist/api'; | ||||
| 
 | ||||
| export function showName(user: FG.User) { | ||||
|   const userStore = useUserStore(); | ||||
|   switch (userStore.userSettings.display_name) { | ||||
|     case DisplayNameMode.DISPLAYNAME: | ||||
|       return user.display_name; | ||||
|     case DisplayNameMode.FIRSTNAME: | ||||
|       return user.firstname; | ||||
|     case DisplayNameMode.LASTNAME: | ||||
|       return user.lastname; | ||||
|     case DisplayNameMode.FIRSTNAME_LASTNAME: | ||||
|       return `${user.firstname} ${user.lastname}`; | ||||
|     case DisplayNameMode.LASTNAME_FIRSTNAME: | ||||
|       return `${user.lastname}, ${user.firstname}`; | ||||
|   } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue