feat: api supports field filtering (halo-dev/console#591)

Signed-off-by: Ryan Wang <i@ryanc.cc>

<!--  Thanks for sending a pull request!  Here are some tips for you:
1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>。
1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>.
2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request.
3. 请确保你已经添加并运行了适当的测试。
3. Ensure you have added or ran the appropriate tests for your PR.
-->

#### What type of PR is this?

/kind feature
/milestone 2.0

<!--
添加其中一个类别:
Add one of the following kinds:

/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind optimization

适当添加其中一个或多个类别(可选):
Optionally add one or more of the following kinds if applicable:

/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->

#### What this PR does / why we need it:

适配 https://github.com/halo-dev/halo/pull/2279

接口支持通过参数筛选数据。

#### Which issue(s) this PR fixes:

<!--
PR 合并时自动关闭 issue。
Automatically closes linked issue when PR is merged.

用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)`
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
None

#### Screenshots:

<!--
如果此 PR 有 UI 的改动,最好截图说明这个 PR 的改动。
If there are UI changes to this PR, it is best to take a screenshot to illustrate the changes to this PR.

eg.

Before:

![screenshot-before](https://user-images.githubusercontent.com/screenshot.png)

After:

![screenshot-after](https://user-images.githubusercontent.com/screenshot.png)
-->

None

#### Special notes for your reviewer:

/hold until https://github.com/halo-dev/halo/pull/2279 merge

#### Does this PR introduce a user-facing change?

<!--
如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。
否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change),
Release Note 需要以 `action required` 开头。
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->

```release-note
None
```
pull/3445/head
Ryan Wang 2022-07-29 17:58:14 +08:00 committed by GitHub
parent 5d84e4de1c
commit 325525c07c
7 changed files with 64 additions and 50 deletions

View File

@ -34,7 +34,7 @@
"@formkit/vue": "1.0.0-beta.9",
"@halo-dev/admin-api": "^1.1.0",
"@halo-dev/admin-shared": "workspace:*",
"@halo-dev/api-client": "^0.0.5",
"@halo-dev/api-client": "^0.0.6",
"@halo-dev/components": "workspace:*",
"@vueuse/components": "^8.9.4",
"@vueuse/core": "^8.9.4",

View File

@ -35,7 +35,7 @@
"homepage": "https://github.com/halo-dev/halo-admin/tree/next/shared/components#readme",
"license": "MIT",
"dependencies": {
"@halo-dev/api-client": "^0.0.5",
"@halo-dev/api-client": "^0.0.6",
"@halo-dev/components": "workspace:*",
"axios": "^0.27.2"
},

View File

@ -14,7 +14,7 @@ importers:
'@formkit/vue': 1.0.0-beta.9
'@halo-dev/admin-api': ^1.1.0
'@halo-dev/admin-shared': workspace:*
'@halo-dev/api-client': ^0.0.5
'@halo-dev/api-client': ^0.0.6
'@halo-dev/components': workspace:*
'@rushstack/eslint-patch': ^1.1.4
'@tailwindcss/aspect-ratio': ^0.4.0
@ -84,7 +84,7 @@ importers:
'@formkit/vue': 1.0.0-beta.9_jly5jqkcc2zgnt3crhnp3znzv4
'@halo-dev/admin-api': 1.1.0
'@halo-dev/admin-shared': link:packages/shared
'@halo-dev/api-client': 0.0.5
'@halo-dev/api-client': 0.0.6
'@halo-dev/components': link:packages/components
'@vueuse/components': 8.9.4_vue@3.2.37
'@vueuse/core': 8.9.4_vue@3.2.37
@ -176,12 +176,12 @@ importers:
packages/shared:
specifiers:
'@halo-dev/api-client': ^0.0.5
'@halo-dev/api-client': ^0.0.6
'@halo-dev/components': workspace:*
axios: ^0.27.2
vite-plugin-dts: ^1.3.1
dependencies:
'@halo-dev/api-client': 0.0.5
'@halo-dev/api-client': 0.0.6
'@halo-dev/components': link:../components
axios: 0.27.2
devDependencies:
@ -1873,8 +1873,8 @@ packages:
- debug
dev: false
/@halo-dev/api-client/0.0.5:
resolution: {integrity: sha512-UqT6svy1nEVGF1swZXJgvu9iy6gQhaJ/o8lY5736Q4BbW8pYrqQBEQYNv8ySRBQr762/Cy7wDFijAGlPod7tDw==}
/@halo-dev/api-client/0.0.6:
resolution: {integrity: sha512-JDWGlTq+pHVrZsmqDCXAowZQFcNL3M6+guL37yrKbhylUgIutYpCMU/d2Qogc+c43FzFBq84igP84T5XtuknjQ==}
dev: false
/@halo-dev/logger/1.1.0:

View File

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { VSwitch, VTag } from "@halo-dev/components";
import type { Ref } from "vue";
import { computed, inject, onMounted, ref } from "vue";
import { computed, inject, ref, watchEffect } from "vue";
import { apiClient } from "@halo-dev/admin-shared";
import type { Plugin, Role } from "@halo-dev/api-client";
import { pluginLabels } from "@/constants/labels";
@ -11,31 +11,24 @@ import { usePluginLifeCycle } from "./composables/use-plugin";
const plugin = inject<Ref<Plugin>>("plugin", ref({} as Plugin));
const { changeStatus, isStarted } = usePluginLifeCycle(plugin);
// TODO
interface RoleTemplateGroup {
module: string | null | undefined;
roles: Role[];
}
const roles = ref<Role[]>([]);
const pluginRoleTemplates = ref<Role[]>([]);
const handleFetchRoles = async () => {
try {
const { data } = await apiClient.extension.role.listv1alpha1Role();
roles.value = data.items;
const { data } = await apiClient.extension.role.listv1alpha1Role(0, 0, [
`${pluginLabels.NAME}=${plugin.value.metadata.name}`,
]);
pluginRoleTemplates.value = data.items;
} catch (e) {
console.error(e);
}
};
const pluginRoleTemplates = computed(() => {
return roles.value.filter((item) => {
return (
item.metadata.labels?.[pluginLabels.NAME] === plugin.value.metadata?.name
);
});
});
const pluginRoleTemplateGroups = computed<RoleTemplateGroup[]>(() => {
const groups: RoleTemplateGroup[] = [];
pluginRoleTemplates.value.forEach((role) => {
@ -55,8 +48,10 @@ const pluginRoleTemplateGroups = computed<RoleTemplateGroup[]>(() => {
return groups;
});
onMounted(() => {
handleFetchRoles();
watchEffect(() => {
if (plugin.value.metadata?.name) {
handleFetchRoles();
}
});
</script>

View File

@ -12,23 +12,42 @@ import {
} from "@halo-dev/components";
import PluginListItem from "./components/PluginListItem.vue";
import PluginInstallModal from "./components/PluginInstallModal.vue";
import { onMounted, ref } from "vue";
import { onMounted, ref, watch } from "vue";
import { apiClient } from "@halo-dev/admin-shared";
import type { Plugin } from "@halo-dev/api-client";
const plugins = ref<Plugin[]>([] as Plugin[]);
const pluginInstall = ref(false);
const keyword = ref("");
const handleFetchPlugins = async () => {
try {
const fieldSelector: Array<string> = [];
if (keyword.value) {
fieldSelector.push(`name=${keyword.value}`);
}
const { data } =
await apiClient.extension.plugin.listpluginHaloRunV1alpha1Plugin();
await apiClient.extension.plugin.listpluginHaloRunV1alpha1Plugin(
0,
0,
[],
fieldSelector
);
plugins.value = data.items;
} catch (e) {
console.error("Fail to fetch plugins", e);
}
};
watch(
() => keyword.value,
() => {
handleFetchPlugins();
}
);
onMounted(handleFetchPlugins);
</script>
<template>
@ -64,7 +83,11 @@ onMounted(handleFetchPlugins);
class="relative flex flex-col items-start sm:flex-row sm:items-center"
>
<div class="flex w-full flex-1 sm:w-auto">
<FormKit placeholder="输入关键词搜索" type="text"></FormKit>
<FormKit
v-model="keyword"
placeholder="输入关键词搜索"
type="text"
></FormKit>
</div>
<div class="mt-4 flex sm:mt-0">
<VSpace spacing="lg">

View File

@ -12,7 +12,7 @@ import {
VTag,
} from "@halo-dev/components";
import RoleEditingModal from "./components/RoleEditingModal.vue";
import { computed, onMounted, ref } from "vue";
import { onMounted, ref } from "vue";
import type { Role } from "@halo-dev/api-client";
import { apiClient } from "@halo-dev/admin-shared";
import { roleLabels } from "@/constants/labels";
@ -22,15 +22,11 @@ const roles = ref<Role[]>([]);
const editingModal = ref<boolean>(false);
const selectedRole = ref<Role | null>(null);
const basicRoles = computed(() => {
return roles.value.filter(
(role) => role.metadata?.labels?.[roleLabels.TEMPLATE] !== "true"
);
});
const handleFetchRoles = async () => {
try {
const { data } = await apiClient.extension.role.listv1alpha1Role();
const { data } = await apiClient.extension.role.listv1alpha1Role(0, 0, [
`!${roleLabels.TEMPLATE}`,
]);
roles.value = data.items;
} catch (e) {
console.error(e);
@ -169,7 +165,7 @@ onMounted(() => {
</div>
</template>
<ul class="box-border h-full w-full divide-y divide-gray-100" role="list">
<li v-for="(role, index) in basicRoles" :key="index">
<li v-for="(role, index) in roles" :key="index">
<div
class="relative block cursor-pointer px-4 py-3 transition-all hover:bg-gray-50"
>

View File

@ -59,21 +59,13 @@ export function useRoleForm() {
}
export function useRoleTemplateSelection() {
const rawRoles = ref<Role[]>([] as Role[]);
const roleTemplates = ref<Role[]>([] as Role[]);
const selectedRoleTemplates = ref<Set<string>>(new Set());
// Get all role templates based on the condition that `metadata.labels.[halo.run/role-template] === 'true'`
const roleTemplates = computed<Role[]>(() => {
return rawRoles.value.filter(
(role) =>
role.metadata.labels?.[roleLabels.TEMPLATE] === "true" &&
role.metadata.labels?.["halo.run/hidden"] !== "true"
);
});
/**
* Grouping role templates by module
* Grouping role templates by module <br />
* Example:
* ```json
* {
* "module": "Users Management",
* "roles": [
@ -151,6 +143,7 @@ export function useRoleTemplateSelection() {
* }
* ]
* }
* ```
*/
const roleTemplateGroups = computed<RoleTemplateGroup[]>(() => {
const groups: RoleTemplateGroup[] = [];
@ -171,10 +164,16 @@ export function useRoleTemplateSelection() {
return groups;
});
/**
* Get all role templates based on the condition that `metadata.labels.[halo.run/role-template] = 'true'` and `!halo.run/hidden`
*/
const handleFetchRoles = async () => {
try {
const { data } = await apiClient.extension.role.listv1alpha1Role();
rawRoles.value = data.items;
const { data } = await apiClient.extension.role.listv1alpha1Role(0, 0, [
`${roleLabels.TEMPLATE}=true`,
"!halo.run/hidden",
]);
roleTemplates.value = data.items;
} catch (e) {
console.error(e);
}
@ -185,7 +184,9 @@ export function useRoleTemplateSelection() {
if (!checked) {
return;
}
const role = rawRoles.value.find((role) => role.metadata.name === value);
const role = roleTemplates.value.find(
(role) => role.metadata.name === value
);
const dependencies =
role?.metadata.annotations?.[rbacAnnotations.DEPENDENCIES];
if (!dependencies) {
@ -200,7 +201,6 @@ export function useRoleTemplateSelection() {
onMounted(handleFetchRoles);
return {
rawRoles,
selectedRoleTemplates,
roleTemplates,
roleTemplateGroups,