@@ -54,6 +54,7 @@ function VendorBadge({
|
|||||||
<button
|
<button
|
||||||
onClick={() => onRemove(vendor)}
|
onClick={() => onRemove(vendor)}
|
||||||
className="size-4 hover:text-txt-primary cursor-pointer"
|
className="size-4 hover:text-txt-primary cursor-pointer"
|
||||||
|
type="button"
|
||||||
>
|
>
|
||||||
<IconCrossLargeX size={14} />
|
<IconCrossLargeX size={14} />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -121,17 +121,13 @@ export const deleteAssetMutation = graphql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const useDeleteAsset = (
|
export const useDeleteAsset = (
|
||||||
asset?: { id?: string; name?: string },
|
asset: { id?: string; name?: string },
|
||||||
connectionId?: string,
|
connectionId: string,
|
||||||
) => {
|
) => {
|
||||||
const [mutate] = useMutation(deleteAssetMutation);
|
const [mutate] = useMutation(deleteAssetMutation);
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
|
|
||||||
if (!asset) {
|
|
||||||
return () => {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (!asset.id || !asset.name) {
|
if (!asset.id || !asset.name) {
|
||||||
return alert(__("Failed to delete asset: missing id or name"));
|
return alert(__("Failed to delete asset: missing id or name"));
|
||||||
@@ -141,7 +137,7 @@ export const useDeleteAsset = (
|
|||||||
promisifyMutation(mutate)({
|
promisifyMutation(mutate)({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
assetId: asset.id!,
|
assetId: asset.id,
|
||||||
},
|
},
|
||||||
connections: [connectionId],
|
connections: [connectionId],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,13 +1,5 @@
|
|||||||
import {
|
import { getAssetTypeVariant, validateSnapshotConsistency } from "@probo/helpers";
|
||||||
ConnectionHandler,
|
import { useTranslate } from "@probo/i18n";
|
||||||
usePreloadedQuery,
|
|
||||||
type PreloadedQuery,
|
|
||||||
} from "react-relay";
|
|
||||||
import {
|
|
||||||
assetNodeQuery,
|
|
||||||
useDeleteAsset,
|
|
||||||
useUpdateAsset,
|
|
||||||
} from "../../../hooks/graph/AssetGraph";
|
|
||||||
import {
|
import {
|
||||||
ActionDropdown,
|
ActionDropdown,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -18,16 +10,25 @@ import {
|
|||||||
IconTrashCan,
|
IconTrashCan,
|
||||||
Option,
|
Option,
|
||||||
} from "@probo/ui";
|
} from "@probo/ui";
|
||||||
import { useTranslate } from "@probo/i18n";
|
import {
|
||||||
import { useOrganizationId } from "/hooks/useOrganizationId";
|
ConnectionHandler,
|
||||||
|
usePreloadedQuery,
|
||||||
|
type PreloadedQuery,
|
||||||
|
} from "react-relay";
|
||||||
import { useParams } from "react-router";
|
import { useParams } from "react-router";
|
||||||
|
import z from "zod";
|
||||||
|
import {
|
||||||
|
assetNodeQuery,
|
||||||
|
useDeleteAsset,
|
||||||
|
useUpdateAsset,
|
||||||
|
} from "../../../hooks/graph/AssetGraph";
|
||||||
|
import { SnapshotBanner } from "/components/SnapshotBanner";
|
||||||
import { ControlledField } from "/components/form/ControlledField";
|
import { ControlledField } from "/components/form/ControlledField";
|
||||||
import { PeopleSelectField } from "/components/form/PeopleSelectField";
|
import { PeopleSelectField } from "/components/form/PeopleSelectField";
|
||||||
import { VendorsMultiSelectField } from "/components/form/VendorsMultiSelectField";
|
import { VendorsMultiSelectField } from "/components/form/VendorsMultiSelectField";
|
||||||
|
import type { AssetGraphNodeQuery } from "/hooks/graph/__generated__/AssetGraphNodeQuery.graphql";
|
||||||
import { useFormWithSchema } from "/hooks/useFormWithSchema";
|
import { useFormWithSchema } from "/hooks/useFormWithSchema";
|
||||||
import z from "zod";
|
import { useOrganizationId } from "/hooks/useOrganizationId";
|
||||||
import { getAssetTypeVariant, validateSnapshotConsistency } from "@probo/helpers";
|
|
||||||
import { SnapshotBanner } from "/components/SnapshotBanner";
|
|
||||||
import { Authorized } from "/permissions";
|
import { Authorized } from "/permissions";
|
||||||
|
|
||||||
const updateAssetSchema = z.object({
|
const updateAssetSchema = z.object({
|
||||||
@@ -40,18 +41,18 @@ const updateAssetSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
queryRef: PreloadedQuery<any>;
|
queryRef: PreloadedQuery<AssetGraphNodeQuery>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function AssetDetailsPage(props: Props) {
|
export default function AssetDetailsPage(props: Props) {
|
||||||
const asset = usePreloadedQuery(assetNodeQuery, props.queryRef);
|
const asset = usePreloadedQuery<AssetGraphNodeQuery>(assetNodeQuery, props.queryRef);
|
||||||
const assetEntry = asset.node;
|
const assetEntry = asset.node;
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const { snapshotId } = useParams<{ snapshotId?: string }>();
|
const { snapshotId } = useParams<{ snapshotId?: string }>();
|
||||||
const isSnapshotMode = Boolean(snapshotId);
|
const isSnapshotMode = Boolean(snapshotId);
|
||||||
|
|
||||||
if (!assetEntry) {
|
if (!assetEntry || !assetEntry.id) {
|
||||||
return <div>{__("Asset not found")}</div>;
|
return <div>{__("Asset not found")}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,16 +65,16 @@ export default function AssetDetailsPage(props: Props) {
|
|||||||
);
|
);
|
||||||
const deleteAsset = useDeleteAsset(assetEntry, connectionId);
|
const deleteAsset = useDeleteAsset(assetEntry, connectionId);
|
||||||
|
|
||||||
const vendors = assetEntry?.vendors?.edges.map((edge: any) => edge.node) ?? [];
|
const vendors = assetEntry.vendors?.edges.map((edge: any) => edge.node) ?? [];
|
||||||
const vendorIds = vendors.map((vendor: any) => vendor.id);
|
const vendorIds = vendors.map((vendor: any) => vendor.id);
|
||||||
|
|
||||||
const { control, formState, handleSubmit, register, reset } = useFormWithSchema(updateAssetSchema, {
|
const { control, formState, handleSubmit, register, reset } = useFormWithSchema(updateAssetSchema, {
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: assetEntry?.name || "",
|
name: assetEntry.name || "",
|
||||||
amount: assetEntry?.amount || 0,
|
amount: assetEntry.amount || 0,
|
||||||
assetType: assetEntry?.assetType || "VIRTUAL",
|
assetType: assetEntry.assetType || "VIRTUAL",
|
||||||
dataTypesStored: assetEntry?.dataTypesStored || "",
|
dataTypesStored: assetEntry.dataTypesStored || "",
|
||||||
ownerId: assetEntry?.owner?.id || "",
|
ownerId: assetEntry.owner?.id || "",
|
||||||
vendorIds: vendorIds,
|
vendorIds: vendorIds,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -82,7 +83,7 @@ export default function AssetDetailsPage(props: Props) {
|
|||||||
|
|
||||||
const onSubmit = handleSubmit(async (formData) => {
|
const onSubmit = handleSubmit(async (formData) => {
|
||||||
await updateAsset({
|
await updateAsset({
|
||||||
id: assetEntry?.id,
|
id: assetEntry.id!,
|
||||||
...formData,
|
...formData,
|
||||||
});
|
});
|
||||||
reset(formData);
|
reset(formData);
|
||||||
@@ -110,7 +111,7 @@ export default function AssetDetailsPage(props: Props) {
|
|||||||
<div className="flex justify-between items-start">
|
<div className="flex justify-between items-start">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<div className="text-2xl">{assetEntry?.name}</div>
|
<div className="text-2xl">{assetEntry?.name}</div>
|
||||||
<Badge variant={getAssetTypeVariant(assetEntry?.assetType)}>
|
<Badge variant={getAssetTypeVariant(assetEntry?.assetType ?? "VIRTUAL")}>
|
||||||
{assetEntry?.assetType === "PHYSICAL" ? __("Physical") : __("Virtual")}
|
{assetEntry?.assetType === "PHYSICAL" ? __("Physical") : __("Virtual")}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -97,7 +97,11 @@ export function RowButton({
|
|||||||
"py-2 bg-highlight hover:bg-highlight-hover active:bg-highlight-pressed cursor-pointer w-full flex gap-2 items-center justify-center text-sm text-txt-secondary",
|
"py-2 bg-highlight hover:bg-highlight-hover active:bg-highlight-pressed cursor-pointer w-full flex gap-2 items-center justify-center text-sm text-txt-secondary",
|
||||||
props.className,
|
props.className,
|
||||||
)}
|
)}
|
||||||
style={{ gridColumnEnd: -1, gridColumnStart: 1 }}
|
style={{
|
||||||
|
gridColumnEnd: -1,
|
||||||
|
gridColumnStart: 1,
|
||||||
|
...props.style,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<IconComponent size={16} />
|
<IconComponent size={16} />
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -146,12 +146,13 @@ export function Select<T>({
|
|||||||
<Content
|
<Content
|
||||||
position="popper"
|
position="popper"
|
||||||
sideOffset={5}
|
sideOffset={5}
|
||||||
|
{...dropdownProps}
|
||||||
style={{
|
style={{
|
||||||
minWidth: "var(--radix-select-trigger-width)",
|
minWidth: "var(--radix-select-trigger-width)",
|
||||||
maxHeight:
|
maxHeight:
|
||||||
"var(--radix-select-content-available-height)",
|
"var(--radix-select-content-available-height)",
|
||||||
|
...dropdownProps?.style,
|
||||||
}}
|
}}
|
||||||
{...dropdownProps}
|
|
||||||
className={content({ className: dropdownProps?.className })}
|
className={content({ className: dropdownProps?.className })}
|
||||||
>
|
>
|
||||||
{onSearch && (
|
{onSearch && (
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ export function TextCell(props: Props) {
|
|||||||
if (props.required && inputValue === "") {
|
if (props.required && inputValue === "") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (inputValue !== props.defaultValue) {
|
||||||
setValue(inputValue);
|
setValue(inputValue);
|
||||||
onUpdate(props.name, inputValue);
|
onUpdate(props.name, inputValue);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user