Skip to content

Commit

Permalink
Merge pull request galaxyproject#17126 from guerler/grids_groups_admin
Browse files Browse the repository at this point in the history
Vueify Admin Groups Grid
  • Loading branch information
davelopez authored Dec 8, 2023
2 parents e7a1680 + 35bcefa commit 6b88703
Show file tree
Hide file tree
Showing 11 changed files with 411 additions and 156 deletions.
6 changes: 5 additions & 1 deletion client/src/api/groups.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import axios from "axios";

import { components } from "@/api/schema";
import { components, fetcher } from "@/api/schema";

type GroupModel = components["schemas"]["GroupModel"];
export async function getAllGroups(): Promise<GroupModel[]> {
const { data } = await axios.get("/api/groups");
return data;
}

export const deleteGroup = fetcher.path("/api/groups/{group_id}").method("delete").create();
export const purgeGroup = fetcher.path("/api/groups/{group_id}/purge").method("post").create();
export const undeleteGroup = fetcher.path("/api/groups/{group_id}/undelete").method("post").create();
88 changes: 88 additions & 0 deletions client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,12 @@ export interface paths {
get: operations["show_group_api_groups__group_id__get"];
/** Modifies a group. */
put: operations["update_api_groups__group_id__put"];
/** Delete */
delete: operations["delete_api_groups__group_id__delete"];
};
"/api/groups/{group_id}/purge": {
/** Purge */
post: operations["purge_api_groups__group_id__purge_post"];
};
"/api/groups/{group_id}/roles": {
/** Displays a collection (list) of groups. */
Expand All @@ -405,6 +411,10 @@ export interface paths {
/** Removes a role from a group */
delete: operations["delete_api_groups__group_id__roles__role_id__delete"];
};
"/api/groups/{group_id}/undelete": {
/** Undelete */
post: operations["undelete_api_groups__group_id__undelete_post"];
};
"/api/groups/{group_id}/user/{user_id}": {
/**
* Displays information about a group user.
Expand Down Expand Up @@ -12044,6 +12054,58 @@ export interface operations {
};
};
};
delete_api_groups__group_id__delete: {
/** Delete */
parameters: {
/** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */
header?: {
"run-as"?: string;
};
path: {
group_id: string;
};
};
responses: {
/** @description Successful Response */
200: {
content: {
"application/json": Record<string, never>;
};
};
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
purge_api_groups__group_id__purge_post: {
/** Purge */
parameters: {
/** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */
header?: {
"run-as"?: string;
};
path: {
group_id: string;
};
};
responses: {
/** @description Successful Response */
200: {
content: {
"application/json": Record<string, never>;
};
};
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
group_roles_api_groups__group_id__roles_get: {
/** Displays a collection (list) of groups. */
parameters: {
Expand Down Expand Up @@ -12158,6 +12220,32 @@ export interface operations {
};
};
};
undelete_api_groups__group_id__undelete_post: {
/** Undelete */
parameters: {
/** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */
header?: {
"run-as"?: string;
};
path: {
group_id: string;
};
};
responses: {
/** @description Successful Response */
200: {
content: {
"application/json": Record<string, never>;
};
};
/** @description Validation Error */
422: {
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
group_user_api_groups__group_id__user__user_id__get: {
/**
* Displays information about a group user.
Expand Down
13 changes: 13 additions & 0 deletions client/src/components/Grid/GridList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ library.add(faCaretDown, faCaretUp, faShieldAlt);
interface Props {
// provide a grid configuration
gridConfig: GridConfig;
// incoming initial message
gridMessage?: string;
// debounce delay
delay?: number;
// rows per page to be shown
Expand Down Expand Up @@ -81,6 +83,16 @@ function applyFilter(filter: string, value: string | boolean, quoted = false) {
}
}
/**
* Display initial message parsed through route query
*/
function displayInitialMessage() {
if (props.gridMessage) {
operationMessage.value = props.gridMessage;
operationStatus.value = "success";
}
}
/**
* Request grid data
*/
Expand Down Expand Up @@ -164,6 +176,7 @@ function onFilter(filter?: string) {
onMounted(() => {
getGridData();
eventBus.on(onRouterPush);
displayInitialMessage();
});
onUnmounted(() => {
Expand Down
181 changes: 181 additions & 0 deletions client/src/components/Grid/configs/adminGroups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import { faEdit, faKey, faPlus, faTrash, faTrashRestore } from "@fortawesome/free-solid-svg-icons";
import { useEventBus } from "@vueuse/core";
import axios from "axios";

import { deleteGroup, purgeGroup, undeleteGroup } from "@/api/groups";
import Filtering, { contains, equals, toBool, type ValidFilter } from "@/utils/filtering";
import _l from "@/utils/localization";
import { withPrefix } from "@/utils/redirect";
import { errorMessageAsString } from "@/utils/simple-error";

import type { ActionArray, FieldArray, GridConfig } from "./types";

const { emit } = useEventBus<string>("grid-router-push");

/**
* Local types
*/
type GroupEntry = Record<string, unknown>;

/**
* Request and return data from server
*/
async function getData(offset: number, limit: number, search: string, sort_by: string, sort_desc: boolean) {
const query = {
limit: String(limit),
offset: String(offset),
search: search,
sort_by: sort_by,
sort_desc: String(sort_desc),
};
const queryString = new URLSearchParams(query).toString();
const { data } = await axios.get(withPrefix(`/admin/groups_list?${queryString}`));
return [data.rows, data.rows_total];
}

/**
* Actions are grid-wide operations
*/
const actions: ActionArray = [
{
title: "Create New Group",
icon: faPlus,
handler: () => {
emit("/admin/form/create_group");
},
},
];

/**
* Declare columns to be displayed
*/
const fields: FieldArray = [
{
key: "name",
title: "Name",
type: "operations",
operations: [
{
title: "Edit Name",
icon: faEdit,
condition: (data: GroupEntry) => !data.deleted,
handler: (data: GroupEntry) => {
emit(`/admin/form/rename_group?id=${data.id}`);
},
},
{
title: "Edit Permissions",
icon: faKey,
condition: (data: GroupEntry) => !data.deleted,
handler: (data: GroupEntry) => {
emit(`/admin/form/manage_users_and_roles_for_group?id=${data.id}`);
},
},
{
title: "Delete",
icon: faTrash,
condition: (data: GroupEntry) => !data.deleted,
handler: async (data: GroupEntry) => {
if (confirm(_l("Are you sure that you want to delete this group?"))) {
try {
await deleteGroup({ group_id: String(data.id) });
return {
status: "success",
message: `'${data.name}' has been deleted.`,
};
} catch (e) {
return {
status: "danger",
message: `Failed to delete '${data.name}': ${errorMessageAsString(e)}`,
};
}
}
},
},
{
title: "Purge",
icon: faTrash,
condition: (data: GroupEntry) => !!data.deleted,
handler: async (data: GroupEntry) => {
if (confirm(_l("Are you sure that you want to purge this group?"))) {
try {
await purgeGroup({ group_id: String(data.id) });
return {
status: "success",
message: `'${data.name}' has been purged.`,
};
} catch (e) {
return {
status: "danger",
message: `Failed to purge '${data.name}': ${errorMessageAsString(e)}`,
};
}
}
},
},
{
title: "Restore",
icon: faTrashRestore,
condition: (data: GroupEntry) => !!data.deleted,
handler: async (data: GroupEntry) => {
try {
await undeleteGroup({ group_id: String(data.id) });
return {
status: "success",
message: `'${data.name}' has been restored.`,
};
} catch (e) {
return {
status: "danger",
message: `Failed to restore '${data.name}': ${errorMessageAsString(e)}`,
};
}
},
},
],
},
{
key: "roles",
title: "Roles",
type: "text",
},
{
key: "users",
title: "Users",
type: "text",
},
{
key: "update_time",
title: "Updated",
type: "date",
},
];

const validFilters: Record<string, ValidFilter<string | boolean | undefined>> = {
name: { placeholder: "name", type: String, handler: contains("name"), menuItem: true },
deleted: {
placeholder: "Filter on deleted entries",
type: Boolean,
boolType: "is",
handler: equals("deleted", "deleted", toBool),
menuItem: true,
},
};

/**
* Grid configuration
*/
const gridConfig: GridConfig = {
id: "groups-grid",
actions: actions,
fields: fields,
filtering: new Filtering(validFilters, undefined, false, false),
getData: getData,
plural: "Groups",
sortBy: "name",
sortDesc: true,
sortKeys: ["name", "update_time"],
title: "Groups",
};

export default gridConfig;
Loading

0 comments on commit 6b88703

Please sign in to comment.