Add delete measure

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-04-27 21:01:08 -07:00
parent 76b6df79fc
commit 230ae1130f
10 changed files with 570 additions and 25 deletions

View File

@@ -15,6 +15,7 @@ import {
useMutation,
fetchQuery,
useRelayEnvironment,
ConnectionHandler,
} from "react-relay";
import {
AlertTriangle,
@@ -106,6 +107,7 @@ import { MesureViewCreateControlMappingMutation } from "./__generated__/MesureVi
import { MesureViewDeleteControlMappingMutation } from "./__generated__/MesureViewDeleteControlMappingMutation.graphql";
import { MesureViewRisksQuery$data } from "./__generated__/MesureViewRisksQuery.graphql";
import { MesureViewRisksQuery } from "./__generated__/MesureViewRisksQuery.graphql";
import { MesureViewDeleteMesureMutation } from "./__generated__/MesureViewDeleteMesureMutation.graphql";
// Function to format ISO8601 duration to human-readable format
const formatDuration = (isoDuration: string): string => {
@@ -326,6 +328,17 @@ const updateMesureStateMutation = graphql`
}
`;
const deleteMesureMutation = graphql`
mutation MesureViewDeleteMesureMutation(
$input: DeleteMesureInput!
$connections: [ID!]!
) {
deleteMesure(input: $input) {
deletedMesureId @deleteEdge(connections: $connections)
}
}
`;
const organizationQuery = graphql`
query MesureViewOrganizationQuery($organizationId: ID!) {
organization: node(id: $organizationId) {
@@ -477,11 +490,17 @@ function MesureViewContent({
mesureViewQuery,
queryRef
);
const { toast } = useToast();
const { organizationId, mesureId } = useParams();
const navigate = useNavigate();
const { toast } = useToast();
const { organizationId, mesureId } = useParams<{
organizationId: string;
mesureId: string;
}>();
const environment = useRelayEnvironment();
const [commitDeleteMesure, isDeletingMesure] = useMutation<MesureViewDeleteMesureMutation>(deleteMesureMutation);
const [isDeleteMesureOpen, setIsDeleteMesureOpen] = useState(false);
// Add state for main content tabs
const [mainContentTab, setMainContentTab] = useState<string>("tasks");
@@ -1815,32 +1834,70 @@ function MesureViewContent({
return "Very High";
};
const handleDeleteMesure = () => {
setIsDeleteMesureOpen(true);
};
const confirmDeleteMesure = () => {
const connectionId = ConnectionHandler.getConnectionID(
organizationId!,
"MesureListView_mesures"
);
commitDeleteMesure({
variables: {
connections: [connectionId],
input: {
mesureId: mesureId!,
},
},
onCompleted: () => {
toast({
title: "Mesure deleted",
description: "Mesure has been deleted successfully.",
});
navigate(`/organizations/${organizationId}/mesures`);
},
onError: (error) => {
toast({
title: "Error deleting mesure",
description: error.message,
variant: "destructive",
});
},
});
};
return (
<PageTemplate
title={data.mesure.name ?? ""}
title={data.mesure?.name || "Mesure"}
description={data.mesure?.description}
actions={
<div className="flex items-center gap-2">
<Button onClick={handleEditMesure}>Edit Mesure</Button>
<Select
defaultValue={data.mesure.state}
onValueChange={handleMesureStateChange}
<div className="flex gap-2">
<Button
variant="outline"
onClick={handleEditMesure}
>
<SelectTrigger className="w-[160px] h-10 text-sm">
<div
className={`${getStateColor(
data.mesure.state
)} px-2 py-0.5 rounded-sm text-sm w-full text-center`}
>
{formatState(data.mesure.state)}
</div>
</SelectTrigger>
<SelectContent>
<SelectItem value="NOT_STARTED">Not Started</SelectItem>
<SelectItem value="IN_PROGRESS">In Progress</SelectItem>
<SelectItem value="IMPLEMENTED">Implemented</SelectItem>
<SelectItem value="NOT_APPLICABLE">Not Applicable</SelectItem>
</SelectContent>
</Select>
Edit
</Button>
<select
value={data.mesure?.state || ""}
onChange={(e) => handleMesureStateChange(e.target.value)}
className="rounded-full cursor-pointer inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-active-b disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border border-low-b hover:bg-h-tertiary-bg active:bg-p-tertiary-bg focus:bg-tertiary-bg shadow-xs px-2"
>
<option value="">Select state</option>
<option value="NOT_STARTED">Not Started</option>
<option value="IN_PROGRESS">In Progress</option>
<option value="NOT_APPLICABLE">Not Applicable</option>
<option value="IMPLEMENTED">Implemented</option>
</select>
<Button
variant="destructive"
onClick={() => handleDeleteMesure()}
disabled={isDeletingMesure}
>
{isDeletingMesure ? "Deleting..." : "Delete"}
</Button>
</div>
}
>
@@ -3598,6 +3655,33 @@ function MesureViewContent({
</DialogFooter>
</DialogContent>
</Dialog>
{/* Delete Mesure Confirmation Dialog */}
<Dialog open={isDeleteMesureOpen} onOpenChange={setIsDeleteMesureOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Delete Mesure</DialogTitle>
<DialogDescription>
Are you sure you want to delete this mesure? This action cannot be undone.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button
variant="outline"
onClick={() => setIsDeleteMesureOpen(false)}
>
Cancel
</Button>
<Button
variant="destructive"
onClick={confirmDeleteMesure}
disabled={isDeletingMesure}
>
{isDeletingMesure ? "Deleting..." : "Delete"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</PageTemplate>
);
}

View File

@@ -0,0 +1,132 @@
/**
* @generated SignedSource<<d2f54e72111c91de1b3fe8ece42a4f07>>
* @lightSyntaxTransform
* @nogrep
*/
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
import { ConcreteRequest } from 'relay-runtime';
export type DeleteMesureInput = {
mesureId: string;
};
export type MesureViewDeleteMesureMutation$variables = {
connections: ReadonlyArray<string>;
input: DeleteMesureInput;
};
export type MesureViewDeleteMesureMutation$data = {
readonly deleteMesure: {
readonly deletedMesureId: string;
};
};
export type MesureViewDeleteMesureMutation = {
response: MesureViewDeleteMesureMutation$data;
variables: MesureViewDeleteMesureMutation$variables;
};
const node: ConcreteRequest = (function(){
var v0 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "connections"
},
v1 = {
"defaultValue": null,
"kind": "LocalArgument",
"name": "input"
},
v2 = [
{
"kind": "Variable",
"name": "input",
"variableName": "input"
}
],
v3 = {
"alias": null,
"args": null,
"kind": "ScalarField",
"name": "deletedMesureId",
"storageKey": null
};
return {
"fragment": {
"argumentDefinitions": [
(v0/*: any*/),
(v1/*: any*/)
],
"kind": "Fragment",
"metadata": null,
"name": "MesureViewDeleteMesureMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "DeleteMesurePayload",
"kind": "LinkedField",
"name": "deleteMesure",
"plural": false,
"selections": [
(v3/*: any*/)
],
"storageKey": null
}
],
"type": "Mutation",
"abstractKey": null
},
"kind": "Request",
"operation": {
"argumentDefinitions": [
(v1/*: any*/),
(v0/*: any*/)
],
"kind": "Operation",
"name": "MesureViewDeleteMesureMutation",
"selections": [
{
"alias": null,
"args": (v2/*: any*/),
"concreteType": "DeleteMesurePayload",
"kind": "LinkedField",
"name": "deleteMesure",
"plural": false,
"selections": [
(v3/*: any*/),
{
"alias": null,
"args": null,
"filters": null,
"handle": "deleteEdge",
"key": "",
"kind": "ScalarHandle",
"name": "deletedMesureId",
"handleArgs": [
{
"kind": "Variable",
"name": "connections",
"variableName": "connections"
}
]
}
],
"storageKey": null
}
]
},
"params": {
"cacheID": "075b3e2d23906985e70fa5ccd3b623c7",
"id": null,
"metadata": {},
"name": "MesureViewDeleteMesureMutation",
"operationKind": "mutation",
"text": "mutation MesureViewDeleteMesureMutation(\n $input: DeleteMesureInput!\n) {\n deleteMesure(input: $input) {\n deletedMesureId\n }\n}\n"
}
};
})();
(node as any).hash = "abf5ae3a6720522aee6b8d672ac389ef";
export default node;