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 (
);
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
);
}
}