Skip to content

Commit

Permalink
Feat/delete from layout config (#42)
Browse files Browse the repository at this point in the history
* feat: possibility to delete layouts from production

* fix: clear layout to default when delete is done, updated some variable-names

* fix: lint-errors, ts-errors and made delete not possible on running prod

* fix: updated error-message
  • Loading branch information
malmen237 authored Oct 17, 2024
1 parent 38b2b1e commit 4dc597e
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 25 deletions.
10 changes: 10 additions & 0 deletions src/api/manager/multiviews.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ObjectId, WithId } from 'mongodb';
import { TMultiviewLayout } from '../../interfaces/preset';
import { getDatabase } from '../mongoClient/dbClient';
import { Log } from '../logger';

export async function getMultiviewLayouts(): Promise<TMultiviewLayout[]> {
const db = await getDatabase();
Expand Down Expand Up @@ -38,3 +39,12 @@ export async function putMultiviewLayout(
await collection.insertOne({ ...newMultiviewLayout, _id: new ObjectId() });
}
}

export async function deleteLayout(id: string): Promise<void> {
const db = await getDatabase();

await db.collection('multiviews').deleteOne({
_id: { $eq: new ObjectId(id) }
});
Log().info('Deleted multiview layout', id);
}
30 changes: 29 additions & 1 deletion src/app/api/manager/multiviews/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { isAuthenticated } from '../../../../../api/manager/auth';
import { Params } from 'next/dist/shared/lib/router/utils/route-matcher';
import { updateMultiviewForPipeline } from '../../../../../api/ateliereLive/pipelines/multiviews/multiviews';
import { MultiviewViews } from '../../../../../interfaces/multiview';
import { getMultiviewLayout } from '../../../../../api/manager/multiviews';
import {
deleteLayout,
getMultiviewLayout
} from '../../../../../api/manager/multiviews';

type PutMultiviewRequest = {
pipelineId: string;
Expand Down Expand Up @@ -52,3 +55,28 @@ export async function PUT(
});
}
}

