-
Notifications
You must be signed in to change notification settings - Fork 2.6k
feat: Folder authorization can optionally include sub-resources #4220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -119,6 +119,28 @@ | |
| </template> | ||
| </el-table-column> | ||
| </app-table> | ||
| <!-- 单个资源授权提示框 --> | ||
| <el-dialog | ||
| v-model="singleSelectDialogVisible" | ||
| :title="$t('views.system.resourceAuthorization.setting.configure')" | ||
| destroy-on-close | ||
| @close="closeSingleSelectDialog" | ||
| > | ||
| <el-radio-group v-model="authAllChildren" class="radio-block"> | ||
| <el-radio :value="false"> | ||
| <p class="color-text-primary lighter">{{ $t('views.system.resourceAuthorization.setting.currentOnly') }}</p> | ||
| </el-radio> | ||
| <el-radio :value="true"> | ||
| <p class="color-text-primary lighter">{{ $t('views.system.resourceAuthorization.setting.includeAll') }}</p> | ||
| </el-radio> | ||
| </el-radio-group> | ||
| <template #footer> | ||
| <div class="dialog-footer mt-24"> | ||
| <el-button @click="closeSingleSelectDialog">{{ $t('common.cancel') }}</el-button> | ||
| <el-button type="primary" @click="confirmSinglePermission">{{ $t('common.confirm') }}</el-button> | ||
| </div> | ||
| </template> | ||
| </el-dialog> | ||
|
|
||
| <!-- 批量配置 弹出层 --> | ||
| <el-dialog | ||
|
|
@@ -128,13 +150,26 @@ | |
| @close="closeDialog" | ||
| > | ||
| <el-radio-group v-model="radioPermission" class="radio-block"> | ||
| <template v-for="(item, index) in permissionOptions" :key="index"> | ||
| <template v-for="(item, index) in getFolderPermissionOptions()" :key="index"> | ||
| <el-radio :value="item.value" class="mr-16"> | ||
| <p class="color-text-primary lighter">{{ item.label }}</p> | ||
| <el-text class="color-secondary lighter">{{ item.desc }}</el-text> | ||
| </el-radio> | ||
| </template> | ||
| </el-radio-group> | ||
| <!-- 如果是文件夹,显示子资源选项 --> | ||
| <div v-if="isFolder" class="mt-16"> | ||
| <el-divider /> | ||
| <div class="color-text-primary mb-8">{{ $t('views.system.resourceAuthorization.setting.effectiveResource') }}</div> | ||
| <el-radio-group v-model="batchAuthAllChildren" class="radio-block"> | ||
| <el-radio :value="false"> | ||
| <p class="color-text-primary lighter">{{ $t('views.system.resourceAuthorization.setting.currentOnly') }}</p> | ||
| </el-radio> | ||
| <el-radio :value="true"> | ||
| <p class="color-text-primary lighter">{{ $t('views.system.resourceAuthorization.setting.includeAll') }}</p> | ||
| </el-radio> | ||
| </el-radio-group> | ||
| </div> | ||
| <template #footer> | ||
| <div class="dialog-footer mt-24"> | ||
| <el-button @click="closeDialog"> {{ $t('common.cancel') }}</el-button> | ||
|
|
@@ -151,9 +186,11 @@ import { getPermissionOptions } from '@/views/system/resource-authorization/cons | |
| import AuthorizationApi from '@/api/system/resource-authorization' | ||
| import { MsgSuccess, MsgConfirm } from '@/utils/message' | ||
| import { t } from '@/locales' | ||
| import permissionMap from '@/permission' | ||
| import { loadSharedApi } from '@/utils/dynamics-api/shared-api' | ||
| const route = useRoute() | ||
| import useStore from '@/stores' | ||
|
|
||
| const { user } = useStore() | ||
| const props = defineProps<{ | ||
| type: string | ||
|
|
@@ -169,6 +206,57 @@ const apiType = computed(() => { | |
| } | ||
| }) | ||
|
|
||
| const folderType = computed(() => { | ||
| if (route.path.includes('application')) { | ||
| return 'application' | ||
| } | ||
| else if (route.path.includes('knowledge')) { | ||
| return 'knowledge' | ||
| } | ||
| else if (route.path.includes('tool')) { | ||
| return 'tool' | ||
| } | ||
| else {return 'application'} | ||
| }) | ||
|
|
||
| const permissionPrecise = computed(() => { | ||
| return permissionMap[folderType.value!]['workspace'] | ||
| }) | ||
|
|
||
| // 取出文件夹id | ||
| function getAllFolderIds(data: any) { | ||
| if (!data) return [] | ||
| return [data.id,...(data.children?.flatMap((child: any) => getAllFolderIds(child)) || [])] | ||
| } | ||
|
|
||
| // 过滤没有Manage权限的文件夹ID | ||
| function filterHasPermissionFolderIds(folderIds: string[]) { | ||
| return folderIds.filter(id => permissionPrecise.value.folderManage(id)) | ||
| } | ||
|
|
||
| function confirmSinglePermission() { | ||
| if (!pendingPermissionChange.value) return | ||
| const { val, row } = pendingPermissionChange.value | ||
| let folderIds: string[] = [] | ||
| if (authAllChildren.value && folderData.value) { | ||
| const allFolderIds = getAllFolderIds(folderData.value) | ||
| folderIds = filterHasPermissionFolderIds(allFolderIds) | ||
| } | ||
| const obj = [ | ||
| { | ||
| user_id: row.id, | ||
| permission: val, | ||
| include_children: authAllChildren.value, | ||
| ...(folderIds.length > 0 && {folder_ids: folderIds}) | ||
| }, | ||
| ] | ||
| submitPermissions(obj) | ||
| singleSelectDialogVisible.value = false | ||
| authAllChildren.value = false | ||
| pendingPermissionChange.value = null | ||
| getPermissionList() | ||
| } | ||
|
|
||
| const permissionOptionMap = computed(() => { | ||
| return { | ||
| rootFolder: getPermissionOptions(true, true), | ||
|
|
@@ -207,6 +295,7 @@ watch(drawerVisible, (bool) => { | |
|
|
||
| const loading = ref(false) | ||
| const targetId = ref('') | ||
| const folderData = ref<any>(null) | ||
| const permissionData = ref<any[]>([]) | ||
| const searchType = ref('nick_name') | ||
| const searchForm = ref<any>({ | ||
|
|
@@ -241,32 +330,59 @@ const handleSelectionChange = (val: any[]) => { | |
| } | ||
|
|
||
| const dialogVisible = ref(false) | ||
| const singleSelectDialogVisible = ref(false) | ||
| const pendingPermissionChange = ref<{ val: any; row: any; } | null>(null) | ||
| const radioPermission = ref('') | ||
| const authAllChildren = ref(false) | ||
| function openMulConfigureDialog() { | ||
| if (multipleSelection.value.length === 0) { | ||
| return | ||
| } | ||
| dialogVisible.value = true | ||
| } | ||
|
|
||
| const batchAuthAllChildren = ref(false) | ||
| function submitDialog() { | ||
| if (multipleSelection.value.length === 0 || !radioPermission.value) { | ||
| return | ||
| } | ||
| let folderIds: string[] = [] | ||
| if (props.isFolder && batchAuthAllChildren.value && folderData.value) { | ||
| const allFolderIds = getAllFolderIds(folderData.value) | ||
| folderIds = filterHasPermissionFolderIds(allFolderIds) | ||
| } | ||
|
|
||
| const obj = multipleSelection.value.map((item) => ({ | ||
| user_id: item.id, | ||
| permission: radioPermission.value, | ||
| include_children: batchAuthAllChildren.value, | ||
| ...(folderIds.length > 0 && { folder_ids: folderIds }) | ||
| })) | ||
| submitPermissions(obj) | ||
| closeDialog() | ||
| } | ||
|
|
||
| function closeSingleSelectDialog() { | ||
| singleSelectDialogVisible.value = false | ||
| authAllChildren.value = false | ||
| pendingPermissionChange.value = null | ||
| getPermissionList() | ||
| } | ||
|
|
||
| function closeDialog() { | ||
| dialogVisible.value = false | ||
| radioPermission.value = '' | ||
| batchAuthAllChildren.value = false | ||
| multipleSelection.value = [] | ||
| multipleTableRef.value?.clearSelection() | ||
| } | ||
|
|
||
| function permissionsHandle(val: any, row: any) { | ||
| if (props.isFolder) { | ||
| singleSelectDialogVisible.value = true | ||
| pendingPermissionChange.value = {val, row} | ||
| return | ||
| } | ||
| const obj = [ | ||
| { | ||
| user_id: row.id, | ||
|
|
@@ -276,7 +392,7 @@ function permissionsHandle(val: any, row: any) { | |
| submitPermissions(obj) | ||
| } | ||
|
|
||
| function submitPermissions(obj: any) { | ||
| function submitPermissions( obj: any) { | ||
| const workspaceId = user.getWorkspaceId() || 'default' | ||
| loadSharedApi({ type: 'resourceAuthorization', systemType: apiType.value }) | ||
| .putResourceAuthorization(workspaceId, targetId.value, props.type, obj, loading) | ||
|
|
@@ -311,8 +427,9 @@ const getPermissionList = () => { | |
| }) | ||
| } | ||
|
|
||
| const open = (id: string) => { | ||
| const open = (id: string, folder_data?: any) => { | ||
| targetId.value = id | ||
| folderData.value = folder_data | ||
| drawerVisible.value = true | ||
| getPermissionList() | ||
| } | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code provided has several improvements and corrections to address potential issues:
Here’s an example of how some lines could look after these adjustments: <template>
<app-table :columns="column"></app-table>
<!-- 单个资源授权提示框 -->
<el-dialog ... @close="closeSingleSelectDialog">
...
</el-dialog>
<!-- 批量配置 弹出层 -->
<el-dialog ... @close="closeDialog">
...
</el-dialog>
</template>
<script setup lang="ts">
// Import statements if needed
import { ref, computed, watch } from 'vue';
import { ElDialog, ElRadioGroup,.ElButton, ElText, ElDivisor } from 'element-plus';
import AuthroizationApi from '@/api/system/resource-authorization';
import msgSuccess from '@/utils/message';
export default {
components: {
appTable,
ElDialog,
ElRadioGroup,
ElButton,
ElText,
ElDivisor,
},
data() {
[...],
},
computed: {
...[],
},
methods: {
open(...[id]): void {
targetId.value = id;
drawerVisible.value = true;
getPermissionList();
},
closeSingleSelectDialog():void{
singleSelectDialogVisible.value = false;
authAllChildren.value = false;
pendingPermissionChange.value = null;
getPermissionList();
},
// Rest of your functions...
});By making these changes, you should improve the stability and functionality of your Vue application related to resource authorization dialogues. |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -123,6 +123,9 @@ export default { | |
| roleDesc: 'Authorize users based on their roles to access this resource', | ||
| notAuthorized: 'Not Authorized', | ||
| configure: 'Configure Permission', | ||
| currentOnly: 'Current resource only', | ||
| includeAll: 'Include all sub-resources', | ||
| effectiveResource: 'Effective Resource', | ||
| }, | ||
| }, | ||
| resource_management: { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The provided code looks generally correct and well-documented. However, there are a few minor suggestions for improving it:
Here's a slightly adjusted version based on these suggestions: /*
* Configuration messages for resource management.
*/
//
// Exported default configuration objects.
//
import { defineMessage } from '@lingui/macro';
const message = defineMessage({
id: 'app.resourceManagement.permissions.labels.roleDesc',
defaultMessage: 'Authorize users based on their roles to access this resource',
description:
"Description of how users' roles will determine their permission level to access specific resources.",
});
const notAuthorizedMsg = defineMessage({
id: 'app.resourceManagement.errors.notAuthorized',
defaultMessage: 'Not Authorized',
description:
"User interface message indicating that the user does not have permission to access the requested resource.",
});
const configurePermissionMsg = defineMessage({
id: 'app.resourceManagement.actions.configure',
defaultMessage: 'Configure Permission',
description:
"Action button label prompting users to configure permissions related to their role(s).",
});
const currentOnlyMsg = defineMessage({
id: 'app.resourceManagement.options.currentOnly',
defaultMessage: 'Current resource only',
description:
"Option in a dropdown menu limiting permission visibility to just the selected resource.",
});
const includeAllSubResourcesMsg = defineMessage({
id: 'app.resourceManagement.options.includeAll',
defaultMessage: 'Include all sub-resources',
description:
"Option in a checkbox or toggle enabling users to grant permissions across all subordinate resources as part of the base resource selection.",
});
const effectiveResourceMsg = defineMessage({
id: 'app.resourceManagement.labels.effectiveResource',
defaultMessage: 'Effective Resource',
description:
"Label describing which resource's permissions are effectively being managed within the system when configuring permissions for a particular user or group.",
});
module.exports = {
labels: {
// ... other labels remain unchanged ...
notAuthorized,
configurePermission,
currentOnly,
includeAll,
effectiveResource,
},
};These changes add some space between sections and explanations where necessary, making the code structure clearer and potentially easier to navigate for those reading it in isolation. |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The provided code snippet has some areas that can be improved for better readability, maintainability, and future-proofing. Below are my observations with specific comments:
Improvements
Import Optimization:
TextFieldimport should only be needed when dealing with certain operations related to database fields. If it's not used elsewhere, you can remove this import.Code Clarity:
=) for better readability.Functionality Reorganization:
Error Handling:
Here's the refactored and optimized version of the code:
Notable Changes
current_user_idargument to the constructor for better flexibility._validate,get_dynamics_model, etc., to keep main function calls clean.These improvements make the code more readable, maintainble, and easier to extend without increasing its complexity significantly.