add child creation
This commit is contained in:
parent
7c84eefe78
commit
34b0fd0b44
7 changed files with 332 additions and 2 deletions
|
|
@ -3,6 +3,8 @@
|
||||||
namespace App\Controllers;
|
namespace App\Controllers;
|
||||||
|
|
||||||
use App\Element\Element;
|
use App\Element\Element;
|
||||||
|
use App\Element\UseCases\CreateChildElement\CreateChildElement;
|
||||||
|
use App\Element\UseCases\CreateChildElement\CreateChildElementRequest;
|
||||||
use App\Element\UseCases\GetElement\GetElement;
|
use App\Element\UseCases\GetElement\GetElement;
|
||||||
use App\Element\UseCases\GetElement\GetElementRequest;
|
use App\Element\UseCases\GetElement\GetElementRequest;
|
||||||
use App\Element\UseCases\UpdateElement\UpdateElement;
|
use App\Element\UseCases\UpdateElement\UpdateElement;
|
||||||
|
|
@ -18,6 +20,7 @@ class ElementController
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private GetElement $getElement,
|
private GetElement $getElement,
|
||||||
|
private CreateChildElement $createChildElement,
|
||||||
private UpdateElement $updateElement,
|
private UpdateElement $updateElement,
|
||||||
private FileUploader $fileUploader,
|
private FileUploader $fileUploader,
|
||||||
) {
|
) {
|
||||||
|
|
@ -55,6 +58,30 @@ class ElementController
|
||||||
], 200);
|
], 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function createChild(Request $request, ?int $parentId): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$element = $this->createChildElement->execute(
|
||||||
|
new CreateChildElementRequest(
|
||||||
|
parentElementId: $parentId,
|
||||||
|
title: $this->stringInput($request, 'title'),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (BadRequestException $exception) {
|
||||||
|
return new JsonResponse([
|
||||||
|
'error' => $exception->getMessage(),
|
||||||
|
], 400);
|
||||||
|
} catch (NotFoundException $exception) {
|
||||||
|
return new JsonResponse([
|
||||||
|
'error' => $exception->getMessage(),
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'element' => $this->buildElementPayload($element),
|
||||||
|
], 201);
|
||||||
|
}
|
||||||
|
|
||||||
public function update(Request $request): JsonResponse
|
public function update(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$file = $this->uploadedFileInput($request, 'file');
|
$file = $this->uploadedFileInput($request, 'file');
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Element\UseCases\CreateChildElement;
|
||||||
|
|
||||||
|
use App\Element\CreateElementDto;
|
||||||
|
use App\Element\Element;
|
||||||
|
use App\Element\ElementRepository;
|
||||||
|
use App\Exceptions\BadRequestException;
|
||||||
|
use App\Exceptions\NotFoundException;
|
||||||
|
|
||||||
|
class CreateChildElement
|
||||||
|
{
|
||||||
|
public function __construct(private ElementRepository $elementRepository)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws BadRequestException
|
||||||
|
* @throws NotFoundException
|
||||||
|
*/
|
||||||
|
public function execute(CreateChildElementRequest $request): Element
|
||||||
|
{
|
||||||
|
if ($request->parentElementId === null) {
|
||||||
|
throw new BadRequestException('parentElementId is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->title === null || $request->title === '') {
|
||||||
|
throw new BadRequestException('title is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
$parentElement = $this->elementRepository->find(
|
||||||
|
$request->parentElementId
|
||||||
|
);
|
||||||
|
if ($parentElement === null) {
|
||||||
|
throw new NotFoundException('Parent element not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->elementRepository->create(new CreateElementDto(
|
||||||
|
set: $parentElement->getSet(),
|
||||||
|
title: $request->title,
|
||||||
|
description: '',
|
||||||
|
iconImageUrl: null,
|
||||||
|
richText: '',
|
||||||
|
shortPdfPath: null,
|
||||||
|
longPdfPath: null,
|
||||||
|
youtubeUrl: null,
|
||||||
|
parentElement: $parentElement,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Element\UseCases\CreateChildElement;
|
||||||
|
|
||||||
|
class CreateChildElementRequest
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
public ?int $parentElementId,
|
||||||
|
public ?string $title,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,5 +12,10 @@ Route::get('/me', [AuthController::class, 'me'])
|
||||||
->middleware(AuthMiddleware::class);
|
->middleware(AuthMiddleware::class);
|
||||||
Route::get('/sets', [SetController::class, 'index']);
|
Route::get('/sets', [SetController::class, 'index']);
|
||||||
Route::get('/elements/{id}', [ElementController::class, 'show']);
|
Route::get('/elements/{id}', [ElementController::class, 'show']);
|
||||||
|
Route::post('/elements/{parentId}/children', [
|
||||||
|
ElementController::class,
|
||||||
|
'createChild',
|
||||||
|
])
|
||||||
|
->middleware(AuthMiddleware::class);
|
||||||
Route::post('/element/update', [ElementController::class, 'update'])
|
Route::post('/element/update', [ElementController::class, 'update'])
|
||||||
->middleware(AuthMiddleware::class);
|
->middleware(AuthMiddleware::class);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ namespace Tests\Unit\Controllers;
|
||||||
use App\Controllers\ElementController;
|
use App\Controllers\ElementController;
|
||||||
use App\Element\CreateElementDto;
|
use App\Element\CreateElementDto;
|
||||||
use App\Element\Element;
|
use App\Element\Element;
|
||||||
|
use App\Element\UseCases\CreateChildElement\CreateChildElement;
|
||||||
use App\Element\UseCases\GetElement\GetElement;
|
use App\Element\UseCases\GetElement\GetElement;
|
||||||
use App\Element\UseCases\UpdateElement\UpdateDescription;
|
use App\Element\UseCases\UpdateElement\UpdateDescription;
|
||||||
use App\Element\UseCases\UpdateElement\UpdateElement;
|
use App\Element\UseCases\UpdateElement\UpdateElement;
|
||||||
|
|
@ -61,6 +62,7 @@ class ElementControllerTest extends TestCase
|
||||||
);
|
);
|
||||||
$this->controller = new ElementController(
|
$this->controller = new ElementController(
|
||||||
$getElement,
|
$getElement,
|
||||||
|
new CreateChildElement($this->elementRepo),
|
||||||
$updateElement,
|
$updateElement,
|
||||||
$this->fileUploader,
|
$this->fileUploader,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,10 @@ export interface UpdateElementInput {
|
||||||
youtubeUrl: string
|
youtubeUrl: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CreateChildElementInput {
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
interface UpdateElementResponse {
|
interface UpdateElementResponse {
|
||||||
element: Element
|
element: Element
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +52,7 @@ interface ErrorResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string
|
||||||
|
const ELEMENTS_URL = `${API_BASE_URL}/api/elements`
|
||||||
const ELEMENT_UPDATE_URL = `${API_BASE_URL}/api/element/update`
|
const ELEMENT_UPDATE_URL = `${API_BASE_URL}/api/element/update`
|
||||||
|
|
||||||
export const useElementsStore = defineStore('elements', () => {
|
export const useElementsStore = defineStore('elements', () => {
|
||||||
|
|
@ -59,7 +64,9 @@ export const useElementsStore = defineStore('elements', () => {
|
||||||
const isUploadingIconImage = ref(false)
|
const isUploadingIconImage = ref(false)
|
||||||
const isUploadingShortPdf = ref(false)
|
const isUploadingShortPdf = ref(false)
|
||||||
const isUploadingLongPdf = ref(false)
|
const isUploadingLongPdf = ref(false)
|
||||||
|
const isManagingChildren = ref(false)
|
||||||
const saveError = ref<string | null>(null)
|
const saveError = ref<string | null>(null)
|
||||||
|
const childActionError = ref<string | null>(null)
|
||||||
|
|
||||||
async function fetchElement(elementId: string): Promise<void> {
|
async function fetchElement(elementId: string): Promise<void> {
|
||||||
element.value = null
|
element.value = null
|
||||||
|
|
@ -101,6 +108,37 @@ export const useElementsStore = defineStore('elements', () => {
|
||||||
return await saveElementPatch(elementId, input, 'Could not save element')
|
return await saveElementPatch(elementId, input, 'Could not save element')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createChildElement(
|
||||||
|
parentElementId: string,
|
||||||
|
input: CreateChildElementInput,
|
||||||
|
): Promise<Element | null> {
|
||||||
|
childActionError.value = null
|
||||||
|
isManagingChildren.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const encodedParentElementId = encodeURIComponent(parentElementId)
|
||||||
|
const response = await fetch(
|
||||||
|
`${ELEMENTS_URL}/${encodedParentElementId}/children`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
credentials: 'include',
|
||||||
|
body: JSON.stringify(input),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return await handleChildElementResponse(
|
||||||
|
response,
|
||||||
|
'Could not add child element',
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
childActionError.value = 'Network error - could not add child element'
|
||||||
|
return null
|
||||||
|
} finally {
|
||||||
|
isManagingChildren.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function clearElementIconImage(elementId: string): Promise<boolean> {
|
async function clearElementIconImage(elementId: string): Promise<boolean> {
|
||||||
return await saveElementPatch(
|
return await saveElementPatch(
|
||||||
elementId,
|
elementId,
|
||||||
|
|
@ -253,6 +291,29 @@ export const useElementsStore = defineStore('elements', () => {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleChildElementResponse(
|
||||||
|
response: Response,
|
||||||
|
failureMessage: string,
|
||||||
|
): Promise<Element | null> {
|
||||||
|
if (response.status === 401) {
|
||||||
|
childActionError.value = 'Please log in again'
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.status === 400 || response.status === 404) {
|
||||||
|
childActionError.value = await errorMessage(response, failureMessage)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
childActionError.value = failureMessage
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: UpdateElementResponse = await response.json()
|
||||||
|
return data.element
|
||||||
|
}
|
||||||
|
|
||||||
async function errorMessage(
|
async function errorMessage(
|
||||||
response: Response,
|
response: Response,
|
||||||
fallbackMessage: string,
|
fallbackMessage: string,
|
||||||
|
|
@ -274,9 +335,12 @@ export const useElementsStore = defineStore('elements', () => {
|
||||||
isUploadingIconImage,
|
isUploadingIconImage,
|
||||||
isUploadingShortPdf,
|
isUploadingShortPdf,
|
||||||
isUploadingLongPdf,
|
isUploadingLongPdf,
|
||||||
|
isManagingChildren,
|
||||||
saveError,
|
saveError,
|
||||||
|
childActionError,
|
||||||
fetchElement,
|
fetchElement,
|
||||||
updateElement,
|
updateElement,
|
||||||
|
createChildElement,
|
||||||
uploadElementIconImage,
|
uploadElementIconImage,
|
||||||
uploadElementShortPdf,
|
uploadElementShortPdf,
|
||||||
uploadElementLongPdf,
|
uploadElementLongPdf,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { computed, reactive, ref, watch } from 'vue'
|
import { computed, reactive, ref, watch } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import RichTextEditor from '@/components/RichTextEditor.vue'
|
import RichTextEditor from '@/components/RichTextEditor.vue'
|
||||||
import SiteHeader from '@/components/SiteHeader.vue'
|
import SiteHeader from '@/components/SiteHeader.vue'
|
||||||
import { useElementsStore } from '@/stores/elements'
|
import { useElementsStore } from '@/stores/elements'
|
||||||
|
|
@ -13,19 +13,28 @@ interface ElementForm {
|
||||||
youtubeUrl: string
|
youtubeUrl: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ChildElementForm {
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
const elementsStore = useElementsStore()
|
const elementsStore = useElementsStore()
|
||||||
const {
|
const {
|
||||||
element,
|
element,
|
||||||
|
childElements,
|
||||||
isLoading,
|
isLoading,
|
||||||
error,
|
error,
|
||||||
isSaving,
|
isSaving,
|
||||||
isUploadingIconImage,
|
isUploadingIconImage,
|
||||||
isUploadingShortPdf,
|
isUploadingShortPdf,
|
||||||
isUploadingLongPdf,
|
isUploadingLongPdf,
|
||||||
|
isManagingChildren,
|
||||||
saveError,
|
saveError,
|
||||||
|
childActionError,
|
||||||
} = storeToRefs(elementsStore)
|
} = storeToRefs(elementsStore)
|
||||||
const savedMessage = ref<string | null>(null)
|
const savedMessage = ref<string | null>(null)
|
||||||
|
const childStatus = ref<string | null>(null)
|
||||||
const iconImageStatus = ref<string | null>(null)
|
const iconImageStatus = ref<string | null>(null)
|
||||||
const shortPdfStatus = ref<string | null>(null)
|
const shortPdfStatus = ref<string | null>(null)
|
||||||
const longPdfStatus = ref<string | null>(null)
|
const longPdfStatus = ref<string | null>(null)
|
||||||
|
|
@ -40,6 +49,10 @@ const form = reactive<ElementForm>({
|
||||||
youtubeUrl: '',
|
youtubeUrl: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const childForm = reactive<ChildElementForm>({
|
||||||
|
title: '',
|
||||||
|
})
|
||||||
|
|
||||||
const elementId = computed(() => {
|
const elementId = computed(() => {
|
||||||
const routeElementId = route.params.id
|
const routeElementId = route.params.id
|
||||||
|
|
||||||
|
|
@ -58,6 +71,10 @@ const statusMessage = computed(() => {
|
||||||
return saveError.value ?? savedMessage.value
|
return saveError.value ?? savedMessage.value
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const childStatusMessage = computed(() => {
|
||||||
|
return childActionError.value ?? childStatus.value
|
||||||
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
elementId,
|
elementId,
|
||||||
(currentElementId) => {
|
(currentElementId) => {
|
||||||
|
|
@ -66,6 +83,8 @@ watch(
|
||||||
}
|
}
|
||||||
|
|
||||||
savedMessage.value = null
|
savedMessage.value = null
|
||||||
|
childStatus.value = null
|
||||||
|
childForm.title = ''
|
||||||
iconImageStatus.value = null
|
iconImageStatus.value = null
|
||||||
shortPdfStatus.value = null
|
shortPdfStatus.value = null
|
||||||
longPdfStatus.value = null
|
longPdfStatus.value = null
|
||||||
|
|
@ -103,6 +122,27 @@ async function handleSubmit(): Promise<void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleAddChild(): Promise<void> {
|
||||||
|
if (elementId.value === '' || childForm.title === '') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
childStatus.value = null
|
||||||
|
const childElement = await elementsStore.createChildElement(elementId.value, {
|
||||||
|
title: childForm.title,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (childElement === null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
childForm.title = ''
|
||||||
|
await router.push({
|
||||||
|
name: 'admin-element',
|
||||||
|
params: { id: childElement.id.toString() },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function chooseIconImage(): void {
|
function chooseIconImage(): void {
|
||||||
iconImageInput.value?.click()
|
iconImageInput.value?.click()
|
||||||
}
|
}
|
||||||
|
|
@ -449,6 +489,78 @@ function resetInput(changeEvent: Event): void {
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<section class="admin-element-page__children">
|
||||||
|
<span class="admin-element-page__label">Child Elements</span>
|
||||||
|
<ul
|
||||||
|
v-if="childElements.length > 0"
|
||||||
|
class="admin-element-page__child-list"
|
||||||
|
data-cy="admin-child-list"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
v-for="childElement in childElements"
|
||||||
|
:key="childElement.id"
|
||||||
|
class="admin-element-page__child-item"
|
||||||
|
>
|
||||||
|
<RouterLink
|
||||||
|
:to="{
|
||||||
|
name: 'admin-element',
|
||||||
|
params: { id: childElement.id },
|
||||||
|
}"
|
||||||
|
class="admin-element-page__child-link"
|
||||||
|
data-cy="admin-child-edit-link"
|
||||||
|
>
|
||||||
|
{{ childElement.title }}
|
||||||
|
</RouterLink>
|
||||||
|
<p
|
||||||
|
v-if="childElement.description !== ''"
|
||||||
|
class="admin-element-page__child-description"
|
||||||
|
>
|
||||||
|
{{ childElement.description }}
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p
|
||||||
|
v-else
|
||||||
|
class="admin-element-page__empty-media"
|
||||||
|
data-cy="admin-child-empty"
|
||||||
|
>
|
||||||
|
No child elements
|
||||||
|
</p>
|
||||||
|
<div class="admin-element-page__child-add">
|
||||||
|
<label class="admin-element-page__child-title-field">
|
||||||
|
<span class="admin-element-page__label">New child title</span>
|
||||||
|
<input
|
||||||
|
v-model="childForm.title"
|
||||||
|
class="admin-element-page__input"
|
||||||
|
data-cy="admin-child-title"
|
||||||
|
type="text"
|
||||||
|
:disabled="isManagingChildren"
|
||||||
|
@keydown.enter.prevent="handleAddChild"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
class="admin-element-page__secondary-button"
|
||||||
|
data-cy="admin-add-child"
|
||||||
|
type="button"
|
||||||
|
:disabled="isManagingChildren || childForm.title === ''"
|
||||||
|
@click="handleAddChild"
|
||||||
|
>
|
||||||
|
{{ isManagingChildren ? 'Adding...' : 'Add child' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
v-if="childStatusMessage !== null"
|
||||||
|
:class="[
|
||||||
|
'admin-element-page__status',
|
||||||
|
'admin-element-page__status--inline',
|
||||||
|
]"
|
||||||
|
data-cy="admin-child-status"
|
||||||
|
aria-live="polite"
|
||||||
|
>
|
||||||
|
{{ childStatusMessage }}
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div class="admin-element-page__actions">
|
<div class="admin-element-page__actions">
|
||||||
<button
|
<button
|
||||||
class="admin-element-page__save"
|
class="admin-element-page__save"
|
||||||
|
|
@ -516,7 +628,8 @@ function resetInput(changeEvent: Event): void {
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-element-page__media-field {
|
.admin-element-page__media-field,
|
||||||
|
.admin-element-page__children {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|
@ -575,6 +688,58 @@ function resetInput(changeEvent: Event): void {
|
||||||
gap: 0.7rem;
|
gap: 0.7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-element-page__child-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.65rem;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-element-page__child-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-element-page__child-link {
|
||||||
|
color: var(--color-slate);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-element-page__child-link:hover,
|
||||||
|
.admin-element-page__child-link:focus-visible {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-element-page__child-description {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-element-page__child-add {
|
||||||
|
display: flex;
|
||||||
|
align-items: end;
|
||||||
|
gap: 0.7rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-element-page__child-title-field {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.35rem;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.admin-element-page__file-input {
|
.admin-element-page__file-input {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -663,5 +828,10 @@ function resetInput(changeEvent: Event): void {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-element-page__child-add {
|
||||||
|
align-items: stretch;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue