From ce359b00b71ed25396eb788190a27a6abb7a3a26 Mon Sep 17 00:00:00 2001 From: Arthur M <4rthem@users.noreply.github.com> Date: Wed, 30 Oct 2024 10:05:45 +0100 Subject: [PATCH] PS-698 add rendition substitution, projection and lock (#470) * PS-698 add rendition substitution, projection and lock * remove projection from transformation context --- .../api/migrations/Version20241023151611.php | 33 +++++++++++++++++ ...php => AssetRenditionInputTransformer.php} | 17 +++++++-- .../api/src/Api/Model/Input/AssetInput.php | 2 +- ...itionInput.php => AssetRenditionInput.php} | 6 ++- .../Api/Model/Output/AssetRenditionOutput.php | 9 +++++ .../AssetRenditionOutputTransformer.php | 3 ++ databox/api/src/Asset/RenditionBuilder.php | 10 +++++ .../Admin/AssetRenditionCrudController.php | 4 ++ .../api/src/Entity/Core/AssetRendition.php | 37 ++++++++++++++++--- databox/api/src/Storage/RenditionManager.php | 24 +++++++++++- databox/client/src/api/rendition.ts | 2 + .../src/components/Dialog/Asset/InfoAsset.tsx | 16 ++++++++ .../src/components/Dialog/Asset/Rendition.tsx | 31 ++++++++++++++-- .../Dialog/Asset/RenditionStructure.tsx | 16 ++++---- .../Dialog/Collection/InfoCollection.tsx | 9 +++++ .../src/components/Dialog/Info/InfoRow.tsx | 20 +++++----- .../Workspace/RenditionDefinitionManager.tsx | 1 + .../Actions/SaveFileAsRenditionDialog.tsx | 1 + .../Media/Asset/Widgets/CodeEditor.tsx | 6 +-- databox/client/src/types.ts | 3 ++ .../rendition-factory/src/DTO/InputFile.php | 2 +- .../rendition-factory/src/DTO/OutputFile.php | 13 ++++++- .../src/DTO/OutputFileInterface.php | 4 ++ .../src/RenditionCreator.php | 8 +++- .../DocumentToPdfTransformerModule.php | 3 +- .../Document/PdfToImageTransformerModule.php | 3 +- .../Imagine/ImagineTransformerModule.php | 1 + .../Video/FFMpegTransformerModule.php | 1 + .../Video/VideoSummaryTransformerModule.php | 1 + .../VideoToAnimationTransformerModule.php | 3 +- .../Video/VideoToFrameTransformerModule.php | 1 + 31 files changed, 246 insertions(+), 44 deletions(-) create mode 100644 databox/api/migrations/Version20241023151611.php rename databox/api/src/Api/InputTransformer/{RenditionInputTransformer.php => AssetRenditionInputTransformer.php} (78%) rename databox/api/src/Api/Model/Input/{RenditionInput.php => AssetRenditionInput.php} (87%) diff --git a/databox/api/migrations/Version20241023151611.php b/databox/api/migrations/Version20241023151611.php new file mode 100644 index 000000000..6cda3786e --- /dev/null +++ b/databox/api/migrations/Version20241023151611.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE asset_rendition ADD locked BOOLEAN NOT NULL DEFAULT FALSE'); + $this->addSql('ALTER TABLE asset_rendition ADD substituted BOOLEAN NOT NULL DEFAULT FALSE'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE asset_rendition DROP locked'); + $this->addSql('ALTER TABLE asset_rendition DROP substituted'); + } +} diff --git a/databox/api/src/Api/InputTransformer/RenditionInputTransformer.php b/databox/api/src/Api/InputTransformer/AssetRenditionInputTransformer.php similarity index 78% rename from databox/api/src/Api/InputTransformer/RenditionInputTransformer.php rename to databox/api/src/Api/InputTransformer/AssetRenditionInputTransformer.php index d8bd3f5ec..1423eda4d 100644 --- a/databox/api/src/Api/InputTransformer/RenditionInputTransformer.php +++ b/databox/api/src/Api/InputTransformer/AssetRenditionInputTransformer.php @@ -4,7 +4,7 @@ namespace App\Api\InputTransformer; -use App\Api\Model\Input\RenditionInput; +use App\Api\Model\Input\AssetRenditionInput; use App\Consumer\Handler\File\CopyFileToRendition; use App\Entity\Core\Asset; use App\Entity\Core\AssetRendition; @@ -12,15 +12,15 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; -class RenditionInputTransformer extends AbstractFileInputTransformer +class AssetRenditionInputTransformer extends AbstractFileInputTransformer { public function supports(string $resourceClass, object $data): bool { - return AssetRendition::class === $resourceClass && $data instanceof RenditionInput; + return AssetRendition::class === $resourceClass && $data instanceof AssetRenditionInput; } /** - * @param RenditionInput $data + * @param AssetRenditionInput $data */ public function transform(object $data, string $resourceClass, array $context = []): object|iterable { @@ -39,12 +39,21 @@ public function transform(object $data, string $resourceClass, array $context = } $object = $this->renditionManager->getOrCreateRendition($asset, $definition); + if ($object->isLocked()) { + throw new BadRequestHttpException('Cannot update locked rendition'); + } + + if ($object->isSubstituted() && !$data->force) { + throw new BadRequestHttpException('Cannot update rendition that has been substituted without the "force" parameter'); + } } if (!$object->getDefinition()->isSubstitutable()) { throw new BadRequestHttpException(sprintf('Cannot substitute rendition "%s"', $object->getDefinition()->getName())); } + $object->setSubstituted($data->substituted); + $workspace = $object->getAsset()->getWorkspace(); if (null !== $file = $this->handleSource($data->sourceFile, $workspace)) { diff --git a/databox/api/src/Api/Model/Input/AssetInput.php b/databox/api/src/Api/Model/Input/AssetInput.php index 2ad2f6510..b0fa668f7 100644 --- a/databox/api/src/Api/Model/Input/AssetInput.php +++ b/databox/api/src/Api/Model/Input/AssetInput.php @@ -59,7 +59,7 @@ class AssetInput extends AbstractOwnerIdInput public $relationship; /** - * @var RenditionInput[] + * @var AssetRenditionInput[] */ public ?array $renditions = null; } diff --git a/databox/api/src/Api/Model/Input/RenditionInput.php b/databox/api/src/Api/Model/Input/AssetRenditionInput.php similarity index 87% rename from databox/api/src/Api/Model/Input/RenditionInput.php rename to databox/api/src/Api/Model/Input/AssetRenditionInput.php index 755a30b1e..3a9d885c2 100644 --- a/databox/api/src/Api/Model/Input/RenditionInput.php +++ b/databox/api/src/Api/Model/Input/AssetRenditionInput.php @@ -4,7 +4,7 @@ namespace App\Api\Model\Input; -class RenditionInput +class AssetRenditionInput { /** * Rendition definition ID. Or provide name. @@ -31,4 +31,8 @@ class RenditionInput * @var string|null */ public $sourceFileId; + + public $substituted; + + public $force; } diff --git a/databox/api/src/Api/Model/Output/AssetRenditionOutput.php b/databox/api/src/Api/Model/Output/AssetRenditionOutput.php index 1ea8ae09e..4b1999baf 100644 --- a/databox/api/src/Api/Model/Output/AssetRenditionOutput.php +++ b/databox/api/src/Api/Model/Output/AssetRenditionOutput.php @@ -28,6 +28,15 @@ class AssetRenditionOutput extends AbstractUuidOutput #[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ, Share::GROUP_PUBLIC_READ])] public ?string $name = null; + #[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ])] + public ?bool $projection = null; + #[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ])] public ?bool $dirty = null; + + #[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ])] + public bool $locked = false; + + #[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ])] + public bool $substituted = false; } diff --git a/databox/api/src/Api/OutputTransformer/AssetRenditionOutputTransformer.php b/databox/api/src/Api/OutputTransformer/AssetRenditionOutputTransformer.php index 62cbf4794..2edf266ed 100644 --- a/databox/api/src/Api/OutputTransformer/AssetRenditionOutputTransformer.php +++ b/databox/api/src/Api/OutputTransformer/AssetRenditionOutputTransformer.php @@ -39,6 +39,9 @@ public function transform($data, string $outputClass, array &$context = []): obj $output->definition = $definition; $output->file = $data->getFile(); $output->name = $data->getName(); + $output->projection = $data->getProjection(); + $output->locked = $data->isLocked(); + $output->substituted = $data->isSubstituted(); if ($this->hasGroup([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ], $context)) { $output->dirty = $this->renditionBuildHashManager->isRenditionDirty($data); diff --git a/databox/api/src/Asset/RenditionBuilder.php b/databox/api/src/Asset/RenditionBuilder.php index fc7d26e1b..0d0dcb588 100644 --- a/databox/api/src/Asset/RenditionBuilder.php +++ b/databox/api/src/Asset/RenditionBuilder.php @@ -34,6 +34,7 @@ public function __construct( public function buildRendition(RenditionDefinition $renditionDefinition, Asset $asset, bool $force = false): void { + $isProjection = true; if ($asset->getWorkspaceId() !== $renditionDefinition->getWorkspaceId()) { throw new \LogicException(sprintf('Asset "%s" and rendition definition "%s" are not in the same workspace', $asset->getId(), $renditionDefinition->getId())); } @@ -44,6 +45,9 @@ public function buildRendition(RenditionDefinition $renditionDefinition, Asset $ throw new \LogicException(sprintf('Parent rendition "%s" not found for asset "%s"', $parentDefinition->getName(), $asset->getId())); } + if (false === $parentRendition->getProjection()) { + $isProjection = false; + } $source = $parentRendition->getFile(); } else { $source = $asset->getSource(); @@ -59,6 +63,7 @@ public function buildRendition(RenditionDefinition $renditionDefinition, Asset $ $source, null, null, + projection: $isProjection, ); $this->em->flush(); @@ -87,6 +92,10 @@ public function buildRendition(RenditionDefinition $renditionDefinition, Asset $ } if (null !== $outputFile) { + if (!$outputFile->isProjection()) { + $isProjection = false; + } + $file = $this->fileManager->createFileFromPath( $asset->getWorkspace(), $outputFile->getPath(), @@ -102,6 +111,7 @@ public function buildRendition(RenditionDefinition $renditionDefinition, Asset $ $file, $buildHash, $outputFile?->getBuildHashes(), + projection: $isProjection, ); $this->em->flush(); } finally { diff --git a/databox/api/src/Controller/Admin/AssetRenditionCrudController.php b/databox/api/src/Controller/Admin/AssetRenditionCrudController.php index 018e5d523..cc5bd9881 100644 --- a/databox/api/src/Controller/Admin/AssetRenditionCrudController.php +++ b/databox/api/src/Controller/Admin/AssetRenditionCrudController.php @@ -63,6 +63,10 @@ public function configureFields(string $pageName): iterable yield AssociationField::new('file'); yield BooleanField::new('ready') ->renderAsSwitch(false); + yield BooleanField::new('locked'); + yield BooleanField::new('substituted'); + yield BooleanField::new('projection') + ->renderAsSwitch(false); yield DateTimeField::new('updatedAt') ->hideOnForm(); yield DateTimeField::new('createdAt') diff --git a/databox/api/src/Entity/Core/AssetRendition.php b/databox/api/src/Entity/Core/AssetRendition.php index b3e9fc82a..ffb18a76d 100644 --- a/databox/api/src/Entity/Core/AssetRendition.php +++ b/databox/api/src/Entity/Core/AssetRendition.php @@ -13,7 +13,7 @@ use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Put; -use App\Api\Model\Input\RenditionInput; +use App\Api\Model\Input\AssetRenditionInput; use App\Api\Model\Output\AssetRenditionOutput; use App\Api\Provider\RenditionCollectionProvider; use App\Entity\Traits\CreatedAtTrait; @@ -22,7 +22,6 @@ use App\Security\Voter\AbstractVoter; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; -use Symfony\Component\Serializer\Annotation\Groups; #[ApiResource( shortName: 'rendition', @@ -113,7 +112,7 @@ normalizationContext: [ 'groups' => [AssetRendition::GROUP_LIST], ], - input: RenditionInput::class, + input: AssetRenditionInput::class, output: AssetRenditionOutput::class, provider: RenditionCollectionProvider::class, )] @@ -142,10 +141,18 @@ class AssetRendition extends AbstractUuidEntity /** * Homothetic and same format has original. */ - #[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ])] #[ORM\Column(type: Types::BOOLEAN, nullable: true)] private ?bool $projection = null; + /** + * Rendition cannot be substituted. + */ + #[ORM\Column(type: Types::BOOLEAN)] + private bool $locked = false; + + #[ORM\Column(type: Types::BOOLEAN)] + private bool $substituted = false; + /** * Hash based on the build process. */ @@ -189,8 +196,6 @@ public function setDefinition(RenditionDefinition $definition): void $this->definition = $definition; } - #[ApiProperty] - #[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ, Asset::GROUP_LIST, Asset::GROUP_READ])] public function getName(): string { return $this->definition->getName(); @@ -230,4 +235,24 @@ public function setModuleHashes(?array $moduleHashes): void { $this->moduleHashes = $moduleHashes; } + + public function isLocked(): bool + { + return $this->locked; + } + + public function setLocked(bool $locked): void + { + $this->locked = $locked; + } + + public function isSubstituted(): bool + { + return $this->substituted; + } + + public function setSubstituted(bool $substituted): void + { + $this->substituted = $substituted; + } } diff --git a/databox/api/src/Storage/RenditionManager.php b/databox/api/src/Storage/RenditionManager.php index 4b46e9cba..d4771db0f 100644 --- a/databox/api/src/Storage/RenditionManager.php +++ b/databox/api/src/Storage/RenditionManager.php @@ -55,12 +55,19 @@ public function createOrReplaceRenditionByPath( ); } + /** + * @param bool $force Force replace a substitution + */ public function createOrReplaceRenditionFile( Asset $asset, RenditionDefinition $definition, File $file, ?string $buildHash, ?array $moduleHashes, + bool $substituted = false, + bool $locked = false, + bool $force = false, + ?bool $projection = null, ): AssetRendition { if (null === $asset->getSource() && $definition->isUseAsOriginal()) { $asset->setSource($file); @@ -68,9 +75,21 @@ public function createOrReplaceRenditionFile( } $rendition = $this->getOrCreateRendition($asset, $definition); + + if ($rendition->isLocked()) { + throw new \InvalidArgumentException(sprintf('Rendition "%s" is locked', $definition->getName())); + } + + if ($rendition->isSubstituted() && !$force) { + throw new \InvalidArgumentException(sprintf('Rendition "%s" is a substitution and cannot be replaced without the "force" option', $definition->getName())); + } + $rendition->setFile($file); $rendition->setBuildHash($buildHash); $rendition->setModuleHashes($moduleHashes); + $rendition->setSubstituted($substituted); + $rendition->setLocked($locked); + $rendition->setProjection($projection); $this->em->persist($rendition); $this->postFlushStack->addBusMessage($this->pusherManager->createBusMessage( @@ -85,7 +104,10 @@ public function createOrReplaceRenditionFile( return $rendition; } - public function getOrCreateRendition(Asset $asset, RenditionDefinition $definition): AssetRendition + public function getOrCreateRendition( + Asset $asset, + RenditionDefinition $definition + ): AssetRendition { if (null !== $assetRendition = $this->getAssetRenditionByDefinition($asset, $definition)) { return $assetRendition; diff --git a/databox/client/src/api/rendition.ts b/databox/client/src/api/rendition.ts index 02394a681..a29eae49b 100644 --- a/databox/client/src/api/rendition.ts +++ b/databox/client/src/api/rendition.ts @@ -27,6 +27,8 @@ type RenditionInput = { definitionId?: string | undefined; sourceFileId?: string | undefined; assetId: string; + substituted?: boolean; + force?: boolean; }; export async function postRendition( diff --git a/databox/client/src/components/Dialog/Asset/InfoAsset.tsx b/databox/client/src/components/Dialog/Asset/InfoAsset.tsx index 48d653d5f..27481a184 100644 --- a/databox/client/src/components/Dialog/Asset/InfoAsset.tsx +++ b/databox/client/src/components/Dialog/Asset/InfoAsset.tsx @@ -9,6 +9,8 @@ import InfoRow from '../Info/InfoRow'; import {useTranslation} from 'react-i18next'; import BusinessIcon from '@mui/icons-material/Business'; import FolderIcon from '@mui/icons-material/Folder'; +import {useNavigateToModal} from "../../Routing/ModalLink.tsx"; +import {modalRoutes} from "../../../routes.ts"; type Props = { data: Asset; @@ -16,6 +18,8 @@ type Props = { export default function InfoAsset({data, onClose, minHeight}: Props) { const {t} = useTranslation(); + const navigateToModal = useNavigateToModal(); + return ( @@ -61,6 +65,12 @@ export default function InfoAsset({data, onClose, minHeight}: Props) { label={t('asset.info.workspace', `Workspace`)} value={data.workspace.name} copyValue={data.workspace.id} + onClick={() => { + navigateToModal(modalRoutes.workspaces.routes.manage, { + id: data.workspace.id, + tab: 'info', + }); + }} /> } @@ -70,6 +80,12 @@ export default function InfoAsset({data, onClose, minHeight}: Props) { t('asset.info.collection.none', 'None') } copyValue={data.referenceCollection?.id} + onClick={data.referenceCollection ? () => { + navigateToModal(modalRoutes.collections.routes.manage, { + id: data.referenceCollection!.id, + tab: 'info', + }); + } : undefined} /> diff --git a/databox/client/src/components/Dialog/Asset/Rendition.tsx b/databox/client/src/components/Dialog/Asset/Rendition.tsx index b082263e9..3253b6490 100644 --- a/databox/client/src/components/Dialog/Asset/Rendition.tsx +++ b/databox/client/src/components/Dialog/Asset/Rendition.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {Asset, AssetRendition} from '../../../types'; import FilePlayer from '../../Media/Asset/FilePlayer'; import {Dimensions} from '../../Media/Asset/Players'; -import {Button, Chip,} from '@mui/material'; +import {Box, Button, Chip, Tooltip,} from '@mui/material'; import byteSize from 'byte-size'; import DownloadIcon from '@mui/icons-material/Download'; import SaveAsButton from '../../Media/Asset/Actions/SaveAsButton'; @@ -10,6 +10,10 @@ import {useTranslation} from 'react-i18next'; import DeleteIcon from "@mui/icons-material/Delete"; import {RenditionStructure} from "./RenditionStructure.tsx"; import {LoadingButton} from "@mui/lab"; +import LockIcon from "@mui/icons-material/Lock"; +import AspectRatioIcon from '@mui/icons-material/AspectRatio'; +import CropRotateIcon from '@mui/icons-material/CropRotate'; +import ChangeCircleIcon from '@mui/icons-material/ChangeCircle'; type Props = { asset: Asset; @@ -23,7 +27,7 @@ export function Rendition({ title, asset, dimensions, - rendition: {name, file, dirty}, + rendition: {name, file, dirty, substituted, projection, locked}, onDelete, }: Props) { const {t} = useTranslation(); @@ -40,7 +44,28 @@ export function Rendition({ return ( +
{name}
+ {locked && } + {substituted && } + {undefined !== projection && <> + {projection ? + : } + } + } dimensions={dimensions} media={ file ? ( diff --git a/databox/client/src/components/Dialog/Asset/RenditionStructure.tsx b/databox/client/src/components/Dialog/Asset/RenditionStructure.tsx index 43f1ad1b4..ea25aceeb 100644 --- a/databox/client/src/components/Dialog/Asset/RenditionStructure.tsx +++ b/databox/client/src/components/Dialog/Asset/RenditionStructure.tsx @@ -2,19 +2,21 @@ import {ReactNode} from "react"; import {Dimensions} from "../../Media/Asset/Players"; import {Card, CardActions, CardContent, CardMedia, Typography} from "@mui/material"; +type Props = { + title: ReactNode; + info: ReactNode; + media: ReactNode | undefined; + actions: ReactNode; + dimensions: Dimensions; +}; + export function RenditionStructure({ title, info, media, actions, dimensions, -}: { - title: ReactNode; - info: ReactNode; - media: ReactNode | undefined; - actions: ReactNode; - dimensions: Dimensions; -}) { +}: Props) { return ( @@ -51,6 +54,12 @@ export default function InfoCollection({data, onClose, minHeight}: Props) { label={t('collection.info.workspace', `Workspace`)} value={data.workspace.name} copyValue={data.workspace.id} + onClick={() => { + navigateToModal(modalRoutes.workspaces.routes.manage, { + id: data.workspace.id, + tab: 'info', + }); + }} /> } diff --git a/databox/client/src/components/Dialog/Info/InfoRow.tsx b/databox/client/src/components/Dialog/Info/InfoRow.tsx index 68dccc971..acac8a0a8 100644 --- a/databox/client/src/components/Dialog/Info/InfoRow.tsx +++ b/databox/client/src/components/Dialog/Info/InfoRow.tsx @@ -1,12 +1,5 @@ import {ReactNode} from 'react'; -import { - Box, - IconButton, - ListItemIcon, - ListItemText, - MenuItem, - Typography, -} from '@mui/material'; +import {Box, IconButton, ListItemIcon, ListItemText, MenuItem, Typography,} from '@mui/material'; import CopyToClipboard from '../../../lib/CopyToClipboard'; import ContentCopyIcon from '@mui/icons-material/ContentCopy'; @@ -15,9 +8,10 @@ type Props = { label: ReactNode; value: ReactNode; copyValue?: string | undefined; + onClick?: () => void; }; -export default function InfoRow({icon, label, value, copyValue}: Props) { +export default function InfoRow({icon, label, value, copyValue, onClick}: Props) { return ( {icon && {icon}} @@ -39,13 +33,17 @@ export default function InfoRow({icon, label, value, copyValue}: Props) { copy(copyValue); }} > - + )} )} - {value} + {onClick ? + {value} + : value} ); diff --git a/databox/client/src/components/Dialog/Workspace/RenditionDefinitionManager.tsx b/databox/client/src/components/Dialog/Workspace/RenditionDefinitionManager.tsx index e10eaf3a2..9502de964 100644 --- a/databox/client/src/components/Dialog/Workspace/RenditionDefinitionManager.tsx +++ b/databox/client/src/components/Dialog/Workspace/RenditionDefinitionManager.tsx @@ -178,6 +178,7 @@ function Item({ name={'definition'} disabled={submitting} mode={'yaml'} + height={'700px'} /> diff --git a/databox/client/src/components/Media/Asset/Actions/SaveFileAsRenditionDialog.tsx b/databox/client/src/components/Media/Asset/Actions/SaveFileAsRenditionDialog.tsx index 4086bf7ad..879224159 100644 --- a/databox/client/src/components/Media/Asset/Actions/SaveFileAsRenditionDialog.tsx +++ b/databox/client/src/components/Media/Asset/Actions/SaveFileAsRenditionDialog.tsx @@ -46,6 +46,7 @@ export default function SaveFileAsRenditionDialog({ definitionId: data.definition, assetId: asset.id, sourceFileId: file.id, + substituted: true, }); }, onSuccess: () => { diff --git a/databox/client/src/components/Media/Asset/Widgets/CodeEditor.tsx b/databox/client/src/components/Media/Asset/Widgets/CodeEditor.tsx index 050731029..6ee87522c 100644 --- a/databox/client/src/components/Media/Asset/Widgets/CodeEditor.tsx +++ b/databox/client/src/components/Media/Asset/Widgets/CodeEditor.tsx @@ -53,10 +53,6 @@ export default function CodeEditor({ onChange={changeHandler} editorProps={{$blockScrolling: true}} value={value} - style={{ - width: '100%', - height: 200, - }} setOptions={{ enableBasicAutocompletion: false, enableLiveAutocompletion: true, @@ -64,6 +60,8 @@ export default function CodeEditor({ showLineNumbers: true, tabSize: 2, }} + width={'100%'} + height={'300px'} {...rest} /> diff --git a/databox/client/src/types.ts b/databox/client/src/types.ts index 4e9342bb2..652f7c6dc 100644 --- a/databox/client/src/types.ts +++ b/databox/client/src/types.ts @@ -158,6 +158,9 @@ export interface AssetRendition extends ApiHydraObjectResponse { file: File | undefined; ready: boolean; dirty?: boolean; + projection?: boolean; + locked: boolean; + substituted: boolean; } export interface RenditionClass extends ApiHydraObjectResponse { diff --git a/lib/php/rendition-factory/src/DTO/InputFile.php b/lib/php/rendition-factory/src/DTO/InputFile.php index 7ae0f6e02..1c5a4d3cf 100644 --- a/lib/php/rendition-factory/src/DTO/InputFile.php +++ b/lib/php/rendition-factory/src/DTO/InputFile.php @@ -6,6 +6,6 @@ { public function createOutputFile(): OutputFileInterface { - return new OutputFile($this->getPath(), $this->getType(), $this->getFamily()); + return new OutputFile($this->getPath(), $this->getType(), $this->getFamily(), true); } } diff --git a/lib/php/rendition-factory/src/DTO/OutputFile.php b/lib/php/rendition-factory/src/DTO/OutputFile.php index 2d6aafd85..738027a2f 100644 --- a/lib/php/rendition-factory/src/DTO/OutputFile.php +++ b/lib/php/rendition-factory/src/DTO/OutputFile.php @@ -8,6 +8,7 @@ public function __construct( string $path, string $type, FamilyEnum $family, + private bool $projection, private ?array $buildHashes = null, ) { parent::__construct($path, $type, $family); @@ -25,6 +26,16 @@ public function getBuildHashes(): ?array public function withBuildHashes(?array $buildHashes): OutputFileInterface { - return new self($this->getPath(), $this->getType(), $this->getFamily(), $buildHashes); + return new self($this->getPath(), $this->getType(), $this->getFamily(), $this->isProjection(), $buildHashes); + } + + public function withProjection(bool $isProjection): OutputFileInterface + { + return new self($this->getPath(), $this->getType(), $this->getFamily(), $isProjection, $this->getBuildHashes()); + } + + public function isProjection(): bool + { + return $this->projection; } } diff --git a/lib/php/rendition-factory/src/DTO/OutputFileInterface.php b/lib/php/rendition-factory/src/DTO/OutputFileInterface.php index 5b8f1b91d..cb04d794e 100644 --- a/lib/php/rendition-factory/src/DTO/OutputFileInterface.php +++ b/lib/php/rendition-factory/src/DTO/OutputFileInterface.php @@ -9,4 +9,8 @@ public function createNextInputFile(): InputFileInterface; public function getBuildHashes(): ?array; public function withBuildHashes(?array $buildHashes): OutputFileInterface; + + public function withProjection(bool $isProjection): OutputFileInterface; + + public function isProjection(): bool; } diff --git a/lib/php/rendition-factory/src/RenditionCreator.php b/lib/php/rendition-factory/src/RenditionCreator.php index ba4cdbe77..86cea27ef 100644 --- a/lib/php/rendition-factory/src/RenditionCreator.php +++ b/lib/php/rendition-factory/src/RenditionCreator.php @@ -56,19 +56,25 @@ public function createRendition( $buildHashes = $context->getBuildHashes(); $buildHashes->setPath(BuildHashes::PATH_LEVEL_FAMILY, $inputFile->getFamily()->value); + $isProjection = true; $transformationCount = count($transformations); foreach (array_values($transformations) as $i => $transformation) { $buildHashes->setPath(BuildHashes::PATH_LEVEL_MODULE, $i); /** @var TransformerModuleInterface $transformer */ $transformer = $this->transformers->get($transformation->getModule()); $outputFile = $transformer->transform($inputFile, $transformation->getOptions(), $context); + if (!$outputFile->isProjection()) { + $isProjection = false; + } if ($i < $transformationCount) { $inputFile = $outputFile->createNextInputFile(); } } - return $outputFile->withBuildHashes($buildHashes->getHashes()); + return $outputFile + ->withBuildHashes($buildHashes->getHashes()) + ->withProjection($isProjection); } /** diff --git a/lib/php/rendition-factory/src/Transformer/Document/DocumentToPdfTransformerModule.php b/lib/php/rendition-factory/src/Transformer/Document/DocumentToPdfTransformerModule.php index c2410eb62..e1546d0ea 100644 --- a/lib/php/rendition-factory/src/Transformer/Document/DocumentToPdfTransformerModule.php +++ b/lib/php/rendition-factory/src/Transformer/Document/DocumentToPdfTransformerModule.php @@ -32,7 +32,8 @@ public function transform(InputFileInterface $inputFile, array $options, Transfo return new OutputFile( $newPath, 'application/pdf', - FamilyEnum::Document + FamilyEnum::Document, + false // TODO implement projection ); } } diff --git a/lib/php/rendition-factory/src/Transformer/Document/PdfToImageTransformerModule.php b/lib/php/rendition-factory/src/Transformer/Document/PdfToImageTransformerModule.php index 956c84df5..0447d9c16 100644 --- a/lib/php/rendition-factory/src/Transformer/Document/PdfToImageTransformerModule.php +++ b/lib/php/rendition-factory/src/Transformer/Document/PdfToImageTransformerModule.php @@ -52,7 +52,8 @@ public function transform(InputFileInterface $inputFile, array $options, Transfo return new OutputFile( $newPath, $context->guessMimeTypeFromPath($newPath), - FamilyEnum::Image + FamilyEnum::Image, + false // TODO implement projection ); } } diff --git a/lib/php/rendition-factory/src/Transformer/Image/Imagine/ImagineTransformerModule.php b/lib/php/rendition-factory/src/Transformer/Image/Imagine/ImagineTransformerModule.php index e7f756978..e7722e3ef 100644 --- a/lib/php/rendition-factory/src/Transformer/Image/Imagine/ImagineTransformerModule.php +++ b/lib/php/rendition-factory/src/Transformer/Image/Imagine/ImagineTransformerModule.php @@ -51,6 +51,7 @@ public function transform(InputFileInterface $inputFile, array $options, Transfo $outputPath, $output->getMimeType(), FamilyEnum::Image, + false // TODO implement projection ); } diff --git a/lib/php/rendition-factory/src/Transformer/Video/FFMpegTransformerModule.php b/lib/php/rendition-factory/src/Transformer/Video/FFMpegTransformerModule.php index a04910bd2..99a63fdb9 100644 --- a/lib/php/rendition-factory/src/Transformer/Video/FFMpegTransformerModule.php +++ b/lib/php/rendition-factory/src/Transformer/Video/FFMpegTransformerModule.php @@ -160,6 +160,7 @@ function ($filter) { $outputPath, $ouputFormat->getMimeType(), $ouputFormat->getFamily(), + false // TODO implement projection ); } diff --git a/lib/php/rendition-factory/src/Transformer/Video/VideoSummaryTransformerModule.php b/lib/php/rendition-factory/src/Transformer/Video/VideoSummaryTransformerModule.php index 695cab783..1010b211d 100644 --- a/lib/php/rendition-factory/src/Transformer/Video/VideoSummaryTransformerModule.php +++ b/lib/php/rendition-factory/src/Transformer/Video/VideoSummaryTransformerModule.php @@ -131,6 +131,7 @@ public function transform(InputFileInterface $inputFile, array $options, Transfo $outputPath, $outputFormat->getMimeType(), $outputFormat->getFamily(), + false // TODO implement projection ); } } diff --git a/lib/php/rendition-factory/src/Transformer/Video/VideoToAnimationTransformerModule.php b/lib/php/rendition-factory/src/Transformer/Video/VideoToAnimationTransformerModule.php index 9131a466b..595339b54 100644 --- a/lib/php/rendition-factory/src/Transformer/Video/VideoToAnimationTransformerModule.php +++ b/lib/php/rendition-factory/src/Transformer/Video/VideoToAnimationTransformerModule.php @@ -118,7 +118,8 @@ public function transform(InputFileInterface $inputFile, array $options, Transfo return new OutputFile( $outputPath, $outputFormat->getMimeType(), - $outputFormat->getFamily() + $outputFormat->getFamily(), + false // TODO implement projection ); } diff --git a/lib/php/rendition-factory/src/Transformer/Video/VideoToFrameTransformerModule.php b/lib/php/rendition-factory/src/Transformer/Video/VideoToFrameTransformerModule.php index 825ac716e..62d462af6 100644 --- a/lib/php/rendition-factory/src/Transformer/Video/VideoToFrameTransformerModule.php +++ b/lib/php/rendition-factory/src/Transformer/Video/VideoToFrameTransformerModule.php @@ -65,6 +65,7 @@ public function transform(InputFileInterface $inputFile, array $options, Transfo $outputPath, $outputFormat->getMimeType(), $outputFormat->getFamily(), + false // TODO implement projection ); } }