mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-09-26 00:10:27 +00:00
feat: add update and remove buttons to the status table
This commit is contained in:
@@ -17,10 +17,13 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
||||
import { Box, Link } from "@mui/material";
|
||||
import {
|
||||
DataGrid,
|
||||
GRID_CHECKBOX_SELECTION_COL_DEF,
|
||||
GridActionsCellItem,
|
||||
type GridColDef,
|
||||
type GridFilterModel,
|
||||
type GridRowId,
|
||||
@@ -56,6 +59,7 @@ function createListColumn(
|
||||
|
||||
export default function PackageTable(): React.JSX.Element {
|
||||
const table = usePackageTable();
|
||||
const { handleRemove, handleUpdate, isAuthorized } = table;
|
||||
const apiRef = useGridApiRef();
|
||||
const debouncedSearch = useDebounce(table.searchText, 300);
|
||||
|
||||
@@ -96,8 +100,31 @@ export default function PackageTable(): React.JSX.Element {
|
||||
<StatusCell isHeld={params.row.isHeld} status={params.row.status} />,
|
||||
width: 120,
|
||||
},
|
||||
...isAuthorized ? [{
|
||||
field: "actions",
|
||||
type: "actions",
|
||||
headerName: "actions",
|
||||
width: 100,
|
||||
disableExport: true,
|
||||
getActions: ({ row }) => [
|
||||
<GridActionsCellItem
|
||||
key="update"
|
||||
icon={<PlayArrowIcon />}
|
||||
label={`Update ${row.base}`}
|
||||
title={`Update ${row.base}`}
|
||||
onClick={() => void handleUpdate([row.base])}
|
||||
/>,
|
||||
<GridActionsCellItem
|
||||
key="remove"
|
||||
icon={<DeleteIcon />}
|
||||
label={`Remove ${row.base}`}
|
||||
title={`Remove ${row.base}`}
|
||||
onClick={() => void handleRemove([row.base])}
|
||||
/>,
|
||||
],
|
||||
} satisfies GridColDef<PackageRow>] : [],
|
||||
],
|
||||
[],
|
||||
[handleRemove, handleUpdate, isAuthorized],
|
||||
);
|
||||
|
||||
return <Box sx={{ display: "flex", flexDirection: "column", width: "100%" }}>
|
||||
@@ -110,8 +137,10 @@ export default function PackageTable(): React.JSX.Element {
|
||||
onRebuildClick: () => table.setDialogOpen("rebuild"),
|
||||
onRefreshDatabaseClick: () => void table.handleRefreshDatabase(),
|
||||
onReloadClick: table.handleReload,
|
||||
onRemoveClick: () => void table.handleRemove(),
|
||||
onUpdateClick: () => void table.handleUpdate(),
|
||||
onRemoveClick: () => void table.handleRemove(table.selectionModel)
|
||||
.then(() => table.setSelectionModel([])),
|
||||
onUpdateClick: () => void table.handleUpdate(table.selectionModel)
|
||||
.then(() => table.setSelectionModel([])),
|
||||
}}
|
||||
isAuthorized={table.isAuthorized}
|
||||
hasSelection={table.selectionModel.length > 0}
|
||||
@@ -123,6 +152,7 @@ export default function PackageTable(): React.JSX.Element {
|
||||
<DataGrid
|
||||
apiRef={apiRef}
|
||||
checkboxSelection
|
||||
localeText={{ checkboxSelectionHeaderName: "selection" }}
|
||||
columnVisibilityModel={table.columnVisibility}
|
||||
columns={columns}
|
||||
density="compact"
|
||||
@@ -134,8 +164,8 @@ export default function PackageTable(): React.JSX.Element {
|
||||
}}
|
||||
loading={table.isLoading}
|
||||
onCellClick={(params, event) => {
|
||||
// Don't open info dialog when clicking checkbox or link
|
||||
if (params.field === GRID_CHECKBOX_SELECTION_COL_DEF.field) {
|
||||
// Don't open info dialog when clicking checkbox, actions, or link
|
||||
if (params.field === GRID_CHECKBOX_SELECTION_COL_DEF.field || params.field === "actions") {
|
||||
return;
|
||||
}
|
||||
if ((event.target as HTMLElement).closest("a")) {
|
||||
|
||||
@@ -24,29 +24,27 @@ import { useClient } from "hooks/useClient";
|
||||
import { useNotification } from "hooks/useNotification";
|
||||
import { useRepository } from "hooks/useRepository";
|
||||
import type { RepositoryId } from "models/RepositoryId";
|
||||
import { useCallback } from "react";
|
||||
|
||||
export interface UsePackageActionsResult {
|
||||
handleRefreshDatabase: () => Promise<void>;
|
||||
handleReload: () => void;
|
||||
handleRemove: () => Promise<void>;
|
||||
handleUpdate: () => Promise<void>;
|
||||
handleRemove: (packages: string[]) => Promise<void>;
|
||||
handleUpdate: (packages: string[]) => Promise<void>;
|
||||
}
|
||||
|
||||
export function usePackageActions(
|
||||
selectionModel: string[],
|
||||
setSelectionModel: (model: string[]) => void,
|
||||
): UsePackageActionsResult {
|
||||
export function usePackageActions(): UsePackageActionsResult {
|
||||
const client = useClient();
|
||||
const { currentRepository } = useRepository();
|
||||
const { showSuccess, showError } = useNotification();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const invalidate = (repository: RepositoryId): void => {
|
||||
const invalidate = useCallback((repository: RepositoryId): void => {
|
||||
void queryClient.invalidateQueries({ queryKey: QueryKeys.packages(repository) });
|
||||
void queryClient.invalidateQueries({ queryKey: QueryKeys.status(repository) });
|
||||
};
|
||||
}, [queryClient]);
|
||||
|
||||
const performAction = async (
|
||||
const performAction = useCallback(async (
|
||||
action: (repository: RepositoryId) => Promise<string>,
|
||||
errorMessage: string,
|
||||
): Promise<void> => {
|
||||
@@ -57,11 +55,10 @@ export function usePackageActions(
|
||||
const successMessage = await action(currentRepository);
|
||||
showSuccess("Success", successMessage);
|
||||
invalidate(currentRepository);
|
||||
setSelectionModel([]);
|
||||
} catch (exception) {
|
||||
showError("Action failed", `${errorMessage}: ${ApiError.errorDetail(exception)}`);
|
||||
}
|
||||
};
|
||||
}, [currentRepository, invalidate, showError, showSuccess]);
|
||||
|
||||
const handleReload = (): void => {
|
||||
if (currentRepository !== null) {
|
||||
@@ -69,14 +66,16 @@ export function usePackageActions(
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdate = (): Promise<void> => performAction(async (repository): Promise<string> => {
|
||||
if (selectionModel.length === 0) {
|
||||
await client.service.servicePackageUpdate(repository, { packages: [] });
|
||||
return "Repository update has been run";
|
||||
}
|
||||
await client.service.servicePackageAdd(repository, { packages: selectionModel });
|
||||
return `Run update for packages ${selectionModel.join(", ")}`;
|
||||
}, "Packages update failed");
|
||||
const handleUpdate = useCallback((packages: string[]): Promise<void> => {
|
||||
return performAction(async (repository): Promise<string> => {
|
||||
if (packages.length === 0) {
|
||||
await client.service.servicePackageUpdate(repository, { packages: [] });
|
||||
return "Repository update has been run";
|
||||
}
|
||||
await client.service.servicePackageAdd(repository, { packages });
|
||||
return `Run update for packages ${packages.join(", ")}`;
|
||||
}, "Packages update failed");
|
||||
}, [client, performAction]);
|
||||
|
||||
const handleRefreshDatabase = (): Promise<void> => performAction(async (repository): Promise<string> => {
|
||||
await client.service.servicePackageUpdate(repository, {
|
||||
@@ -89,15 +88,15 @@ export function usePackageActions(
|
||||
return "Pacman database update has been requested";
|
||||
}, "Could not update pacman databases");
|
||||
|
||||
const handleRemove = (): Promise<void> => {
|
||||
if (selectionModel.length === 0) {
|
||||
const handleRemove = useCallback((packages: string[]): Promise<void> => {
|
||||
if (packages.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return performAction(async (repository): Promise<string> => {
|
||||
await client.service.servicePackageRemove(repository, selectionModel);
|
||||
return `Packages ${selectionModel.join(", ")} have been removed`;
|
||||
await client.service.servicePackageRemove(repository, packages);
|
||||
return `Packages ${packages.join(", ")} have been removed`;
|
||||
}, "Could not remove packages");
|
||||
};
|
||||
}, [client, performAction]);
|
||||
|
||||
return {
|
||||
handleRefreshDatabase,
|
||||
|
||||
@@ -30,8 +30,8 @@ export interface UsePackageTableResult {
|
||||
filterModel: GridFilterModel;
|
||||
handleRefreshDatabase: () => Promise<void>;
|
||||
handleReload: () => void;
|
||||
handleRemove: () => Promise<void>;
|
||||
handleUpdate: () => Promise<void>;
|
||||
handleRemove: (packages: string[]) => Promise<void>;
|
||||
handleUpdate: (packages: string[]) => Promise<void>;
|
||||
isAuthorized: boolean;
|
||||
isLoading: boolean;
|
||||
paginationModel: { page: number; pageSize: number };
|
||||
@@ -52,7 +52,7 @@ export interface UsePackageTableResult {
|
||||
export function usePackageTable(): UsePackageTableResult {
|
||||
const { rows, isLoading, isAuthorized, status } = usePackageData();
|
||||
const tableState = useTableState();
|
||||
const actions = usePackageActions(tableState.selectionModel, tableState.setSelectionModel);
|
||||
const actions = usePackageActions();
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
|
||||
Reference in New Issue
Block a user