mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-03-13 15:39:18 +08:00
api key page layout
This commit is contained in:
parent
ecae457660
commit
9576882ac8
82
frontend/components/layouts/UserProfile.vue
Normal file
82
frontend/components/layouts/UserProfile.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-row>
|
||||
<v-col cols="1">
|
||||
<UserAvatar :username="user.name" :avatar-url="$util.avatarUrl(user.name)" :clazz="avatarClazz"></UserAvatar>
|
||||
</v-col>
|
||||
<v-col cols="auto">
|
||||
<h1 class="d-inline">{{ user.name }}</h1>
|
||||
<v-list dense flat class="d-inline-flex">
|
||||
<v-list-item v-for="btn in buttons" :key="btn.name">
|
||||
<v-list-item-content>
|
||||
<v-btn icon :to="btn.url">
|
||||
<v-icon>{{ btn.icon }}</v-icon>
|
||||
</v-btn>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<div>
|
||||
<v-subheader>
|
||||
<template v-if="user.tagline">{{ user.tagline }}</template>
|
||||
<!-- TODO tagline edit -->
|
||||
<!--<template v-else-if="u.isCurrent() || canEditOrgSettings(u, o, so)">{{ $t('author.addTagline') }}</template>-->
|
||||
<v-btn icon>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-btn>
|
||||
</v-subheader>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-spacer />
|
||||
<v-col cols="2">
|
||||
<v-subheader>{{ $t('author.numProjects', [user.projectCount]) }}</v-subheader>
|
||||
<v-subheader>{{ $t('author.memberSince', [$util.prettyDate(user.joinDate)]) }}</v-subheader>
|
||||
<a :href="$util.forumUrl(user.name)">{{ $t('author.viewForums') }}<v-icon>mdi-open-in-new</v-icon></a>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-divider />
|
||||
<v-row>
|
||||
<slot></slot>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
import { Prop } from 'vue-property-decorator';
|
||||
import { HangarUser } from 'hangar-internal';
|
||||
import UserAvatar from '~/components/UserAvatar.vue';
|
||||
|
||||
interface Button {
|
||||
icon: String;
|
||||
action?: Function;
|
||||
url: String;
|
||||
name: String;
|
||||
}
|
||||
|
||||
@Component({
|
||||
components: { UserAvatar },
|
||||
})
|
||||
export default class UserProfile extends Vue {
|
||||
@Prop()
|
||||
user!: HangarUser;
|
||||
|
||||
get avatarClazz(): String {
|
||||
return 'user-avatar-md';
|
||||
// todo check org an add 'organization-avatar'
|
||||
}
|
||||
|
||||
get buttons(): Button[] {
|
||||
const buttons = [] as Button[];
|
||||
// TODO user admin
|
||||
buttons.push({ icon: 'mdi-cog', url: '', name: 'Settings' });
|
||||
buttons.push({ icon: 'mdi-lock-open-outline', url: '', name: 'Lock Account' });
|
||||
buttons.push({ icon: 'mdi-lock-outline', url: '', name: 'Unlock Account' });
|
||||
buttons.push({ icon: 'mdi-key', url: '/' + this.user.name + '/settings/api-keys', name: 'API Keys' });
|
||||
buttons.push({ icon: 'mdi-calendar', url: '', name: 'Activity' });
|
||||
buttons.push({ icon: 'mdi-wrench', url: '', name: 'User Admin' });
|
||||
return buttons;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
@ -471,6 +471,18 @@ const msgs: LocaleMessageObject = {
|
||||
lastUpdate: 'Last Update: {0}',
|
||||
},
|
||||
},
|
||||
apiKeys: {
|
||||
createNew: 'Create new key',
|
||||
existing: 'Existing keys',
|
||||
name: 'Name',
|
||||
key: 'Key',
|
||||
keyIdentifier: 'Key Identifier',
|
||||
permissions: 'Permissions',
|
||||
delete: 'Delete',
|
||||
deleteKey: 'Delete Key',
|
||||
createKey: 'Create key',
|
||||
noKeys: 'There are no api keys yet. You can create one on the right side',
|
||||
},
|
||||
message: 'Good morning!',
|
||||
};
|
||||
|
||||
|
@ -1,59 +1,23 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-row>
|
||||
<v-col cols="1">
|
||||
<UserAvatar :username="user.name" :avatar-url="$util.avatarUrl(user.name)" :clazz="avatarClazz"></UserAvatar>
|
||||
</v-col>
|
||||
<v-col cols="auto">
|
||||
<h1 class="d-inline">{{ user.name }}</h1>
|
||||
<v-list dense flat class="d-inline-flex">
|
||||
<v-list-item v-for="btn in buttons" :key="btn.name">
|
||||
<v-list-item-content>
|
||||
<v-btn icon
|
||||
><v-icon>{{ btn.icon }}</v-icon></v-btn
|
||||
>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<div>
|
||||
<v-subheader>
|
||||
<template v-if="user.tagline">{{ user.tagline }}</template>
|
||||
<!-- TODO tagline edit -->
|
||||
<!--<template v-else-if="u.isCurrent() || canEditOrgSettings(u, o, so)">{{ $t('author.addTagline') }}</template>-->
|
||||
<v-btn icon>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-btn>
|
||||
</v-subheader>
|
||||
</div>
|
||||
</v-col>
|
||||
<v-spacer />
|
||||
<v-col cols="2">
|
||||
<v-subheader>{{ $t('author.numProjects', [user.projectCount]) }}</v-subheader>
|
||||
<v-subheader>{{ $t('author.memberSince', [$util.prettyDate(user.joinDate)]) }}</v-subheader>
|
||||
<a :href="$util.forumUrl(user.name)">{{ $t('author.viewForums') }}<v-icon>mdi-open-in-new</v-icon></a>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-divider />
|
||||
<v-row>
|
||||
<v-col cols="12" md="8">
|
||||
<ProjectList :projects="projects" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-list dense>
|
||||
<v-subheader>{{ $t('author.orgs') }}</v-subheader>
|
||||
<!-- todo display orgs -->
|
||||
</v-list>
|
||||
<v-list dense>
|
||||
<v-subheader>{{ $t('author.stars') }}</v-subheader>
|
||||
<!-- todo display stars -->
|
||||
</v-list>
|
||||
<v-list dense>
|
||||
<v-subheader>{{ $t('author.watching') }}</v-subheader>
|
||||
<!-- todo watching -->
|
||||
</v-list>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
<UserProfile :user="user">
|
||||
<v-col cols="12" md="8">
|
||||
<ProjectList :projects="projects" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-list dense>
|
||||
<v-subheader>{{ $t('author.orgs') }}</v-subheader>
|
||||
<!-- todo display orgs -->
|
||||
</v-list>
|
||||
<v-list dense>
|
||||
<v-subheader>{{ $t('author.stars') }}</v-subheader>
|
||||
<!-- todo display stars -->
|
||||
</v-list>
|
||||
<v-list dense>
|
||||
<v-subheader>{{ $t('author.watching') }}</v-subheader>
|
||||
<!-- todo watching -->
|
||||
</v-list>
|
||||
</v-col>
|
||||
</UserProfile>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@ -63,16 +27,11 @@ import { Context } from '@nuxt/types';
|
||||
import { HangarUser } from 'hangar-internal';
|
||||
import UserAvatar from '~/components/UserAvatar.vue';
|
||||
import ProjectList from '~/components/projects/ProjectList.vue';
|
||||
|
||||
interface Button {
|
||||
icon: String;
|
||||
action?: Function;
|
||||
url: String;
|
||||
name: String;
|
||||
}
|
||||
import UserProfile from '~/components/layouts/UserProfile.vue';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
UserProfile,
|
||||
UserAvatar,
|
||||
ProjectList,
|
||||
},
|
||||
@ -88,23 +47,6 @@ export default class AuthorPage extends Vue {
|
||||
};
|
||||
}
|
||||
|
||||
get avatarClazz(): String {
|
||||
return 'user-avatar-md';
|
||||
// todo check org an add 'organization-avatar'
|
||||
}
|
||||
|
||||
get buttons(): Button[] {
|
||||
const buttons = [] as Button[];
|
||||
// TODO user admin
|
||||
buttons.push({ icon: 'mdi-cog', url: '', name: 'Settings' });
|
||||
buttons.push({ icon: 'mdi-lock-open-outline', url: '', name: 'Lock Account' });
|
||||
buttons.push({ icon: 'mdi-lock-outline', url: '', name: 'Unlock Account' });
|
||||
buttons.push({ icon: 'mdi-key', url: '', name: 'API Keys' });
|
||||
buttons.push({ icon: 'mdi-calendar', url: '', name: 'Activity' });
|
||||
buttons.push({ icon: 'mdi-wrench', url: '', name: 'User Admin' });
|
||||
return buttons;
|
||||
}
|
||||
|
||||
async asyncData({ $api, route, $util }: Context) {
|
||||
const user = await $api.requestInternal<HangarUser>(`users/${route.params.author}`, false).catch($util.handlePageRequestError);
|
||||
const projects = await $api
|
||||
|
@ -1,13 +1,101 @@
|
||||
<template>
|
||||
<div>{{ $nuxt.$route.name }}</div>
|
||||
<UserProfile :user="user">
|
||||
<v-col cols="12" md="6">
|
||||
<h2>{{ $t('apiKeys.createNew') }}</h2>
|
||||
<v-row>
|
||||
<v-col v-for="perm in perms" :key="perm.frontendName" cols="6">
|
||||
<v-checkbox v-model="selectedPerms" :label="perm.frontendName" :value="perm.value"> </v-checkbox>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-text-field v-model="name" :label="$t('apiKeys.name')" type="text">
|
||||
<template #append-outer>
|
||||
<v-btn @click="create">{{ $t('apiKeys.createKey') }}</v-btn>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<h2>{{ $t('apiKeys.existing') }}</h2>
|
||||
<v-simple-table>
|
||||
<template #default>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-left">{{ $t('apiKeys.name') }}</th>
|
||||
<th class="text-left">{{ $t('apiKeys.key') }}</th>
|
||||
<th class="text-left">{{ $t('apiKeys.keyIdentifier') }}</th>
|
||||
<th class="text-left">{{ $t('apiKeys.permissions') }}</th>
|
||||
<th class="text-left">{{ $t('apiKeys.delete') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="key in apiKeys" :key="key.name">
|
||||
<td>{{ key.name }}</td>
|
||||
<td>{{ key.key }}</td>
|
||||
<td>{{ key.identifier }}</td>
|
||||
<td>{{ key.permissions }}</td>
|
||||
<td>
|
||||
<v-btn color="red" @click="deleteKey(key.key)">{{ $t('apiKeys.deleteKey') }}</v-btn>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</template>
|
||||
</v-simple-table>
|
||||
<v-alert v-if="apiKeys.length === 0" type="info">{{ $t('apiKeys.noKeys') }}</v-alert>
|
||||
</v-col>
|
||||
</UserProfile>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
import { HangarUser } from 'hangar-internal';
|
||||
import { Context } from '@nuxt/types';
|
||||
import { ApiKey, IPermission } from 'hangar-api';
|
||||
import UserProfile from '~/components/layouts/UserProfile.vue';
|
||||
import { RootState } from '~/store';
|
||||
import { NamedPermission } from '~/types/enums';
|
||||
|
||||
// TODO implement AuthorSettingsApiKeysPage (I think this should just be a modal in the user page - Jake)
|
||||
@Component
|
||||
export default class AuthorSettingsApiKeysPage extends Vue {}
|
||||
@Component({
|
||||
components: { UserProfile },
|
||||
})
|
||||
export default class AuthorSettingsApiKeysPage extends Vue {
|
||||
user!: HangarUser;
|
||||
|
||||
selectedPerms: NamedPermission[] = [];
|
||||
name: string = '';
|
||||
|
||||
// TODO load from server
|
||||
apiKeys: ApiKey[] = [];
|
||||
|
||||
get perms(): IPermission[] {
|
||||
return Array.from((this.$store.state as RootState).permissions.values());
|
||||
}
|
||||
|
||||
async asyncData({ $api, route, $util }: Context) {
|
||||
const user = await $api.requestInternal<HangarUser>(`users/${route.params.author}`, false).catch($util.handlePageRequestError);
|
||||
return { user };
|
||||
}
|
||||
|
||||
create() {
|
||||
// TODO send to server
|
||||
this.apiKeys.push({ key: 'blah', identifier: 'blub', permissions: this.selectedPerms, name: this.name, createdAt: new Date().toString() });
|
||||
this.name = '';
|
||||
this.selectedPerms = [];
|
||||
}
|
||||
|
||||
deleteKey(key: string) {
|
||||
// todo send to server
|
||||
this.apiKeys = this.apiKeys.filter((e) => e.key !== key);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.v-input--checkbox {
|
||||
margin-top: 0;
|
||||
}
|
||||
.v-messages {
|
||||
min-height: 0;
|
||||
}
|
||||
.col {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
8
frontend/types/api/users.d.ts
vendored
8
frontend/types/api/users.d.ts
vendored
@ -1,6 +1,6 @@
|
||||
declare module 'hangar-api' {
|
||||
import { Color, Model, Named } from 'hangar-api';
|
||||
import { RoleCategory } from '~/types/enums';
|
||||
import { NamedPermission, RoleCategory } from '~/types/enums';
|
||||
|
||||
interface Role {
|
||||
value: string;
|
||||
@ -17,4 +17,10 @@ declare module 'hangar-api' {
|
||||
roles: Role[];
|
||||
projectCount: number;
|
||||
}
|
||||
|
||||
interface ApiKey extends Model, Named {
|
||||
key: string;
|
||||
identifier: string;
|
||||
permissions: NamedPermission[];
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user