refactor: response structure of Extension list API

see halo-dev/halo#2244
pull/3445/head
Ryan Wang 2022-07-14 16:48:54 +08:00
parent 878129d072
commit 16cf4d70a1
16 changed files with 142 additions and 90 deletions

View File

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

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { useOffsetPagination } from "@vueuse/core";
import { UseOffsetPagination } from "@vueuse/components";
import { IconArrowLeft, IconArrowRight } from "../../icons/icons";
import { defineProps } from "vue";
import { defineProps, ref, toRefs, watch } from "vue";
const props = defineProps({
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 onPageChange = ({
@ -27,73 +31,81 @@ const onPageChange = ({
currentPage: number;
currentPageSize: number;
}) => {
emit("update:size", props.size);
emit("update:page", props.page);
emit("change", {
page: currentPage,
size: currentPageSize,
});
};
const { currentPage, pageCount, prev, next } = useOffsetPagination({
total: props.total,
page: props.page,
pageSize: props.size,
onPageChange: onPageChange,
onPageSizeChange: onPageChange,
});
watch(
() => total?.value,
() => {
key.value = Math.random();
}
);
</script>
<template>
<div class="bg-white flex items-center justify-between">
<div class="flex-1 flex justify-between sm:hidden items-center">
<span
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"
>
<IconArrowLeft />
</span>
<span class="text-sm text-gray-500">
{{ currentPage }} / {{ pageCount }}
</span>
<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"
>
<UseOffsetPagination
:key="key"
v-slot="{ currentPage, next, prev, pageCount }"
:page="page"
:pageSize="size"
:total="total"
@page-change="onPageChange"
@page-size-change="onPageChange"
>
<div class="bg-white flex items-center justify-between">
<div class="flex-1 flex justify-between sm:hidden items-center">
<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"
>
<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 = i"
>
{{ i }}
<span class="text-sm text-gray-500">
{{ currentPage }} / {{ pageCount }}
</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"
>
<IconArrowRight />
</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>
</UseOffsetPagination>
</template>

View File

@ -30,6 +30,7 @@ importers:
'@vue/eslint-config-typescript': ^11.0.0
'@vue/test-utils': ^2.0.2
'@vue/tsconfig': ^0.1.3
'@vueuse/components': ^8.9.2
'@vueuse/core': ^8.9.2
autoprefixer: ^10.4.7
axios: ^0.27.2
@ -79,6 +80,7 @@ importers:
'@halo-dev/admin-shared': link:packages/shared
'@halo-dev/api-client': 0.0.0
'@halo-dev/components': link:packages/components
'@vueuse/components': 8.9.2_vue@3.2.37
'@vueuse/core': 8.9.2_vue@3.2.37
axios: 0.27.2
filepond: 4.30.4
@ -2874,6 +2876,17 @@ packages:
'@types/node': 17.0.45
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:
resolution: {integrity: sha512-dE3/JgwqIHmmtmRBdZAnq87rZCSFbYVps2t3gWy9Jv/+Qp6sHSSKuPFtwguJVZ2OnaGnB/AMRmx4CuFRxFin3A==}
peerDependencies:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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