fixed global styles issue
This commit is contained in:
parent
e6b4fe69c7
commit
a31af13c84
@ -0,0 +1,80 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Remove invalid element_type_defaults entries.
|
||||
* Only valid element types defined in DEFAULT_ROWS should exist.
|
||||
*/
|
||||
module.exports = {
|
||||
async up(queryInterface, Sequelize) {
|
||||
// Valid element types as defined in element_type_defaults.js DEFAULT_ROWS
|
||||
const validTypes = [
|
||||
'navigation_next',
|
||||
'navigation_prev',
|
||||
'tooltip',
|
||||
'description',
|
||||
'gallery',
|
||||
'carousel',
|
||||
'video_player',
|
||||
'audio_player',
|
||||
'spot',
|
||||
'logo',
|
||||
'popup',
|
||||
];
|
||||
|
||||
// Find invalid entries
|
||||
const invalidEntries = await queryInterface.sequelize.query(
|
||||
`SELECT id, element_type, name
|
||||
FROM element_type_defaults
|
||||
WHERE element_type NOT IN (:validTypes)
|
||||
AND "deletedAt" IS NULL`,
|
||||
{
|
||||
replacements: { validTypes },
|
||||
type: Sequelize.QueryTypes.SELECT,
|
||||
},
|
||||
);
|
||||
|
||||
if (invalidEntries.length === 0) {
|
||||
console.log('No invalid element_type_defaults found.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Found ${invalidEntries.length} invalid element_type_defaults:`,
|
||||
);
|
||||
invalidEntries.forEach((entry) => {
|
||||
console.log(` - ${entry.name} (${entry.element_type})`);
|
||||
});
|
||||
|
||||
// Delete invalid entries
|
||||
const idsToDelete = invalidEntries.map((e) => e.id);
|
||||
await queryInterface.sequelize.query(
|
||||
`DELETE FROM element_type_defaults WHERE id IN (:ids)`,
|
||||
{ replacements: { ids: idsToDelete } },
|
||||
);
|
||||
|
||||
// Also delete from project_element_defaults
|
||||
const deletedProjectDefaults = await queryInterface.sequelize.query(
|
||||
`DELETE FROM project_element_defaults
|
||||
WHERE element_type NOT IN (:validTypes)
|
||||
RETURNING id, element_type`,
|
||||
{
|
||||
replacements: { validTypes },
|
||||
type: Sequelize.QueryTypes.SELECT,
|
||||
},
|
||||
);
|
||||
|
||||
console.log(
|
||||
`Deleted ${idsToDelete.length} invalid element_type_defaults.`,
|
||||
);
|
||||
console.log(
|
||||
`Deleted ${deletedProjectDefaults.length} invalid project_element_defaults.`,
|
||||
);
|
||||
},
|
||||
|
||||
async down(_queryInterface, _Sequelize) {
|
||||
// Cannot restore deleted invalid entries
|
||||
console.log(
|
||||
'Down migration not applicable - invalid entries cannot be restored.',
|
||||
);
|
||||
},
|
||||
};
|
||||
@ -106,76 +106,70 @@ const CarouselSettingsSection: React.FC<CarouselSettingsSectionProps> = ({
|
||||
</FormField>
|
||||
</div>
|
||||
|
||||
<div className='mb-3 mt-4 flex items-center justify-between'>
|
||||
<h3 className='text-sm font-semibold'>Carousel slides</h3>
|
||||
<BaseButton
|
||||
color='info'
|
||||
icon={mdiPlus}
|
||||
small
|
||||
label='Add slide'
|
||||
onClick={onAddSlide}
|
||||
/>
|
||||
</div>
|
||||
{/* Slides editor only shown in constructor - slides are instance-specific */}
|
||||
{isConstructor && (
|
||||
<>
|
||||
<div className='mb-3 mt-4 flex items-center justify-between'>
|
||||
<h3 className='text-sm font-semibold'>Carousel slides</h3>
|
||||
<BaseButton
|
||||
color='info'
|
||||
icon={mdiPlus}
|
||||
small
|
||||
label='Add slide'
|
||||
onClick={onAddSlide}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='space-y-4'>
|
||||
{carouselSlides.length === 0 ? (
|
||||
<p className='text-sm text-gray-500'>No slides yet.</p>
|
||||
) : (
|
||||
carouselSlides.map((slide, index) => (
|
||||
<CardBox
|
||||
key={slide.id}
|
||||
className='border border-gray-200 dark:border-dark-700'
|
||||
>
|
||||
<div className='mb-3 flex items-center justify-between'>
|
||||
<h4 className='text-sm font-semibold'>Slide {index + 1}</h4>
|
||||
<BaseButton
|
||||
color='danger'
|
||||
icon={mdiTrashCan}
|
||||
small
|
||||
outline
|
||||
onClick={() => onRemoveSlide(slide.id)}
|
||||
/>
|
||||
</div>
|
||||
<div className='grid gap-3 md:grid-cols-2'>
|
||||
{isConstructor ? (
|
||||
<FormField label='Image'>
|
||||
<select
|
||||
value={slide.imageUrl}
|
||||
onChange={(event) =>
|
||||
onUpdateSlide(slide.id, 'imageUrl', event.target.value)
|
||||
}
|
||||
>
|
||||
<option value=''>Not selected</option>
|
||||
{imageAssetOptions.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</FormField>
|
||||
) : (
|
||||
<FormField label='Image URL'>
|
||||
<input
|
||||
value={slide.imageUrl}
|
||||
onChange={(event) =>
|
||||
onUpdateSlide(slide.id, 'imageUrl', event.target.value)
|
||||
}
|
||||
<div className='space-y-4'>
|
||||
{carouselSlides.length === 0 ? (
|
||||
<p className='text-sm text-gray-500'>No slides yet.</p>
|
||||
) : (
|
||||
carouselSlides.map((slide, index) => (
|
||||
<CardBox
|
||||
key={slide.id}
|
||||
className='border border-gray-200 dark:border-dark-700'
|
||||
>
|
||||
<div className='mb-3 flex items-center justify-between'>
|
||||
<h4 className='text-sm font-semibold'>Slide {index + 1}</h4>
|
||||
<BaseButton
|
||||
color='danger'
|
||||
icon={mdiTrashCan}
|
||||
small
|
||||
outline
|
||||
onClick={() => onRemoveSlide(slide.id)}
|
||||
/>
|
||||
</FormField>
|
||||
)}
|
||||
<FormField label='Caption'>
|
||||
<input
|
||||
value={slide.caption}
|
||||
onChange={(event) =>
|
||||
onUpdateSlide(slide.id, 'caption', event.target.value)
|
||||
}
|
||||
/>
|
||||
</FormField>
|
||||
</div>
|
||||
</CardBox>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='grid gap-3 md:grid-cols-2'>
|
||||
<FormField label='Image'>
|
||||
<select
|
||||
value={slide.imageUrl}
|
||||
onChange={(event) =>
|
||||
onUpdateSlide(slide.id, 'imageUrl', event.target.value)
|
||||
}
|
||||
>
|
||||
<option value=''>Not selected</option>
|
||||
{imageAssetOptions.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</FormField>
|
||||
<FormField label='Caption'>
|
||||
<input
|
||||
value={slide.caption}
|
||||
onChange={(event) =>
|
||||
onUpdateSlide(slide.id, 'caption', event.target.value)
|
||||
}
|
||||
/>
|
||||
</FormField>
|
||||
</div>
|
||||
</CardBox>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</CardBox>
|
||||
);
|
||||
};
|
||||
|
||||
@ -63,87 +63,85 @@ const GallerySettingsSection: React.FC<GallerySettingsSectionProps> = ({
|
||||
</FormField>
|
||||
</div>
|
||||
|
||||
<div className='mb-3 flex items-center justify-between'>
|
||||
<h3 className='text-sm font-semibold'>Gallery cards</h3>
|
||||
<BaseButton
|
||||
color='info'
|
||||
icon={mdiPlus}
|
||||
small
|
||||
label='Add card'
|
||||
onClick={onAddCard}
|
||||
/>
|
||||
</div>
|
||||
{/* Cards editor only shown in constructor - cards are instance-specific */}
|
||||
{isConstructor && (
|
||||
<>
|
||||
<div className='mb-3 flex items-center justify-between'>
|
||||
<h3 className='text-sm font-semibold'>Gallery cards</h3>
|
||||
<BaseButton
|
||||
color='info'
|
||||
icon={mdiPlus}
|
||||
small
|
||||
label='Add card'
|
||||
onClick={onAddCard}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='space-y-4'>
|
||||
{galleryCards.length === 0 ? (
|
||||
<p className='text-sm text-gray-500'>No cards yet.</p>
|
||||
) : (
|
||||
galleryCards.map((card, index) => (
|
||||
<CardBox
|
||||
key={card.id}
|
||||
className='border border-gray-200 dark:border-dark-700'
|
||||
>
|
||||
<div className='mb-3 flex items-center justify-between'>
|
||||
<h4 className='text-sm font-semibold'>Card {index + 1}</h4>
|
||||
<BaseButton
|
||||
color='danger'
|
||||
icon={mdiTrashCan}
|
||||
small
|
||||
outline
|
||||
onClick={() => onRemoveCard(card.id)}
|
||||
/>
|
||||
</div>
|
||||
<div className='grid gap-3 md:grid-cols-2'>
|
||||
{isConstructor ? (
|
||||
<FormField label='Image'>
|
||||
<select
|
||||
value={card.imageUrl}
|
||||
onChange={(event) =>
|
||||
onUpdateCard(card.id, 'imageUrl', event.target.value)
|
||||
}
|
||||
>
|
||||
<option value=''>Not selected</option>
|
||||
{imageAssetOptions.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</FormField>
|
||||
) : (
|
||||
<FormField label='Image URL'>
|
||||
<input
|
||||
value={card.imageUrl}
|
||||
onChange={(event) =>
|
||||
onUpdateCard(card.id, 'imageUrl', event.target.value)
|
||||
}
|
||||
<div className='space-y-4'>
|
||||
{galleryCards.length === 0 ? (
|
||||
<p className='text-sm text-gray-500'>No cards yet.</p>
|
||||
) : (
|
||||
galleryCards.map((card, index) => (
|
||||
<CardBox
|
||||
key={card.id}
|
||||
className='border border-gray-200 dark:border-dark-700'
|
||||
>
|
||||
<div className='mb-3 flex items-center justify-between'>
|
||||
<h4 className='text-sm font-semibold'>Card {index + 1}</h4>
|
||||
<BaseButton
|
||||
color='danger'
|
||||
icon={mdiTrashCan}
|
||||
small
|
||||
outline
|
||||
onClick={() => onRemoveCard(card.id)}
|
||||
/>
|
||||
</FormField>
|
||||
)}
|
||||
<FormField label='Title'>
|
||||
<input
|
||||
value={card.title}
|
||||
onChange={(event) =>
|
||||
onUpdateCard(card.id, 'title', event.target.value)
|
||||
}
|
||||
/>
|
||||
</FormField>
|
||||
<div className='md:col-span-2'>
|
||||
<FormField label='Description' hasTextareaHeight>
|
||||
<textarea
|
||||
value={card.description}
|
||||
onChange={(event) =>
|
||||
onUpdateCard(card.id, 'description', event.target.value)
|
||||
}
|
||||
className='h-24 w-full rounded border border-gray-300 p-2 dark:border-dark-700 dark:bg-dark-900'
|
||||
/>
|
||||
</FormField>
|
||||
</div>
|
||||
</div>
|
||||
</CardBox>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='grid gap-3 md:grid-cols-2'>
|
||||
<FormField label='Image'>
|
||||
<select
|
||||
value={card.imageUrl}
|
||||
onChange={(event) =>
|
||||
onUpdateCard(card.id, 'imageUrl', event.target.value)
|
||||
}
|
||||
>
|
||||
<option value=''>Not selected</option>
|
||||
{imageAssetOptions.map((option) => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</FormField>
|
||||
<FormField label='Title'>
|
||||
<input
|
||||
value={card.title}
|
||||
onChange={(event) =>
|
||||
onUpdateCard(card.id, 'title', event.target.value)
|
||||
}
|
||||
/>
|
||||
</FormField>
|
||||
<div className='md:col-span-2'>
|
||||
<FormField label='Description' hasTextareaHeight>
|
||||
<textarea
|
||||
value={card.description}
|
||||
onChange={(event) =>
|
||||
onUpdateCard(
|
||||
card.id,
|
||||
'description',
|
||||
event.target.value,
|
||||
)
|
||||
}
|
||||
className='h-24 w-full rounded border border-gray-300 p-2 dark:border-dark-700 dark:bg-dark-900'
|
||||
/>
|
||||
</FormField>
|
||||
</div>
|
||||
</div>
|
||||
</CardBox>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</CardBox>
|
||||
);
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user