Skip to content

Commit

Permalink
New task link from the object details view (#5365)
Browse files Browse the repository at this point in the history
* update copy buttons

* remove id in details list

* get description from object instead of schema if possible

* add fragment

* update mock data

* fix hfid

* fix component check

* update tests

* update test

* change the details button to keep the help button as it is

* update fragment

* update node select for filters

* update hfid copied value

* update name select component

* update task filter for node

* lint

* add fragment
  • Loading branch information
pa-lem authored Jan 3, 2025
1 parent 12501ea commit 6044ca2
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 136 deletions.
1 change: 1 addition & 0 deletions changelog/tasks-link.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a new link in the object details button to redirect to the tasks list with a filter for the current object
20 changes: 8 additions & 12 deletions frontend/app/src/components/filters/tasks-filter-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,17 @@ export const TasksFilterForm = forwardRef<FormRef, FilterFormProps>(
ref={ref}
onSubmit={onSubmit}
className={classNames("bg-custom-white flex flex-col flex-1 overflow-auto p-4", className)}
defaultValues={{
branch: currentFilters?.branch,
state: currentFilters?.state,
namespace: currentFilters?.namespace,
name: currentFilters?.name,
}}
{...props}
>
<DropdownField
name="branch"
label="Branch"
items={branchesOptions}
defaultValue={currentFilters?.branch}
/>
<DropdownField name="branch" label="Branch" items={branchesOptions} />

<DropdownField
name="state"
label="State"
items={statesOptions}
defaultValue={currentFilters?.state}
/>
<DropdownField name="state" label="State" items={statesOptions} />

<div className="text-right">
{onCancel && (
Expand Down
98 changes: 98 additions & 0 deletions frontend/app/src/components/form/name-select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { namespacesState, schemaState } from "@/state/atoms/schema.atom";
import { useAtomValue } from "jotai";
import { useEffect } from "react";
import { useFormContext } from "react-hook-form";
import { DEFAULT_FORM_FIELD_VALUE } from "./constants";
import DropdownField from "./fields/dropdown.field";
import { FormAttributeValue } from "./type";
import { isRequired } from "./utils/validation";

export const NameSelect = () => {
const namespaces = useAtomValue(namespacesState);
const nodes = useAtomValue(schemaState);

const form = useFormContext();
const selectedNamespaceField: FormAttributeValue = form.watch("namespace");
const selectedNameField: FormAttributeValue = form.watch("name");

const namespaceOptions = [
{
value: "*",
label: "*",
},
...namespaces.map((namespace) => {
return {
value: namespace.name,
label: namespace.name,
};
}),
];

const selectedNamespace =
selectedNamespaceField?.value === "*"
? { value: "*", name: "*" }
: namespaces
.filter((namespace) => {
if (!selectedNameField?.value) {
return true;
}

return namespace.used_by?.includes(selectedNameField?.value);
})
.find((namespace) => {
return namespace.name === selectedNamespaceField?.value;
});

const nameOptions = [
{
value: "*",
label: "*",
},
...nodes
.filter((node) => {
if (!selectedNamespace || selectedNamespace?.name === "*") return true;

return node.namespace === selectedNamespace?.name;
})
.map((node) => ({
value: node.name,
label: node.label,
badge: node.namespace,
})),
];

useEffect(() => {
// Break if namespace already set
if (selectedNamespaceField?.value) return;

// Break if no name is provided
if (!selectedNameField?.value) return;

// Get current node from form field value
const currentNode = nodes.find((node) => node.name === selectedNameField?.value);
if (!currentNode) return;

form.setValue("namespace", { value: currentNode.namespace, label: currentNode.namespace });
}, [selectedNameField?.value]);

return (
<>
<DropdownField
name={"namespace"}
label="Namespace"
defaultValue={DEFAULT_FORM_FIELD_VALUE}
items={namespaceOptions}
rules={{ validate: { required: isRequired } }}
/>

<DropdownField
key={selectedNamespaceField?.value}
name={"name"}
label="Name"
defaultValue={DEFAULT_FORM_FIELD_VALUE}
items={nameOptions}
rules={{ validate: { required: isRequired } }}
/>
</>
);
};
101 changes: 101 additions & 0 deletions frontend/app/src/components/form/node-select.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { namespacesState, schemaState } from "@/state/atoms/schema.atom";
import { useAtomValue } from "jotai";
import { useEffect } from "react";
import { useFormContext } from "react-hook-form";
import { DEFAULT_FORM_FIELD_VALUE } from "./constants";
import DropdownField from "./fields/dropdown.field";
import { FormAttributeValue } from "./type";

type NodeSelectProps = {
isRequired?: boolean;
};

export const NodeSelect = ({ isRequired }: NodeSelectProps) => {
const namespaces = useAtomValue(namespacesState);
const nodes = useAtomValue(schemaState);

const form = useFormContext();
const selectedNamespaceField: FormAttributeValue = form.watch("namespace");
const selectedNameField: FormAttributeValue = form.watch("name");

const namespaceOptions = [
{
value: "*",
label: "*",
},
...namespaces.map((namespace) => {
return {
value: namespace.name,
label: namespace.name,
};
}),
];

const selectedNamespace =
selectedNamespaceField?.value === "*"
? { value: "*", name: "*" }
: namespaces
.filter((namespace) => {
if (!selectedNameField?.value) {
return true;
}

return namespace.used_by?.includes(selectedNameField?.value);
})
.find((namespace) => {
return namespace.name === selectedNamespaceField?.value;
});

const nameOptions = [
{
value: "*",
label: "*",
},
...nodes
.filter((node) => {
if (!selectedNamespace || selectedNamespace?.name === "*") return true;

return node.namespace === selectedNamespace?.name;
})
.map((node) => ({
value: node.name,
label: node.label,
badge: node.namespace,
})),
];

useEffect(() => {
// Break if namespace already set
if (selectedNamespaceField?.value) return;

// Break if no name is provided
if (!selectedNameField?.value) return;

// Get current node from form field value
const currentNode = nodes.find((node) => node.name === selectedNameField?.value);
if (!currentNode) return;

form.setValue("namespace", { value: currentNode.namespace, label: currentNode.namespace });
}, [selectedNameField?.value]);

return (
<>
<DropdownField
name={"namespace"}
label="Namespace"
defaultValue={DEFAULT_FORM_FIELD_VALUE}
items={namespaceOptions}
rules={{ required: true, validate: { required: isRequired } }}
/>

<DropdownField
key={selectedNamespaceField?.value}
name={"name"}
label="Name"
defaultValue={DEFAULT_FORM_FIELD_VALUE}
items={nameOptions}
rules={{ required: true, validate: { required: isRequired } }}
/>
</>
);
};
23 changes: 23 additions & 0 deletions frontend/app/src/components/menu/object-details-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { QSP } from "@/config/qsp";
import { ReactComponent as TasksStatusIcon } from "@/images/icons/tasks-status.svg";
import { constructPath } from "@/utils/fetch";
import { Icon } from "@iconify-icon/react";
import { Link } from "react-router-dom";
import { CopyToClipboard } from "../buttons/copy-to-clipboard";

interface ObjectDetailsButtonProps extends ButtonProps {
Expand All @@ -15,6 +19,11 @@ interface ObjectDetailsButtonProps extends ButtonProps {
}

export const ObjectDetailsButton = ({ id, hfid, ...props }: ObjectDetailsButtonProps) => {
const taskFilter = {
name: "node__value",
value: id,
};

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
Expand All @@ -39,6 +48,20 @@ export const ObjectDetailsButton = ({ id, hfid, ...props }: ObjectDetailsButtonP
Copy HFID
</CopyToClipboard>
</DropdownMenuItem>

<DropdownMenuItem asChild>
<Link
to={constructPath("/tasks", [
{ name: QSP.FILTER, value: JSON.stringify([taskFilter]) },
])}
target="_blank"
rel="noreferrer"
>
<TasksStatusIcon />
Tasks
<Icon icon="mdi:open-in-new" />
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
Expand Down
Loading

0 comments on commit 6044ca2

Please sign in to comment.