implement user admin page

This commit is contained in:
MiniDigger 2022-03-21 18:11:08 +01:00
parent 870e16ca3a
commit 3e57dc4e3d
5 changed files with 135 additions and 14 deletions

View File

@ -265,8 +265,8 @@ once QA has passed, the checkboxes can be removed and the page can be ~~striked
- [ ] qa
- user (empty)
- [user]
- [ ] fetch
- [ ] layout
- [ ] functionality
- [ ] design
- [x] fetch
- [x] layout
- [x] functionality
- [x] design
- [ ] qa

View File

@ -6,7 +6,7 @@ import Table from "~/components/design/Table.vue";
export interface Header {
name: string;
title: string;
sortable: boolean;
sortable?: boolean;
}
const props = defineProps({

View File

@ -1,16 +1,23 @@
<script setup lang="ts">
const props = defineProps({
label: {
type: String,
required: true,
},
import { computed } from "vue";
const emit = defineEmits<{
(e: "update:modelValue", value: boolean): void;
}>();
const value = computed({
get: () => props.modelValue,
set: (v) => emit("update:modelValue", v),
});
const props = defineProps<{
modelValue: boolean;
label?: string;
}>();
</script>
<template>
<label class="group relative cursor-pointer pl-30px customCheckboxContainer">
{{ props.label }}
<input type="checkbox" class="hidden" />
<template v-if="props.label">{{ props.label }}</template>
<input v-model="value" type="checkbox" class="hidden" v-bind="$attrs" />
<span
class="absolute top-5px left-0 h-15px w-15px rounded bg-gray-300"
after="absolute hidden content-DEFAULT top-1px left-5px border-solid w-6px h-12px border-r-3px border-b-3px border-white"

View File

@ -1,5 +1,120 @@
<script lang="ts" setup>
import PageTitle from "~/components/design/PageTitle.vue";
import { useI18n } from "vue-i18n";
import Link from "~/components/design/Link.vue";
import Card from "~/components/design/Card.vue";
import { useApi, useInternalApi } from "~/composables/useApi";
import { PaginatedResult, Project } from "hangar-api";
import { useRoute } from "vue-router";
import { handleRequestError } from "~/composables/useErrorHandling";
import { useContext } from "vite-ssr/vue";
import { RoleTable } from "hangar-internal";
import { computed } from "vue";
import SortableTable, { Header } from "~/components/SortableTable.vue";
import InputCheckbox from "~/components/ui/InputCheckbox.vue";
const i18n = useI18n();
const route = useRoute();
const ctx = useContext();
const projects = await useApi<PaginatedResult<Project>>("projects", false, "get", {
owner: route.params.user,
}).catch((e) => handleRequestError(e, ctx, i18n));
const orgs = await useInternalApi<{ [key: string]: RoleTable }>(`organizations/${route.params.user}/userOrganizations`, false).catch((e) =>
handleRequestError(e, ctx, i18n)
);
const projectsConfig = [
{ title: i18n.t("userAdmin.project"), name: "name" },
{ title: i18n.t("userAdmin.owner"), name: "owner" },
{ title: i18n.t("userAdmin.role"), name: "role" },
{ title: i18n.t("userAdmin.accepted"), name: "accepted" },
] as Header[];
const orgConfig = [
{ title: i18n.t("userAdmin.organization"), name: "name" },
{ title: i18n.t("userAdmin.owner"), name: "owner" },
{ title: i18n.t("userAdmin.role"), name: "role" },
{ title: i18n.t("userAdmin.accepted"), name: "accepted" },
] as Header[];
const orgList = computed(() => {
return orgs
? Object.keys(orgs).map((name) => {
return { name };
})
: [];
});
</script>
<template>
<h1>user admin</h1>
<PageTitle
>{{ i18n.t("userAdmin.title") }}
<Link :to="'/' + $route.params.user">
{{ $route.params.user }}
</Link>
</PageTitle>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card md="col-start-1">
<template #header>{{ i18n.t("userAdmin.organizations") }}</template>
<SortableTable :items="orgList" :headers="orgConfig">
<template #item_name="{ item }">
<Link :to="'/' + item.name">
{{ item.name }}
</Link>
</template>
<template #item_owner="{ item }">
<!-- todo owner -->
<Link :to="'/' + item.name.owner">
{{ item.name.owner }}
</Link>
</template>
<template #item_role="{ item }">
{{ orgs[item.name].role.title }}
</template>
<template #item_accepted="{ item }">
<InputCheckbox v-model="orgs[item.name].accepted" :disabled="true" />
</template>
</SortableTable>
</Card>
<Card md="col-start-1">
<template #header>{{ i18n.t("userAdmin.projects") }}</template>
<SortableTable :items="projects.result" :headers="projectsConfig">
<template #item_name="{ item }">
<Link :to="'/' + item.namespace.owner + '/' + item.name">
{{ item.name }}
</Link>
</template>
<template #item_owner="{ item }">
<Link :to="'/' + item.namespace.owner">
{{ item.namespace.owner }}
</Link>
</template>
<template #item_role="{ item }">
<!-- todo role -->
Role {{ item.name }}
</template>
<template #item_accepted="{ item }">
<InputCheckbox :model-value="item.visibility === 'public'" :disabled="true" />
</template>
</SortableTable>
</Card>
<Card md="col-start-2 row-start-1 row-end-2">
<template #header>{{ i18n.t("userAdmin.sidebar") }}</template>
<ul>
<!-- todo links -->
<li>
<Link href="">{{ i18n.t("userAdmin.hangarAuth") }}</Link>
</li>
<li>
<Link href="">{{ i18n.t("userAdmin.forum") }}</Link>
</li>
</ul>
</Card>
</div>
</template>
<route lang="yaml">

View File

@ -5,7 +5,6 @@
declare module "vue" {
export interface GlobalComponents {
IconMdiClipboardOutline: typeof import("~icons/mdi/clipboard-outline")["default"];
IconMdiClose: typeof import("~icons/mdi/close")["default"];
IconMdiCloseCircle: typeof import("~icons/mdi/close-circle")["default"];
IconMdiKeyOutline: typeof import("~icons/mdi/key-outline")["default"];
IconMdiMenu: typeof import("~icons/mdi/menu")["default"];