refactor: response structure of Extension list API

see halo-dev/halo#2244
pull/588/head
Ryan Wang 2022-07-14 16:48:54 +08:00
parent b866860177
commit 9569b43dab
16 changed files with 142 additions and 90 deletions

View File

@ -35,6 +35,7 @@
"@halo-dev/admin-shared": "workspace:*", "@halo-dev/admin-shared": "workspace:*",
"@halo-dev/api-client": "^0.0.0", "@halo-dev/api-client": "^0.0.0",
"@halo-dev/components": "workspace:*", "@halo-dev/components": "workspace:*",
"@vueuse/components": "^8.9.2",
"@vueuse/core": "^8.9.2", "@vueuse/core": "^8.9.2",
"axios": "^0.27.2", "axios": "^0.27.2",
"filepond": "^4.30.4", "filepond": "^4.30.4",

View File

@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useOffsetPagination } from "@vueuse/core"; import { UseOffsetPagination } from "@vueuse/components";
import { IconArrowLeft, IconArrowRight } from "../../icons/icons"; import { IconArrowLeft, IconArrowRight } from "../../icons/icons";
import { defineProps } from "vue"; import { defineProps, ref, toRefs, watch } from "vue";
const props = defineProps({ const props = defineProps({
page: { page: {
@ -18,6 +18,10 @@ const props = defineProps({
}, },
}); });
const { page, size, total } = toRefs(props);
const key = ref(Math.random());
const emit = defineEmits(["update:page", "update:size", "change"]); const emit = defineEmits(["update:page", "update:size", "change"]);
const onPageChange = ({ const onPageChange = ({
@ -27,73 +31,81 @@ const onPageChange = ({
currentPage: number; currentPage: number;
currentPageSize: number; currentPageSize: number;
}) => { }) => {
emit("update:size", props.size);
emit("update:page", props.page);
emit("change", { emit("change", {
page: currentPage, page: currentPage,
size: currentPageSize, size: currentPageSize,
}); });
}; };
const { currentPage, pageCount, prev, next } = useOffsetPagination({ watch(
total: props.total, () => total?.value,
page: props.page, () => {
pageSize: props.size, key.value = Math.random();
onPageChange: onPageChange, }
onPageSizeChange: onPageChange, );
});
</script> </script>
<template> <template>
<div class="bg-white flex items-center justify-between"> <UseOffsetPagination
<div class="flex-1 flex justify-between sm:hidden items-center"> :key="key"
<span v-slot="{ currentPage, next, prev, pageCount }"
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer" :page="page"
@click="prev" :pageSize="size"
> :total="total"
<IconArrowLeft /> @page-change="onPageChange"
</span> @page-size-change="onPageChange"
<span class="text-sm text-gray-500"> >
{{ currentPage }} / {{ pageCount }} <div class="bg-white flex items-center justify-between">
</span> <div class="flex-1 flex justify-between sm:hidden items-center">
<span
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer"
@click="next"
>
<IconArrowRight />
</span>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center">
<nav
aria-label="Pagination"
class="relative z-0 inline-flex rounded-base shadow-sm -space-x-px"
>
<span <span
class="relative inline-flex items-center px-2 py-2 rounded-l-[4px] border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer" class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer"
@click="prev" @click="prev"
> >
<IconArrowLeft /> <IconArrowLeft />
</span> </span>
<span <span class="text-sm text-gray-500">
v-for="i in pageCount" {{ currentPage }} / {{ pageCount }}
:key="i"
:class="{
'z-10 bg-primary/1 border-primary text-primary': i === currentPage,
'bg-white border-gray-300 text-gray-500 hover:bg-gray-50':
i !== currentPage,
}"
aria-current="page"
class="relative inline-flex items-center px-4 py-2 border text-sm font-medium cursor-pointer select-none"
@click="currentPage = i"
>
{{ i }}
</span> </span>
<span <span
class="relative inline-flex items-center px-2 py-2 rounded-r-[4px] border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer" class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer"
@click="next" @click="next"
> >
<IconArrowRight /> <IconArrowRight />
</span> </span>
</nav> </div>
<div class="hidden sm:flex-1 sm:flex sm:items-center">
<nav
aria-label="Pagination"
class="relative z-0 inline-flex rounded-base shadow-sm -space-x-px"
>
<span
class="relative inline-flex items-center px-2 py-2 rounded-l-[4px] border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer"
@click="prev"
>
<IconArrowLeft />
</span>
<span
v-for="i in pageCount"
:key="i"
:class="{
'z-10 bg-primary/1 border-primary text-primary':
i === currentPage,
'bg-white border-gray-300 text-gray-500 hover:bg-gray-50':
i !== currentPage,
}"
aria-current="page"
class="relative inline-flex items-center px-4 py-2 border text-sm font-medium cursor-pointer select-none"
@click="currentPage.value = i"
>
{{ i }}
</span>
<span
class="relative inline-flex items-center px-2 py-2 rounded-r-[4px] border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer"
@click="next"
>
<IconArrowRight />
</span>
</nav>
</div>
</div> </div>
</div> </UseOffsetPagination>
</template> </template>

View File

@ -30,6 +30,7 @@ importers:
'@vue/eslint-config-typescript': ^11.0.0 '@vue/eslint-config-typescript': ^11.0.0
'@vue/test-utils': ^2.0.2 '@vue/test-utils': ^2.0.2
'@vue/tsconfig': ^0.1.3 '@vue/tsconfig': ^0.1.3
'@vueuse/components': ^8.9.2
'@vueuse/core': ^8.9.2 '@vueuse/core': ^8.9.2
autoprefixer: ^10.4.7 autoprefixer: ^10.4.7
axios: ^0.27.2 axios: ^0.27.2
@ -79,6 +80,7 @@ importers:
'@halo-dev/admin-shared': link:packages/shared '@halo-dev/admin-shared': link:packages/shared
'@halo-dev/api-client': 0.0.0 '@halo-dev/api-client': 0.0.0
'@halo-dev/components': link:packages/components '@halo-dev/components': link:packages/components
'@vueuse/components': 8.9.2_vue@3.2.37
'@vueuse/core': 8.9.2_vue@3.2.37 '@vueuse/core': 8.9.2_vue@3.2.37
axios: 0.27.2 axios: 0.27.2
filepond: 4.30.4 filepond: 4.30.4
@ -2874,6 +2876,17 @@ packages:
'@types/node': 17.0.45 '@types/node': 17.0.45
dev: true dev: true
/@vueuse/components/8.9.2_vue@3.2.37:
resolution: {integrity: sha512-7K39dgpSdMJgotCGCaa3W7q/9AEZ2jitG+mBWH0TK+HSqLeYd5syHQKKK61raWP/qImu/mrwcsqeKtbFunU1FA==}
dependencies:
'@vueuse/core': 8.9.2_vue@3.2.37
'@vueuse/shared': 8.9.2_vue@3.2.37
vue-demi: 0.12.1_vue@3.2.37
transitivePeerDependencies:
- '@vue/composition-api'
- vue
dev: false
/@vueuse/core/8.9.2_vue@3.2.37: /@vueuse/core/8.9.2_vue@3.2.37:
resolution: {integrity: sha512-dE3/JgwqIHmmtmRBdZAnq87rZCSFbYVps2t3gWy9Jv/+Qp6sHSSKuPFtwguJVZ2OnaGnB/AMRmx4CuFRxFin3A==} resolution: {integrity: sha512-dE3/JgwqIHmmtmRBdZAnq87rZCSFbYVps2t3gWy9Jv/+Qp6sHSSKuPFtwguJVZ2OnaGnB/AMRmx4CuFRxFin3A==}
peerDependencies: peerDependencies:

View File

@ -97,11 +97,11 @@ function loadStyle(href: string) {
} }
async function loadPluginModules() { async function loadPluginModules() {
const response = const { data } =
await apiClient.extension.plugin.listpluginHaloRunV1alpha1Plugin(); await apiClient.extension.plugin.listpluginHaloRunV1alpha1Plugin();
// Get all started plugins // Get all started plugins
const plugins = response.data.filter( const plugins = data.items.filter(
(plugin) => plugin.status?.phase === "STARTED" && plugin.spec.enabled (plugin) => plugin.status?.phase === "STARTED" && plugin.spec.enabled
); );
@ -138,8 +138,13 @@ async function loadPluginModules() {
} }
async function loadCurrentUser() { async function loadCurrentUser() {
const response = await apiClient.user.getCurrentUserDetail(); const { data: user } = await apiClient.user.getCurrentUserDetail();
app.provide<User>("currentUser", response.data); app.provide<User>("currentUser", user);
const { data: permissions } = await apiClient.user.getPermissions(
"ac7cdce1-acf2-4e27-a422-c16d6f47cfa2"
);
app.provide("permissions", permissions);
} }
(async function () { (async function () {

View File

@ -82,7 +82,7 @@ const attachments = Array.from(new Array(50), (_, index) => index).map(
const handleFetchUsers = async () => { const handleFetchUsers = async () => {
try { try {
const { data } = await apiClient.extension.user.listv1alpha1User(); const { data } = await apiClient.extension.user.listv1alpha1User();
users.value = data; users.value = data.items;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View File

@ -53,7 +53,7 @@ useExtensionPointsState("PAGES", pagesPublicState);
const handleFetchUsers = async () => { const handleFetchUsers = async () => {
try { try {
const { data } = await apiClient.extension.user.listv1alpha1User(); const { data } = await apiClient.extension.user.listv1alpha1User();
users.value = data; users.value = data.items;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View File

@ -44,7 +44,7 @@ const checkedCount = computed(() => {
const handleFetchUsers = async () => { const handleFetchUsers = async () => {
try { try {
const { data } = await apiClient.extension.user.listv1alpha1User(); const { data } = await apiClient.extension.user.listv1alpha1User();
users.value = data; users.value = data.items;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View File

@ -9,7 +9,7 @@ const users = ref<User[]>([]);
const handleFetchUsers = async () => { const handleFetchUsers = async () => {
try { try {
const { data } = await apiClient.extension.user.listv1alpha1User(); const { data } = await apiClient.extension.user.listv1alpha1User();
users.value = data; users.value = data.items;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View File

@ -63,6 +63,9 @@ const handleFetchPlugin = async () => {
}; };
const handleFetchSettings = async () => { const handleFetchSettings = async () => {
if (!plugin.value.spec.settingName) {
return;
}
try { try {
const response = await apiClient.extension.setting.getv1alpha1Setting( const response = await apiClient.extension.setting.getv1alpha1Setting(
plugin.value.spec.settingName as string plugin.value.spec.settingName as string
@ -92,6 +95,9 @@ const handleFetchSettings = async () => {
}; };
const handleFetchConfigMap = async () => { const handleFetchConfigMap = async () => {
if (!plugin.value.spec.configMapName) {
return;
}
try { try {
const response = await apiClient.extension.configMap.getv1alpha1ConfigMap( const response = await apiClient.extension.configMap.getv1alpha1ConfigMap(
plugin.value.spec.configMapName as string plugin.value.spec.configMapName as string

View File

@ -37,9 +37,9 @@ const isStarted = (plugin: Plugin) => {
const handleFetchPlugins = async () => { const handleFetchPlugins = async () => {
try { try {
const response = const {data} =
await apiClient.extension.plugin.listpluginHaloRunV1alpha1Plugin(); await apiClient.extension.plugin.listpluginHaloRunV1alpha1Plugin();
plugins.value = response.data; plugins.value = data.items;
} catch (e) { } catch (e) {
console.error("Fail to fetch plugins", e); console.error("Fail to fetch plugins", e);
} }

View File

@ -91,7 +91,7 @@ const handleFetchRole = async () => {
const handleFetchRoles = async () => { const handleFetchRoles = async () => {
try { try {
const { data } = await apiClient.extension.role.listv1alpha1Role(); const { data } = await apiClient.extension.role.listv1alpha1Role();
roles.value = data; roles.value = data.items;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
@ -100,7 +100,7 @@ const handleFetchRoles = async () => {
const handleFetchUsers = async () => { const handleFetchUsers = async () => {
try { try {
const { data } = await apiClient.extension.user.listv1alpha1User(); const { data } = await apiClient.extension.user.listv1alpha1User();
users.value = data; users.value = data.items;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View File

@ -32,7 +32,7 @@ const router = useRouter();
const handleFetchRoles = async () => { const handleFetchRoles = async () => {
try { try {
const { data } = await apiClient.extension.role.listv1alpha1Role(); const { data } = await apiClient.extension.role.listv1alpha1Role();
roles.value = data; roles.value = data.items;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View File

@ -72,7 +72,7 @@ const roleTemplateGroups = computed<RoleTemplateGroup[]>(() => {
const handleFetchRoles = async () => { const handleFetchRoles = async () => {
try { try {
const { data } = await apiClient.extension.role.listv1alpha1Role(); const { data } = await apiClient.extension.role.listv1alpha1Role();
roles.value = data; roles.value = data.items;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View File

@ -20,9 +20,9 @@ const personalAccessTokens = ref<PersonalAccessToken[]>([]);
const handleFetchPersonalAccessTokens = async () => { const handleFetchPersonalAccessTokens = async () => {
try { try {
const response = const { data } =
await apiClient.extension.personalAccessToken.listv1alpha1PersonalAccessToken(); await apiClient.extension.personalAccessToken.listv1alpha1PersonalAccessToken();
personalAccessTokens.value = response.data; personalAccessTokens.value = data.items;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View File

@ -16,30 +16,46 @@ import UserCreationModal from "./components/UserCreationModal.vue";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { apiClient } from "@halo-dev/admin-shared"; import { apiClient } from "@halo-dev/admin-shared";
import type { User } from "@halo-dev/api-client"; import type { User } from "@halo-dev/api-client";
import type { UserList } from "@halo-dev/api-client";
const checkAll = ref(false); const checkAll = ref(false);
const creationModal = ref<boolean>(false); const creationModal = ref<boolean>(false);
const users = ref<User[]>([]); const users = ref<UserList>({
const selectedUser = ref<User | null>(null);
const pagination = ref<{
page: number;
size: number;
total: number;
}>({
page: 1, page: 1,
size: 10, size: 5,
total: 100, total: 0,
items: [],
first: true,
last: false,
hasNext: false,
hasPrevious: false,
}); });
const selectedUser = ref<User | null>(null);
const handleFetchUsers = async () => { const handleFetchUsers = async () => {
try { try {
const { data } = await apiClient.extension.user.listv1alpha1User(); const { data } = await apiClient.extension.user.listv1alpha1User(
users.value.page,
users.value.size
);
users.value = data; users.value = data;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
}; };
const handlePaginationChange = async ({
page,
size,
}: {
page: number;
size: number;
}) => {
users.value.page = page;
users.value.size = size;
await handleFetchUsers();
};
const handleOpenCreateModal = (user: User) => { const handleOpenCreateModal = (user: User) => {
selectedUser.value = user; selectedUser.value = user;
creationModal.value = true; creationModal.value = true;
@ -206,7 +222,7 @@ onMounted(() => {
</div> </div>
</template> </template>
<ul class="box-border h-full w-full divide-y divide-gray-100" role="list"> <ul class="box-border h-full w-full divide-y divide-gray-100" role="list">
<li v-for="(user, index) in users" :key="index"> <li v-for="(user, index) in users.items" :key="index">
<div <div
:class="{ :class="{
'bg-gray-100': checkAll, 'bg-gray-100': checkAll,
@ -286,9 +302,10 @@ onMounted(() => {
<template #footer> <template #footer>
<div class="bg-white sm:flex sm:items-center sm:justify-end"> <div class="bg-white sm:flex sm:items-center sm:justify-end">
<VPagination <VPagination
v-model:page="pagination.page" :page="users.page"
v-model:size="pagination.size" :size="users.size"
:total="pagination.total" :total="users.total"
@change="handlePaginationChange"
/> />
</div> </div>
</template> </template>

View File

@ -71,7 +71,7 @@ watch(props, (newVal) => {
const handleFetchRoles = async () => { const handleFetchRoles = async () => {
try { try {
const { data } = await apiClient.extension.role.listv1alpha1Role(); const { data } = await apiClient.extension.role.listv1alpha1Role();
roles.value = data; roles.value = data.items;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
@ -102,14 +102,12 @@ const handleCreateUser = async () => {
user = response.data; user = response.data;
} }
// if (selectedRole.value) { if (selectedRole.value) {
// await apiClient.user.( await apiClient.user.grantPermission(user.metadata.name, {
// `/apis/api.halo.run/v1alpha1/users/${user.metadata.name}/permissions`, // @ts-ignore
// { roles: [selectedRole.value],
// roles: [selectedRole.value], });
// } }
// );
// }
handleVisibleChange(false); handleVisibleChange(false);
} catch (e) { } catch (e) {