feat: add multi-select functionality across various pages
- Implemented checkbox selection for multiple items in DeploymentRulesPage, DomainsPage, EnvironmentsPage, ServicesPage, TargetsPage, TemplateCategoriesPage, and TemplatesPage. - Added delete functionality for selected items with confirmation prompts. - Updated state management to handle selected IDs for batch operations. - Enhanced UI with a toolbar for actions related to selected items. - Adjusted API calls to accommodate changes in data structure, including deployment requests and job details.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Combobox,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
@@ -66,6 +67,7 @@ export function TargetsPage() {
|
||||
const [providerType, setProviderType] = useState("OnPrem");
|
||||
const [externalId, setExternalId] = useState("");
|
||||
const [metadataJson, setMetadataJson] = useState("");
|
||||
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
||||
|
||||
const { data, error, isLoading } = useQuery({
|
||||
queryKey: ["targets"],
|
||||
@@ -132,6 +134,15 @@ export function TargetsPage() {
|
||||
await queryClient.invalidateQueries({ queryKey: ["targets"] });
|
||||
},
|
||||
});
|
||||
const deleteSelectedTargets = useMutation({
|
||||
mutationFn: async (ids: string[]) => {
|
||||
await Promise.all(ids.map((id) => portalApi.deleteTarget(id)));
|
||||
},
|
||||
onSuccess: async () => {
|
||||
setSelectedIds([]);
|
||||
await queryClient.invalidateQueries({ queryKey: ["targets"] });
|
||||
},
|
||||
});
|
||||
|
||||
const linkTargetToDomain = useMutation({
|
||||
mutationFn: ({ targetId, targetDomainId }: { targetId: string; targetDomainId: string }) =>
|
||||
@@ -172,6 +183,10 @@ export function TargetsPage() {
|
||||
const domainNameById = new Map((domains ?? []).map((domain: Domain) => [domain.id, domain.name]));
|
||||
const linkedTargets = (data ?? []).filter((target) => Boolean(target.domainID));
|
||||
const unlinkedTargets = (data ?? []).filter((target) => !target.domainID);
|
||||
const allSelected = Boolean(data?.length) && data!.every((target) => selectedIds.includes(target.id));
|
||||
const toggleSelected = (id: string, checked: boolean) => {
|
||||
setSelectedIds((current) => (checked ? [...new Set([...current, id])] : current.filter((entry) => entry !== id)));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -203,6 +218,19 @@ export function TargetsPage() {
|
||||
>
|
||||
Unlink Domain
|
||||
</Button>
|
||||
<Button
|
||||
appearance="secondary"
|
||||
disabled={selectedIds.length === 0 || deleteSelectedTargets.isPending}
|
||||
icon={<DeleteRegular />}
|
||||
onClick={() => {
|
||||
if (window.confirm(`${selectedIds.length} Targets wirklich loeschen?`)) {
|
||||
deleteSelectedTargets.mutate(selectedIds);
|
||||
}
|
||||
}}
|
||||
style={{ marginLeft: "10px" }}
|
||||
>
|
||||
Auswahl loeschen
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Dialog open={dialogMode !== null} onOpenChange={(_, dialogData) => !dialogData.open && closeDialog()}>
|
||||
@@ -373,12 +401,18 @@ export function TargetsPage() {
|
||||
|
||||
<DataState
|
||||
isLoading={isLoading || domainsLoading}
|
||||
error={error ?? domainsError ?? deleteTarget.error ?? linkTargetToDomain.error ?? unlinkTargetFromDomain.error}
|
||||
error={error ?? domainsError ?? deleteTarget.error ?? deleteSelectedTargets.error ?? linkTargetToDomain.error ?? unlinkTargetFromDomain.error}
|
||||
/>
|
||||
{data && (
|
||||
<Table aria-label="Targets">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHeaderCell>
|
||||
<Checkbox
|
||||
checked={allSelected}
|
||||
onChange={(_, checkboxData) => setSelectedIds(checkboxData.checked ? data.map((target) => target.id) : [])}
|
||||
/>
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell>Name</TableHeaderCell>
|
||||
<TableHeaderCell>Type</TableHeaderCell>
|
||||
<TableHeaderCell>Provider</TableHeaderCell>
|
||||
@@ -391,6 +425,12 @@ export function TargetsPage() {
|
||||
<TableBody>
|
||||
{data.map((target) => (
|
||||
<TableRow key={target.id}>
|
||||
<TableCell>
|
||||
<Checkbox
|
||||
checked={selectedIds.includes(target.id)}
|
||||
onChange={(_, checkboxData) => toggleSelected(target.id, Boolean(checkboxData.checked))}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>{target.name}</TableCell>
|
||||
<TableCell>{target.targetType}</TableCell>
|
||||
<TableCell>{target.providerType}</TableCell>
|
||||
|
||||
Reference in New Issue
Block a user