Eliminar un activo
This commit is contained in:
parent
45b559ab92
commit
5dfb50e13a
@ -87,6 +87,15 @@ export async function verifyInventory(
|
|||||||
assert.equal(created.history[0]?.id.charAt(14), "7");
|
assert.equal(created.history[0]?.id.charAt(14), "7");
|
||||||
assert.ok(created.history[0]?.actorName);
|
assert.ok(created.history[0]?.actorName);
|
||||||
assert.ok(created.history[0]?.actorId);
|
assert.ok(created.history[0]?.actorId);
|
||||||
|
const disposable = await save(path, { ...input, name: "MON-ELIMINAR" });
|
||||||
|
const deletion = await request(`${path}/${disposable.id}/delete`, {});
|
||||||
|
|
||||||
|
assert.equal(deletion.status, 200, await deletion.clone().text());
|
||||||
|
assert.equal(AssetResponseSchema.parse(await deletion.json()).asset.id, disposable.id);
|
||||||
|
assert.equal(
|
||||||
|
(await read()).assets.some((asset) => asset.id === disposable.id),
|
||||||
|
false
|
||||||
|
);
|
||||||
assert.equal((await read(`/assets/${otherId}`)).assets.length, 0);
|
assert.equal((await read(`/assets/${otherId}`)).assets.length, 0);
|
||||||
await error(`/assets/${otherId}/${created.id}/update`, input, "ASSET_NOT_FOUND", 404);
|
await error(`/assets/${otherId}/${created.id}/update`, input, "ASSET_NOT_FOUND", 404);
|
||||||
await error(path, { ...input, siteId: foreignSite.id }, "SITE_NOT_FOUND", 404);
|
await error(path, { ...input, siteId: foreignSite.id }, "SITE_NOT_FOUND", 404);
|
||||||
|
|||||||
@ -21,6 +21,10 @@ export type InventoryContext = Readonly<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
export interface IAssetRepository {
|
export interface IAssetRepository {
|
||||||
|
remove(
|
||||||
|
company: UniqueID,
|
||||||
|
id: UniqueID
|
||||||
|
): Promise<Result<{ asset: Asset; actorNames: ReadonlyMap<string, string> }, AssetCatalogError>>;
|
||||||
removeRelationship(company: UniqueID, id: UniqueID): Promise<Result<void, AssetCatalogError>>;
|
removeRelationship(company: UniqueID, id: UniqueID): Promise<Result<void, AssetCatalogError>>;
|
||||||
saveWorkstation(
|
saveWorkstation(
|
||||||
companyId: UniqueID,
|
companyId: UniqueID,
|
||||||
|
|||||||
@ -22,6 +22,17 @@ export class AssetUseCases {
|
|||||||
return this.repository.get(company.data);
|
return this.repository.get(company.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remove(companyId: string, id: string) {
|
||||||
|
const company = UniqueID.create(companyId);
|
||||||
|
const identity = UniqueID.create(id);
|
||||||
|
|
||||||
|
if (!(company.isSuccess && identity.isSuccess)) {
|
||||||
|
return Promise.resolve(Result.fail(new AssetCatalogError("INVALID_REQUEST")));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.repository.remove(company.data, identity.data);
|
||||||
|
}
|
||||||
|
|
||||||
save(companyId: string, id: string | undefined, input: AssetInput, actorId: string) {
|
save(companyId: string, id: string | undefined, input: AssetInput, actorId: string) {
|
||||||
const company = UniqueID.create(companyId);
|
const company = UniqueID.create(companyId);
|
||||||
const actor = UniqueID.create(actorId);
|
const actor = UniqueID.create(actorId);
|
||||||
|
|||||||
@ -55,6 +55,32 @@ export function registerAssetRoutes(
|
|||||||
})
|
})
|
||||||
.catch(next);
|
.catch(next);
|
||||||
});
|
});
|
||||||
|
router.post("/:companyId/:id/delete", (request, response, next) => {
|
||||||
|
const params = AssetParamsSchema.safeParse(request.params);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
params.success &&
|
||||||
|
z.strictObject({}).safeParse(request.query).success &&
|
||||||
|
z.strictObject({}).safeParse(request.body).success
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
fail(response, "INVALID_REQUEST");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
useCases
|
||||||
|
.remove(params.data.companyId, params.data.id)
|
||||||
|
.then((result) => {
|
||||||
|
if (!result.isSuccess) {
|
||||||
|
fail(response, result.error.code);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.json({ asset: buildAssetResponse(result.data.asset, result.data.actorNames) });
|
||||||
|
})
|
||||||
|
.catch(next);
|
||||||
|
});
|
||||||
for (const path of ["/:companyId", "/:companyId/:id/update"]) {
|
for (const path of ["/:companyId", "/:companyId/:id/update"]) {
|
||||||
router.post(path, (request, response, next) => {
|
router.post(path, (request, response, next) => {
|
||||||
const params = (
|
const params = (
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { AssetCatalogPersistenceMapper } from "./asset-catalog-persistence.mappe
|
|||||||
import { readBindings, readDefinitions } from "./asset-catalog-relational";
|
import { readBindings, readDefinitions } from "./asset-catalog-relational";
|
||||||
import { readInventory, writeInventory } from "./asset-inventory-relational";
|
import { readInventory, writeInventory } from "./asset-inventory-relational";
|
||||||
import { AssetPersistenceMapper, inventoryIdentity } from "./asset-persistence.mapper";
|
import { AssetPersistenceMapper, inventoryIdentity } from "./asset-persistence.mapper";
|
||||||
|
import { sqlIdentifier } from "./asset-relational-sql";
|
||||||
import { RelationshipModel } from "./asset-relationship.model";
|
import { RelationshipModel } from "./asset-relationship.model";
|
||||||
import { AssetRelationshipPersistenceMapper } from "./asset-relationship-persistence.mapper";
|
import { AssetRelationshipPersistenceMapper } from "./asset-relationship-persistence.mapper";
|
||||||
import { loadWorkstations } from "./load-workstations";
|
import { loadWorkstations } from "./load-workstations";
|
||||||
@ -186,6 +187,78 @@ export class SequelizeAssetRepository implements IAssetRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async hasExternalReferences(assetId: string, transaction: Transaction) {
|
||||||
|
const references = await this.database.query<{ tableName: string; columnName: string }>(
|
||||||
|
"SELECT TABLE_NAME AS tableName,COLUMN_NAME AS columnName FROM information_schema.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_SCHEMA=DATABASE() AND REFERENCED_TABLE_NAME='assets' AND REFERENCED_COLUMN_NAME='id'",
|
||||||
|
{ type: QueryTypes.SELECT, transaction }
|
||||||
|
);
|
||||||
|
const ownedTables = new Set([
|
||||||
|
"asset_characteristics",
|
||||||
|
"asset_revision_characteristics",
|
||||||
|
"asset_revisions",
|
||||||
|
"asset_specification_field_choices",
|
||||||
|
"asset_specification_fields",
|
||||||
|
"asset_specification_sections",
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (const reference of references) {
|
||||||
|
if (ownedTables.has(reference.tableName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const rows = await this.database.query<{ value: number }>(
|
||||||
|
`SELECT 1 AS value FROM ${sqlIdentifier(reference.tableName)} WHERE ${sqlIdentifier(reference.columnName)}=:assetId LIMIT 1`,
|
||||||
|
{ replacements: { assetId }, type: QueryTypes.SELECT, transaction }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rows.length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async removeInventory(assetId: string, companyId: string, transaction: Transaction) {
|
||||||
|
for (const table of [
|
||||||
|
"asset_revision_characteristics",
|
||||||
|
"asset_characteristics",
|
||||||
|
"asset_specification_field_choices",
|
||||||
|
"asset_specification_fields",
|
||||||
|
"asset_specification_sections",
|
||||||
|
"asset_revisions",
|
||||||
|
]) {
|
||||||
|
await this.database.query(`DELETE FROM ${sqlIdentifier(table)} WHERE assetId=:assetId`, {
|
||||||
|
replacements: { assetId },
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await this.database.query("DELETE FROM assets WHERE companyId=:companyId AND id=:assetId", {
|
||||||
|
replacements: { assetId, companyId },
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(companyId: UniqueID, id: UniqueID) {
|
||||||
|
return this.database.transaction(async (transaction) => {
|
||||||
|
const loaded = await this.load(companyId, transaction, true);
|
||||||
|
|
||||||
|
if (!loaded.isSuccess) {
|
||||||
|
return Result.fail(loaded.error);
|
||||||
|
}
|
||||||
|
const asset = loaded.data.assets.find((item) => item.id.equals(id));
|
||||||
|
|
||||||
|
if (!asset) {
|
||||||
|
return Result.fail(new AssetCatalogError("ASSET_NOT_FOUND"));
|
||||||
|
}
|
||||||
|
if (await this.hasExternalReferences(id.toPrimitive(), transaction)) {
|
||||||
|
return Result.fail(new AssetCatalogError("ASSET_IN_USE"));
|
||||||
|
}
|
||||||
|
await this.removeInventory(id.toPrimitive(), companyId.toPrimitive(), transaction);
|
||||||
|
|
||||||
|
return Result.ok({ asset, actorNames: loaded.data.actorNames });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
removeRelationship(company: UniqueID, id: UniqueID): Promise<Result<void, AssetCatalogError>> {
|
removeRelationship(company: UniqueID, id: UniqueID): Promise<Result<void, AssetCatalogError>> {
|
||||||
return this.database.transaction(async (transaction) => {
|
return this.database.transaction(async (transaction) => {
|
||||||
await this.database.query("SELECT id FROM companies WHERE id=:companyId FOR UPDATE", {
|
await this.database.query("SELECT id FROM companies WHERE id=:companyId FOR UPDATE", {
|
||||||
|
|||||||
@ -90,6 +90,10 @@
|
|||||||
"relatedNotice": "This item is saved separately and remains available if you later cancel the main form.",
|
"relatedNotice": "This item is saved separately and remains available if you later cancel the main form.",
|
||||||
"newAsset": "New asset",
|
"newAsset": "New asset",
|
||||||
"editAsset": "Edit asset",
|
"editAsset": "Edit asset",
|
||||||
|
"deleteAsset": "Delete asset",
|
||||||
|
"deleteAssetDescription": "The asset “{{name}}” and its history will be deleted. It cannot be deleted while it is linked to other records.",
|
||||||
|
"deletingAsset": "Deleting asset…",
|
||||||
|
"deleteAssetError": "The asset could not be deleted. Please try again.",
|
||||||
"viewAsset": "Details and history",
|
"viewAsset": "Details and history",
|
||||||
"template": "Template",
|
"template": "Template",
|
||||||
"site": "Site",
|
"site": "Site",
|
||||||
@ -123,6 +127,7 @@
|
|||||||
"INVALID_MEMBERS": "Select distinct valid assets.",
|
"INVALID_MEMBERS": "Select distinct valid assets.",
|
||||||
"WORKSTATION_NOT_FOUND": "Workstation not found in this company.",
|
"WORKSTATION_NOT_FOUND": "Workstation not found in this company.",
|
||||||
"ASSET_IN_WORKSTATION": "An asset belongs to another active workstation. Remove it there before assigning it.",
|
"ASSET_IN_WORKSTATION": "An asset belongs to another active workstation. Remove it there before assigning it.",
|
||||||
|
"ASSET_IN_USE": "The asset cannot be deleted because it is linked to other records.",
|
||||||
"INVALID_REQUEST": "Check the form data.",
|
"INVALID_REQUEST": "Check the form data.",
|
||||||
"INVALID_CHARACTERISTICS": "A characteristic does not match its field or type.",
|
"INVALID_CHARACTERISTICS": "A characteristic does not match its field or type.",
|
||||||
"REQUIRED_CHARACTERISTICS": "Complete the template's required characteristics.",
|
"REQUIRED_CHARACTERISTICS": "Complete the template's required characteristics.",
|
||||||
|
|||||||
@ -90,6 +90,10 @@
|
|||||||
"relatedNotice": "El elemento se guarda por separado y se conserva aunque después canceles el formulario principal.",
|
"relatedNotice": "El elemento se guarda por separado y se conserva aunque después canceles el formulario principal.",
|
||||||
"newAsset": "Nuevo activo",
|
"newAsset": "Nuevo activo",
|
||||||
"editAsset": "Editar activo",
|
"editAsset": "Editar activo",
|
||||||
|
"deleteAsset": "Eliminar activo",
|
||||||
|
"deleteAssetDescription": "Se eliminarán el activo «{{name}}» y su historial. No se puede eliminar si está relacionado con otros registros.",
|
||||||
|
"deletingAsset": "Eliminando activo…",
|
||||||
|
"deleteAssetError": "No se ha podido eliminar el activo. Inténtalo de nuevo.",
|
||||||
"viewAsset": "Ficha e historial",
|
"viewAsset": "Ficha e historial",
|
||||||
"template": "Plantilla",
|
"template": "Plantilla",
|
||||||
"site": "Sede",
|
"site": "Sede",
|
||||||
@ -123,6 +127,7 @@
|
|||||||
"INVALID_MEMBERS": "Selecciona activos distintos y válidos.",
|
"INVALID_MEMBERS": "Selecciona activos distintos y válidos.",
|
||||||
"WORKSTATION_NOT_FOUND": "El puesto no existe en esta compañía.",
|
"WORKSTATION_NOT_FOUND": "El puesto no existe en esta compañía.",
|
||||||
"ASSET_IN_WORKSTATION": "Un activo ya pertenece a otro puesto activo. Retíralo de allí antes de asignarlo.",
|
"ASSET_IN_WORKSTATION": "Un activo ya pertenece a otro puesto activo. Retíralo de allí antes de asignarlo.",
|
||||||
|
"ASSET_IN_USE": "No se puede eliminar el activo porque está relacionado con otros registros.",
|
||||||
"INVALID_REQUEST": "Revisa los datos del formulario.",
|
"INVALID_REQUEST": "Revisa los datos del formulario.",
|
||||||
"INVALID_CHARACTERISTICS": "Alguna característica no corresponde a su campo o tipo.",
|
"INVALID_CHARACTERISTICS": "Alguna característica no corresponde a su campo o tipo.",
|
||||||
"REQUIRED_CHARACTERISTICS": "Completa las características obligatorias de la plantilla.",
|
"REQUIRED_CHARACTERISTICS": "Completa las características obligatorias de la plantilla.",
|
||||||
|
|||||||
@ -22,6 +22,7 @@ export function AssetSelectionPanel({
|
|||||||
onClose,
|
onClose,
|
||||||
onView,
|
onView,
|
||||||
onEdit,
|
onEdit,
|
||||||
|
onDelete,
|
||||||
}: {
|
}: {
|
||||||
companyId: string;
|
companyId: string;
|
||||||
asset: AssetDTO | undefined;
|
asset: AssetDTO | undefined;
|
||||||
@ -32,6 +33,7 @@ export function AssetSelectionPanel({
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onView: (id: string) => void;
|
onView: (id: string) => void;
|
||||||
onEdit: (id: string) => void;
|
onEdit: (id: string) => void;
|
||||||
|
onDelete: (id: string) => void;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation("assets");
|
const { t } = useTranslation("assets");
|
||||||
|
|
||||||
@ -63,6 +65,9 @@ export function AssetSelectionPanel({
|
|||||||
<Button disabled={!canEdit} onClick={() => onEdit(asset.id)} size="sm" variant="outline">
|
<Button disabled={!canEdit} onClick={() => onEdit(asset.id)} size="sm" variant="outline">
|
||||||
{t("edit")}
|
{t("edit")}
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button onClick={() => onDelete(asset.id)} size="sm" variant="destructive">
|
||||||
|
{t("deleteAsset")}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<AssetDetail asset={asset} compact lookups={lookups}>
|
<AssetDetail asset={asset} compact lookups={lookups}>
|
||||||
<DetailSection title={t("relations")}>
|
<DetailSection title={t("relations")}>
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { useBrowserSearchParams, useEntityNavigation } from "@metis/core/client";
|
import { useBrowserSearchParams, useEntityNavigation } from "@metis/core/client";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { catalogApi, catalogKeys } from "../../../catalog/shared/api";
|
import { catalogApi, catalogKeys } from "../../../catalog/shared/api";
|
||||||
import { inventoryKeys } from "../../../shared/queries";
|
import { inventoryKeys } from "../../../shared/queries";
|
||||||
|
import { removeAsset } from "../../shared/api";
|
||||||
import { getAssetInventory } from "../api";
|
import { getAssetInventory } from "../api";
|
||||||
import type { AssetInventoryPageProps } from "../types";
|
import type { AssetInventoryPageProps } from "../types";
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ export function useAssetInventoryPageController({
|
|||||||
initialCreate = false,
|
initialCreate = false,
|
||||||
}: AssetInventoryPageProps) {
|
}: AssetInventoryPageProps) {
|
||||||
const { t } = useTranslation("assets");
|
const { t } = useTranslation("assets");
|
||||||
|
const client = useQueryClient();
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
queryKey: inventoryKeys.company(companyId),
|
queryKey: inventoryKeys.company(companyId),
|
||||||
queryFn: () => getAssetInventory(companyId),
|
queryFn: () => getAssetInventory(companyId),
|
||||||
@ -38,6 +40,14 @@ export function useAssetInventoryPageController({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [editor, setEditor] = useState<string | undefined>(initialCreate ? "new" : undefined);
|
const [editor, setEditor] = useState<string | undefined>(initialCreate ? "new" : undefined);
|
||||||
|
const [deleteId, setDeleteId] = useState<string | undefined>();
|
||||||
|
const remove = useMutation({
|
||||||
|
mutationFn: (id: string) => removeAsset(companyId, id),
|
||||||
|
onSuccess: async () => {
|
||||||
|
await client.invalidateQueries({ queryKey: inventoryKeys.company(companyId) });
|
||||||
|
setDeleteId(undefined);
|
||||||
|
},
|
||||||
|
});
|
||||||
const compact = useCompactInventory();
|
const compact = useCompactInventory();
|
||||||
const [localViewId, setLocalViewId] = useState<string | undefined>();
|
const [localViewId, setLocalViewId] = useState<string | undefined>();
|
||||||
const {
|
const {
|
||||||
@ -53,6 +63,7 @@ export function useAssetInventoryPageController({
|
|||||||
const selected = selectedId ? assets.find((asset) => asset.id === selectedId) : assets[0];
|
const selected = selectedId ? assets.find((asset) => asset.id === selectedId) : assets[0];
|
||||||
const edited = assets.find((asset) => asset.id === editor);
|
const edited = assets.find((asset) => asset.id === editor);
|
||||||
const viewed = assets.find((asset) => asset.id === viewId);
|
const viewed = assets.find((asset) => asset.id === viewId);
|
||||||
|
const deleted = assets.find((asset) => asset.id === deleteId);
|
||||||
const filtered = assets.filter((asset) => {
|
const filtered = assets.filter((asset) => {
|
||||||
const site = lookups.sites.find((site) => site.id === asset.values.siteId);
|
const site = lookups.sites.find((site) => site.id === asset.values.siteId);
|
||||||
|
|
||||||
@ -73,6 +84,10 @@ export function useAssetInventoryPageController({
|
|||||||
setSearch,
|
setSearch,
|
||||||
editor,
|
editor,
|
||||||
setEditor,
|
setEditor,
|
||||||
|
deleted,
|
||||||
|
deleteId,
|
||||||
|
setDeleteId,
|
||||||
|
remove,
|
||||||
setViewId,
|
setViewId,
|
||||||
setSelectedId,
|
setSelectedId,
|
||||||
detailOpen,
|
detailOpen,
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import { CatalogError } from "../../../catalog";
|
|||||||
import { AssetTemplateIcon } from "../../../catalog-templates/shared/ui/asset-template-icon";
|
import { AssetTemplateIcon } from "../../../catalog-templates/shared/ui/asset-template-icon";
|
||||||
import { InventoryFeedback } from "../../../shared";
|
import { InventoryFeedback } from "../../../shared";
|
||||||
import { AssetDetailDialog, AssetSelectionPanel } from "../../detail";
|
import { AssetDetailDialog, AssetSelectionPanel } from "../../detail";
|
||||||
import { AssetEditorDialog } from "../../shared";
|
import { AssetEditorDialog, DeleteAssetDialog } from "../../shared";
|
||||||
import { useAssetInventoryPageController } from "../controllers";
|
import { useAssetInventoryPageController } from "../controllers";
|
||||||
import type { AssetInventoryPageProps } from "../types";
|
import type { AssetInventoryPageProps } from "../types";
|
||||||
|
|
||||||
@ -32,6 +32,10 @@ export function AssetInventoryPage(props: AssetInventoryPageProps) {
|
|||||||
setSearch,
|
setSearch,
|
||||||
editor,
|
editor,
|
||||||
setEditor,
|
setEditor,
|
||||||
|
deleted,
|
||||||
|
deleteId,
|
||||||
|
setDeleteId,
|
||||||
|
remove,
|
||||||
setViewId,
|
setViewId,
|
||||||
setSelectedId,
|
setSelectedId,
|
||||||
detailOpen,
|
detailOpen,
|
||||||
@ -173,6 +177,12 @@ export function AssetInventoryPage(props: AssetInventoryPageProps) {
|
|||||||
<EntityAction disabled={!catalog.data} onClick={() => setEditor(asset.id)}>
|
<EntityAction disabled={!catalog.data} onClick={() => setEditor(asset.id)}>
|
||||||
{t("edit")}
|
{t("edit")}
|
||||||
</EntityAction>
|
</EntityAction>
|
||||||
|
<EntityAction
|
||||||
|
className="text-destructive data-highlighted:text-destructive"
|
||||||
|
onClick={() => setDeleteId(asset.id)}
|
||||||
|
>
|
||||||
|
{t("deleteAsset")}
|
||||||
|
</EntityAction>
|
||||||
</div>{" "}
|
</div>{" "}
|
||||||
</EntityRowActions>
|
</EntityRowActions>
|
||||||
),
|
),
|
||||||
@ -195,6 +205,7 @@ export function AssetInventoryPage(props: AssetInventoryPageProps) {
|
|||||||
companyId={companyId}
|
companyId={companyId}
|
||||||
lookups={lookups}
|
lookups={lookups}
|
||||||
onClose={() => setDetailOpen(false)}
|
onClose={() => setDetailOpen(false)}
|
||||||
|
onDelete={setDeleteId}
|
||||||
onEdit={setEditor}
|
onEdit={setEditor}
|
||||||
onView={setViewId}
|
onView={setViewId}
|
||||||
open={detailOpen}
|
open={detailOpen}
|
||||||
@ -222,6 +233,21 @@ export function AssetInventoryPage(props: AssetInventoryPageProps) {
|
|||||||
onClose={() => setViewId(undefined)}
|
onClose={() => setViewId(undefined)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<DeleteAssetDialog
|
||||||
|
asset={deleted}
|
||||||
|
errorCode={remove.error instanceof Error ? remove.error.message : undefined}
|
||||||
|
onClose={() => setDeleteId(undefined)}
|
||||||
|
onConfirm={async () => {
|
||||||
|
if (!deleteId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await remove.mutateAsync(deleteId);
|
||||||
|
setDetailOpen(false);
|
||||||
|
setSelectedId(undefined);
|
||||||
|
setViewId(undefined);
|
||||||
|
}}
|
||||||
|
open={Boolean(deleted)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export { saveAsset } from "./save-asset.api";
|
export { removeAsset, saveAsset } from "./save-asset.api";
|
||||||
|
|||||||
@ -7,3 +7,7 @@ export async function saveAsset(companyId: string, values: AssetInput, id?: stri
|
|||||||
await inventoryRequest(`${companyId}${id ? `/${id}/update` : ""}`, { values })
|
await inventoryRequest(`${companyId}${id ? `/${id}/update` : ""}`, { values })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function removeAsset(companyId: string, id: string) {
|
||||||
|
return AssetResponseSchema.parse(await inventoryRequest(`${companyId}/${id}/delete`, {}));
|
||||||
|
}
|
||||||
|
|||||||
@ -1,3 +1,2 @@
|
|||||||
export type { InventoryLookups } from "./types";
|
export type { InventoryLookups } from "./types";
|
||||||
|
export { AssetEditorDialog, AssetForm, DeleteAssetDialog } from "./ui";
|
||||||
export { AssetEditorDialog, AssetForm } from "./ui";
|
|
||||||
|
|||||||
@ -272,6 +272,7 @@ test("la ficha lateral agrupa información y ofrece acciones superiores y enlace
|
|||||||
sites: [{ id: siteId, name: "Fábrica" }],
|
sites: [{ id: siteId, name: "Fábrica" }],
|
||||||
}}
|
}}
|
||||||
onClose={() => undefined}
|
onClose={() => undefined}
|
||||||
|
onDelete={() => undefined}
|
||||||
onEdit={() => undefined}
|
onEdit={() => undefined}
|
||||||
onView={() => undefined}
|
onView={() => undefined}
|
||||||
open
|
open
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { ConfirmDeleteDialog } from "@repo/rdx-ui/components/confirm-delete-dialog";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
import type { AssetDTO } from "../../../../common/inventory";
|
||||||
|
|
||||||
|
export function DeleteAssetDialog({
|
||||||
|
asset,
|
||||||
|
open,
|
||||||
|
errorCode,
|
||||||
|
onClose,
|
||||||
|
onConfirm,
|
||||||
|
}: {
|
||||||
|
asset: AssetDTO | undefined;
|
||||||
|
open: boolean;
|
||||||
|
errorCode: string | undefined;
|
||||||
|
onClose: () => void;
|
||||||
|
onConfirm: () => Promise<void>;
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation("assets");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmDeleteDialog
|
||||||
|
cancelLabel={t("cancel")}
|
||||||
|
confirmLabel={t("deleteAsset")}
|
||||||
|
description={t("deleteAssetDescription", { name: asset?.values.name ?? "" })}
|
||||||
|
errorLabel={
|
||||||
|
errorCode === "ASSET_IN_USE" ? t("inventoryErrors.ASSET_IN_USE") : t("deleteAssetError")
|
||||||
|
}
|
||||||
|
onConfirm={onConfirm}
|
||||||
|
onOpenChange={(value) => {
|
||||||
|
if (!value) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
open={open}
|
||||||
|
pendingLabel={t("deletingAsset")}
|
||||||
|
title={t("deleteAsset")}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,3 +1,3 @@
|
|||||||
export { AssetEditorDialog } from "./asset-editor-dialog";
|
export { AssetEditorDialog } from "./asset-editor-dialog";
|
||||||
|
|
||||||
export { AssetForm } from "./asset-form";
|
export { AssetForm } from "./asset-form";
|
||||||
|
export { DeleteAssetDialog } from "./delete-asset-dialog";
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user