export async function DELETE(
request: NextRequest,
{ params }: { params: Params }
): Promise<NextResponse> {
if (!(await isAuthenticated())) {
return new NextResponse(`Not Authorized!`, {
status: 403
});
}
try {
await deleteLayout(params.id);
return new NextResponse(null, {
status: 200
});
} catch (error) {
console.log(error);
return new NextResponse(
`Error occurred while deleting from DB! Error: ${error}`,
{
status: 500
}
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default function MultiviewLayout({
id: singleSource.id,
label: singleSource.label
}))}
value={label || ''}
value=""
update={(value) => handleChange(id || '', value)}
columnStyle
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { useMultiviewPresets } from '../../../../hooks/multiviewPreset';
import { MultiviewPreset } from '../../../../interfaces/preset';
import { useTranslate } from '../../../../i18n/useTranslate';
import { useSetupMultiviewLayout } from '../../../../hooks/useSetupMultiviewLayout';
import { useMultiviewLayouts } from '../../../../hooks/multiviewLayout';
import {
useDeleteMultiviewLayout,
useMultiviewLayouts
} from '../../../../hooks/multiviewLayout';
import { Production } from '../../../../interfaces/production';
import { useConfigureMultiviewLayout } from '../../../../hooks/useConfigureMultiviewLayout';
import { TMultiviewLayout } from '../../../../interfaces/preset';
Expand All @@ -12,6 +15,9 @@ import { TListSource } from '../../../../interfaces/multiview';
import Options from '../../configureOutputModal/Options';
import Input from '../../configureOutputModal/Input';
import MultiviewLayout from './MultiviewLayout';
import { IconTrash } from '@tabler/icons-react';
import toast from 'react-hot-toast';
import { set } from 'lodash';

type ChangeLayout = {
defaultLabel?: string;
Expand All @@ -28,10 +34,11 @@ export default function MultiviewLayoutSettings({
}) {
const [selectedMultiviewPreset, setSelectedMultiviewPreset] =
useState<MultiviewPreset | null>(null);
const [refresh, setRefresh] = useState(true);
const [changedLayout, setChangedLayout] = useState<ChangeLayout | null>(null);
const [newPresetName, setNewPresetName] = useState<string | null>(null);
const [layoutToChange, setLayoutToChange] = useState<string>('');
const [multiviewLayouts] = useMultiviewLayouts();
const [multiviewLayouts] = useMultiviewLayouts(refresh);
const [multiviewPresets] = useMultiviewPresets();
const { multiviewPresetLayout } = useSetupMultiviewLayout(
selectedMultiviewPreset
Expand All @@ -45,6 +52,7 @@ export default function MultiviewLayoutSettings({
newPresetName
);
const { inputList } = useCreateInputArray(production);
const deleteLayout = useDeleteMultiviewLayout();
const t = useTranslate();

const multiviewPresetNames = multiviewPresets?.map((preset) => preset.name)
Expand All @@ -57,6 +65,15 @@ export default function MultiviewLayoutSettings({
const multiviewLayoutNames =
availableMultiviewLayouts?.map((layout) => layout.name) || [];

const productionLayouts =
multiviewLayouts?.filter(
(layout) => layout.productionId === production?._id
) || [];
const globalMultiviewLayouts = multiviewLayouts?.filter(
(layout) => !layout.productionId
);
const deleteDisabled = productionLayouts.length < 1;

// This useEffect is used to set the drawn layout of the multiviewer on start,
// if this fails then the modal will be empty
useEffect(() => {
Expand All @@ -65,6 +82,12 @@ export default function MultiviewLayoutSettings({
}
}, [multiviewPresets]);

useEffect(() => {
if (multiviewLayouts) {
setRefresh(false);
}
}, [multiviewLayouts]);

const layoutNameAlreadyExist = availableMultiviewLayouts?.find(
(singlePreset) => singlePreset.name === multiviewLayout?.name
)?.name;
Expand Down Expand Up @@ -111,6 +134,7 @@ export default function MultiviewLayoutSettings({
const defaultLabel = availableMultiviewLayouts[0].layout.views.find(
(item) => item.input_slot === idFirstInputView
)?.label;

inputList.map((source) => {
if (value === '') {
setChangedLayout({ defaultLabel, viewId });
Expand All @@ -122,21 +146,68 @@ export default function MultiviewLayoutSettings({
}
};

const removeMultiviewLayout = () => {
const layoutToRemove = productionLayouts.find(
(layout) => layout.name === newPresetName
);
const globalLayoutToRemove = globalMultiviewLayouts?.find(
(layout) => layout.name === newPresetName
);

if (!layoutToRemove && globalLayoutToRemove) {
toast.error(t('preset.not_possible_delete_global_layout'));
return;
}
if (layoutToRemove && !layoutToRemove._id) {
toast.error(t('preset.could_not_delete_layout'));
return;
}
if (layoutToRemove && layoutToRemove._id) {
deleteLayout(layoutToRemove._id.toString()).then(() => {
setRefresh(true);
if (multiviewPresets && multiviewPresets[0]) {
setSelectedMultiviewPreset(multiviewPresets[0]);
}
setNewPresetName('');
toast.success(t('preset.layout_deleted'));
});
}
};

return (
<>
{selectedMultiviewPreset && (
<div className="flex flex-col w-full h-full">
<div className="flex flex-col self-center w-[40%] pt-5">
<Options
label={t('preset.select_multiview_layout')}
options={multiviewLayoutNames.map((singleItem) => ({
label: singleItem
}))}
value={
selectedMultiviewPreset ? selectedMultiviewPreset.name : ''
}
update={(value) => handleLayoutUpdate(value, 'layout')}
/>
<div className="relative">
<Options
label={t('preset.select_multiview_layout')}
options={multiviewLayoutNames.map((singleItem) => ({
label: singleItem
}))}
value={
selectedMultiviewPreset ? selectedMultiviewPreset.name : ''
}
update={(value) => handleLayoutUpdate(value, 'layout')}
/>
{!production?.isActive && (
<button
type="button"
title={t('preset.remove_layout')}
className="absolute top-0 right-[-10%] min-w-fit"
onClick={() => removeMultiviewLayout()}
disabled={deleteDisabled}
>
<IconTrash
className={`ml-4 ${
deleteDisabled
? 'pointer-events-none text-zinc-400'
: 'text-button-delete hover:text-red-400'
}`}
/>
</button>
)}
</div>
<Options
label={t('preset.select_multiview_preset')}
options={multiviewPresetNames.map((singleItem) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function MultiviewSettingsConfig({
productionId
}: MultiviewSettingsProps) {
const t = useTranslate();
const [multiviewLayouts] = useMultiviewLayouts();
const [multiviewLayouts] = useMultiviewLayouts(true);
const [selectedMultiviewLayout, setSelectedMultiviewLayout] = useState<
TMultiviewLayout | undefined
>();
Expand Down
12 changes: 6 additions & 6 deletions src/components/modal/configureOutputModal/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ export default function Options({
onChange={(e) => {
update(e.target.value);
}}
value={value}
value={value === '' && columnStyle ? undefined : value}
className="cursor-pointer px-2 border justify-center text-sm rounded-lg w-6/12 pt-1 pb-1 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:border-gray-400 focus:outline-none"
>
{columnStyle && <option value={''}>{t('preset.select_option')}</option>}
{options.map((value, i) => (
{columnStyle && <option value="">{t('preset.select_option')}</option>}
{options.map((option, i) => (
<option
value={value.id ? value.id : value.label}
key={value.id ? value.id.toString() : value.label + i}
value={option.id ? option.id.toString() : option.label}
key={option.id ? option.id.toString() : option.label + i}
>
{value.label}
{option.label}
</option>
))}
</select>
Expand Down
2 changes: 1 addition & 1 deletion src/components/startProduction/StartProductionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function StartProductionButton({
const [deleteMonitoring] = useDeleteMonitoring();
const [modalOpen, setModalOpen] = useState(false);
const [stopModalOpen, setStopModalOpen] = useState(false);
const [multiviewLayouts] = useMultiviewLayouts();
const [multiviewLayouts] = useMultiviewLayouts(true);

const onClick = () => {
if (!production) return;
Expand Down
27 changes: 24 additions & 3 deletions src/hooks/multiviewLayout.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { TMultiviewLayout } from '../interfaces/preset';
import { DataHook } from './types';
import { WithId } from 'mongodb';
Expand Down Expand Up @@ -30,13 +30,21 @@ export function useGetMultiviewLayout() {
};
}

export function useMultiviewLayouts(): DataHook<TMultiviewLayout[]> {
export function useMultiviewLayouts(
refresh: boolean
): DataHook<TMultiviewLayout[]> {
const [loading, setLoading] = useState(true);
const [multiviewLayouts, setmultiviewLayouts] = useState<TMultiviewLayout[]>(
[]
);

useEffect(() => {
setmultiviewLayouts([]);

if (!refresh) {
return;
}

setLoading(true);
fetch('/api/manager/multiviews', {
method: 'GET',
Expand All @@ -48,7 +56,7 @@ export function useMultiviewLayouts(): DataHook<TMultiviewLayout[]> {
}
})
.finally(() => setLoading(false));
}, []);
}, [refresh]);

return [multiviewLayouts, loading, undefined];
}
Expand All @@ -66,3 +74,16 @@ export function usePutMultiviewLayout() {
throw await response.text();
};
}

export function useDeleteMultiviewLayout() {
return async (id: string): Promise<void> => {
const response = await fetch(`/api/manager/multiviews/${id}`, {
method: 'DELETE',
headers: [['x-api-key', `Bearer ${API_SECRET_KEY}`]]
});
if (response.ok) {
return;
}
throw await response.text();
};
}
4 changes: 4 additions & 0 deletions src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,11 @@ export const en = {
layout_already_exist:
'Layout {{layoutNameAlreadyExist}} will be replaced on save',
remove_multiview: 'Remove multiview',
remove_layout: 'Remove layout',
add_another_multiview: 'Add another multiview',
not_possible_delete_global_layout: 'Global layout can not be deleted',
could_not_delete_layout: 'Could not delete layout',
layout_deleted: 'Layout deleted',
confirm_update_multiviewers:
'Are you sure you want to update multiviewers for the running production?',
confirm_update: 'Update multiviewers'
Expand Down
5 changes: 5 additions & 0 deletions src/i18n/locales/sv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,12 @@ export const sv = {
layout_already_exist:
'Konfigurationen {{layoutNameAlreadyExist}} skrivs över om du sparar',
remove_multiview: 'Ta bort multiview',
remove_layout: 'Ta bort komposition',
add_another_multiview: 'Lägg till ny multiview',
layout_deleted: 'Kompositionen har tagits bort',
not_possible_delete_global_layout:
'Det går inte att ta bort globala kompositioner',
could_not_delete_layout: 'Kunde inte ta bort kompositionen',
confirm_update_multiviewers:
'Är du säker på att du vill uppdatera multiview för pågående produktion?',
confirm_update: 'Uppdatera multiviewers'
Expand Down

0 comments on commit 4dc597e

Please sign in to comment.