@@ -73,10 +73,7 @@ const createTaskSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
description: z.string().optional().nullable(),
|
||||
timeEstimate: z.string().optional().nullable(),
|
||||
assignedToId: z.preprocess(
|
||||
(val) => (val === "" || val == null ? undefined : val),
|
||||
z.string({ required_error: "Assigned to is required" }).min(1, "Assigned to is required")
|
||||
),
|
||||
assignedToId: z.string().optional().nullable(),
|
||||
measureId: z.preprocess(
|
||||
(val) => (val === "" || val == null ? undefined : val),
|
||||
z.string({ required_error: "Measure is required" }).min(1, "Measure is required")
|
||||
@@ -88,7 +85,7 @@ const updateTaskSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
description: z.string().optional().nullable(),
|
||||
timeEstimate: z.string().optional().nullable(),
|
||||
assignedToId: z.string().optional(),
|
||||
assignedToId: z.string().optional().nullable(),
|
||||
measureId: z.string().optional(),
|
||||
deadline: z.string().optional().nullable(),
|
||||
});
|
||||
@@ -137,6 +134,7 @@ export default function TaskFormDialog(props: Props) {
|
||||
description: data.description || null,
|
||||
timeEstimate: data.timeEstimate || null,
|
||||
deadline: formatDatetime(data.deadline) ?? null,
|
||||
assignedToId: data.assignedToId ?? null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -149,7 +147,7 @@ export default function TaskFormDialog(props: Props) {
|
||||
description: data.description || null,
|
||||
timeEstimate: data.timeEstimate || null,
|
||||
deadline: formatDatetime(data.deadline) ?? null,
|
||||
assignedToId: data.assignedToId,
|
||||
assignedToId: data.assignedToId || null,
|
||||
measureId: data.measureId,
|
||||
},
|
||||
connections: [props.connection!],
|
||||
@@ -165,7 +163,6 @@ export default function TaskFormDialog(props: Props) {
|
||||
dialogRef.current?.close();
|
||||
});
|
||||
const showMeasure = !props.measureId && !isUpdating;
|
||||
const isCreating = !isUpdating;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
@@ -198,18 +195,17 @@ export default function TaskFormDialog(props: Props) {
|
||||
{/* Properties form */}
|
||||
<div className="py-5 px-6 bg-subtle">
|
||||
<Label>{__("Properties")}</Label>
|
||||
{isCreating && (
|
||||
<PropertyRow
|
||||
label={__("Assigned to")}
|
||||
error={formState.errors.assignedToId?.message}
|
||||
>
|
||||
<PeopleSelectField
|
||||
name="assignedToId"
|
||||
control={control}
|
||||
organizationId={organizationId}
|
||||
/>
|
||||
</PropertyRow>
|
||||
)}
|
||||
<PropertyRow
|
||||
label={__("Assigned to")}
|
||||
error={formState.errors.assignedToId?.message}
|
||||
>
|
||||
<PeopleSelectField
|
||||
name="assignedToId"
|
||||
control={control}
|
||||
organizationId={organizationId}
|
||||
optional={true}
|
||||
/>
|
||||
</PropertyRow>
|
||||
{showMeasure && (
|
||||
<PropertyRow
|
||||
label={__("Measure")}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { promisifyMutation } from "@probo/helpers";
|
||||
import { promisifyMutation, formatDate, formatDuration } from "@probo/helpers";
|
||||
import { usePageTitle } from "@probo/hooks";
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import {
|
||||
ActionDropdown,
|
||||
Avatar,
|
||||
Card,
|
||||
DropdownItem,
|
||||
IconArrowCornerDownLeft,
|
||||
@@ -40,6 +39,8 @@ type Props = {
|
||||
name: string;
|
||||
state: "TODO" | "DONE";
|
||||
description?: string | null;
|
||||
timeEstimate?: string | null;
|
||||
deadline?: string | null;
|
||||
measure?: {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -128,7 +129,7 @@ export default function TasksCard({ tasks, connectionId }: Props) {
|
||||
}
|
||||
|
||||
type TaskRowProps = {
|
||||
task: ItemOf<Props["tasks"]> & TaskFormDialogFragment$key;
|
||||
task: ItemOf<Props["tasks"]>;
|
||||
connectionId: string;
|
||||
hasAnyAction: boolean;
|
||||
};
|
||||
@@ -207,30 +208,48 @@ function TaskRow(props: TaskRowProps) {
|
||||
<TaskStateIcon state={props.task.state} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="text-sm space-y-1">
|
||||
<div className="text-sm space-y-1 flex-1">
|
||||
<h2 className="font-medium">{props.task.name}</h2>
|
||||
{props.task.measure && (
|
||||
<p className="text-txt-secondary flex items-center gap-2">
|
||||
<IconArrowCornerDownLeft className="scale-x-[-1]" size={16} />
|
||||
<Link
|
||||
className="hover:underline"
|
||||
to={`/organizations/${organizationId}/measures/${props.task.measure?.id}`}
|
||||
>
|
||||
{props.task.measure?.name}
|
||||
</Link>
|
||||
{props.task.description && (
|
||||
<p className="text-txt-secondary whitespace-pre-wrap break-words">
|
||||
{props.task.description}
|
||||
</p>
|
||||
)}
|
||||
<div className="flex flex-wrap items-center gap-3 text-txt-secondary text-xs">
|
||||
{props.task.measure && (
|
||||
<span className="flex items-center gap-1">
|
||||
<IconArrowCornerDownLeft className="scale-x-[-1]" size={14} />
|
||||
<Link
|
||||
className="hover:underline"
|
||||
to={`/organizations/${organizationId}/measures/${props.task.measure?.id}`}
|
||||
>
|
||||
{props.task.measure?.name}
|
||||
</Link>
|
||||
</span>
|
||||
)}
|
||||
{props.task.timeEstimate && (
|
||||
<span>{formatDuration(props.task.timeEstimate, __)}</span>
|
||||
)}
|
||||
{props.task.deadline && (
|
||||
<time dateTime={props.task.deadline}>
|
||||
{formatDate(props.task.deadline)}
|
||||
</time>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{props.task.assignedTo?.fullName && (
|
||||
<div className="text-sm text-txt-secondary ml-auto mr-8">
|
||||
<Link
|
||||
className="hover:underline"
|
||||
to={`/organizations/${organizationId}/people/${props.task.assignedTo.id}`}
|
||||
>
|
||||
{props.task.assignedTo.fullName}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex gap-2 items-center">
|
||||
{isUpdating && <Spinner size={16} />}
|
||||
{props.task.assignedTo && (
|
||||
<Link
|
||||
to={`/organizations/${organizationId}/people/${props.task.assignedTo?.id}`}
|
||||
>
|
||||
<Avatar name={props.task.assignedTo?.fullName ?? ""} />
|
||||
</Link>
|
||||
)}
|
||||
{props.hasAnyAction && (
|
||||
<ActionDropdown>
|
||||
{isAuthorized("Task", "updateTask") && (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<1cc9998f8dcbb02ac977744023d372d6>>
|
||||
* @generated SignedSource<<1d9eed2918f5f58de18ef4ea5f0058b7>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -12,6 +12,7 @@ import { ConcreteRequest } from 'relay-runtime';
|
||||
import { FragmentRefs } from "relay-runtime";
|
||||
export type TaskState = "DONE" | "TODO";
|
||||
export type UpdateTaskInput = {
|
||||
assignedToId?: string | null | undefined;
|
||||
deadline?: any | null | undefined;
|
||||
description?: string | null | undefined;
|
||||
name?: string | null | undefined;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<cff26152bf46e7734e8ae5f5671b47b6>>
|
||||
* @generated SignedSource<<40ebf241dc89f4b4b1705e4a2fabb935>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -296,12 +296,12 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "a0b3367a3288c70f0bbcde73ec237bee",
|
||||
"cacheID": "72cbeaa7667c477f85e5c3ecb09b7bf4",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "TaskGraphQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query TaskGraphQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n ...TasksPageFragment\n }\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n\nfragment TasksPageFragment on Organization {\n tasks(first: 500) {\n edges {\n node {\n id\n name\n state\n description\n ...TaskFormDialogFragment\n measure {\n id\n name\n }\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
|
||||
"text": "query TaskGraphQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n ...TasksPageFragment\n }\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n\nfragment TasksPageFragment on Organization {\n tasks(first: 500) {\n edges {\n node {\n id\n name\n state\n description\n timeEstimate\n deadline\n ...TaskFormDialogFragment\n measure {\n id\n name\n }\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -20,6 +20,8 @@ const tasksQuery = graphql`
|
||||
name
|
||||
state
|
||||
description
|
||||
timeEstimate
|
||||
deadline
|
||||
...TaskFormDialogFragment
|
||||
assignedTo {
|
||||
id
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<f2e7ca902ae7ee08f260f27a0fefa043>>
|
||||
* @generated SignedSource<<f1100222ab7c7aeff0f7643640ecc23c>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -25,10 +25,12 @@ export type MeasureTasksTabQuery$data = {
|
||||
readonly fullName: string;
|
||||
readonly id: string;
|
||||
} | null | undefined;
|
||||
readonly deadline: any | null | undefined;
|
||||
readonly description: string | null | undefined;
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly state: TaskState;
|
||||
readonly timeEstimate: any | null | undefined;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"TaskFormDialogFragment">;
|
||||
};
|
||||
}>;
|
||||
@@ -84,6 +86,20 @@ v5 = {
|
||||
"storageKey": null
|
||||
},
|
||||
v6 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "timeEstimate",
|
||||
"storageKey": null
|
||||
},
|
||||
v7 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "deadline",
|
||||
"storageKey": null
|
||||
},
|
||||
v8 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "People",
|
||||
@@ -102,21 +118,21 @@ v6 = {
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
v7 = {
|
||||
v9 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
},
|
||||
v8 = {
|
||||
v10 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
},
|
||||
v9 = {
|
||||
v11 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
@@ -141,7 +157,7 @@ v9 = {
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
v10 = {
|
||||
v12 = {
|
||||
"kind": "ClientExtension",
|
||||
"selections": [
|
||||
{
|
||||
@@ -153,7 +169,7 @@ v10 = {
|
||||
}
|
||||
]
|
||||
},
|
||||
v11 = [
|
||||
v13 = [
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
@@ -207,22 +223,24 @@ return {
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
(v5/*: any*/),
|
||||
(v6/*: any*/),
|
||||
(v7/*: any*/),
|
||||
{
|
||||
"args": null,
|
||||
"kind": "FragmentSpread",
|
||||
"name": "TaskFormDialogFragment"
|
||||
},
|
||||
(v6/*: any*/),
|
||||
(v7/*: any*/)
|
||||
(v8/*: any*/),
|
||||
(v9/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v8/*: any*/)
|
||||
(v10/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v9/*: any*/),
|
||||
(v10/*: any*/)
|
||||
(v11/*: any*/),
|
||||
(v12/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
@@ -251,14 +269,14 @@ return {
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v7/*: any*/),
|
||||
(v9/*: any*/),
|
||||
(v2/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v11/*: any*/),
|
||||
"args": (v13/*: any*/),
|
||||
"concreteType": "TaskConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "tasks",
|
||||
@@ -284,21 +302,9 @@ return {
|
||||
(v3/*: any*/),
|
||||
(v4/*: any*/),
|
||||
(v5/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "timeEstimate",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "deadline",
|
||||
"storageKey": null
|
||||
},
|
||||
(v6/*: any*/),
|
||||
(v7/*: any*/),
|
||||
(v8/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
@@ -311,22 +317,22 @@ return {
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v7/*: any*/)
|
||||
(v9/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v8/*: any*/)
|
||||
(v10/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
(v9/*: any*/),
|
||||
(v10/*: any*/)
|
||||
(v11/*: any*/),
|
||||
(v12/*: any*/)
|
||||
],
|
||||
"storageKey": "tasks(first:100)"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v11/*: any*/),
|
||||
"args": (v13/*: any*/),
|
||||
"filters": null,
|
||||
"handle": "connection",
|
||||
"key": "Measure__tasks",
|
||||
@@ -343,7 +349,7 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "bc71d01128d96026a1e630b96e649409",
|
||||
"cacheID": "7988e2a18d5929fe99d9cef8de244627",
|
||||
"id": null,
|
||||
"metadata": {
|
||||
"connection": [
|
||||
@@ -360,11 +366,11 @@ return {
|
||||
},
|
||||
"name": "MeasureTasksTabQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query MeasureTasksTabQuery(\n $measureId: ID!\n) {\n node(id: $measureId) {\n __typename\n ... on Measure {\n id\n tasks(first: 100) {\n edges {\n node {\n id\n name\n state\n description\n ...TaskFormDialogFragment\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n"
|
||||
"text": "query MeasureTasksTabQuery(\n $measureId: ID!\n) {\n node(id: $measureId) {\n __typename\n ... on Measure {\n id\n tasks(first: 100) {\n edges {\n node {\n id\n name\n state\n description\n timeEstimate\n deadline\n ...TaskFormDialogFragment\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "12445eb032af3bc00fea9edce6f427e2";
|
||||
(node as any).hash = "358a07bb3e13ea9828d0703541caf894";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -39,6 +39,8 @@ const tasksFragment = graphql`
|
||||
name
|
||||
state
|
||||
description
|
||||
timeEstimate
|
||||
deadline
|
||||
...TaskFormDialogFragment
|
||||
measure {
|
||||
id
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<8bba8d318de0f4b0d28a8fba8b8e0bdf>>
|
||||
* @generated SignedSource<<f6e71f80c25925eb372e360c1b9ec122>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -21,6 +21,7 @@ export type TasksPageFragment$data = {
|
||||
readonly fullName: string;
|
||||
readonly id: string;
|
||||
} | null | undefined;
|
||||
readonly deadline: any | null | undefined;
|
||||
readonly description: string | null | undefined;
|
||||
readonly id: string;
|
||||
readonly measure: {
|
||||
@@ -29,6 +30,7 @@ export type TasksPageFragment$data = {
|
||||
} | null | undefined;
|
||||
readonly name: string;
|
||||
readonly state: TaskState;
|
||||
readonly timeEstimate: any | null | undefined;
|
||||
readonly " $fragmentSpreads": FragmentRefs<"TaskFormDialogFragment">;
|
||||
};
|
||||
}>;
|
||||
@@ -168,6 +170,20 @@ return {
|
||||
"name": "description",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "timeEstimate",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "deadline",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"args": null,
|
||||
"kind": "FragmentSpread",
|
||||
@@ -286,6 +302,6 @@ return {
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "84864638db9ddf53e9ae7da7952803af";
|
||||
(node as any).hash = "466d3b82119334991a0714bb0b7cd6d0";
|
||||
|
||||
export default node;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @generated SignedSource<<46a3b0baa64ec5a6a1c6d289a3737ade>>
|
||||
* @generated SignedSource<<e765e52f0386640e282459c13a3e9769>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
@@ -369,16 +369,16 @@ return {
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "58db4c11a870b12c21eef1c6f24271b0",
|
||||
"cacheID": "d31450ee0ddd09b0e08b43c9f7728f5f",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "TasksPageFragment_query",
|
||||
"operationKind": "query",
|
||||
"text": "query TasksPageFragment_query(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 500\n $last: Int = null\n $order: TaskOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...TasksPageFragment_16fISc\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n\nfragment TasksPageFragment_16fISc on Organization {\n tasks(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n name\n state\n description\n ...TaskFormDialogFragment\n measure {\n id\n name\n }\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
|
||||
"text": "query TasksPageFragment_query(\n $after: CursorKey = null\n $before: CursorKey = null\n $first: Int = 500\n $last: Int = null\n $order: TaskOrder = null\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...TasksPageFragment_16fISc\n id\n }\n}\n\nfragment TaskFormDialogFragment on Task {\n id\n description\n name\n state\n timeEstimate\n deadline\n assignedTo {\n id\n }\n measure {\n id\n }\n}\n\nfragment TasksPageFragment_16fISc on Organization {\n tasks(first: $first, after: $after, last: $last, before: $before, orderBy: $order) {\n edges {\n node {\n id\n name\n state\n description\n timeEstimate\n deadline\n ...TaskFormDialogFragment\n measure {\n id\n name\n }\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n hasPreviousPage\n startCursor\n }\n }\n id\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "84864638db9ddf53e9ae7da7952803af";
|
||||
(node as any).hash = "466d3b82119334991a0714bb0b7cd6d0";
|
||||
|
||||
export default node;
|
||||
|
||||
Reference in New Issue
Block a user