first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
import {FormTextField} from '@common/ui/forms/input-field/text-field/text-field';
import {Trans} from '@common/i18n/trans';
import React, {Fragment} from 'react';
import {useFormContext} from 'react-hook-form';
import {UpdateChannelPayload} from '@common/admin/channels/requests/use-update-channel';
import {SlugEditor} from '@common/ui/slug-editor';
import {useTrans} from '@common/i18n/use-trans';
import {message} from '@common/i18n/message';
import clsx from 'clsx';
interface Props {
className?: string;
autoFocus?: boolean;
}
export function ChannelNameField({className, autoFocus}: Props) {
return (
<Fragment>
<FormTextField
name="name"
label={<Trans message="Title" />}
required
autoFocus={autoFocus}
className={clsx('mb-10', className)}
/>
<FormSlugField />
</Fragment>
);
}
function FormSlugField() {
const {watch, setValue} = useFormContext<UpdateChannelPayload>();
const value = watch('slug');
const name = watch('name');
const disableSlugEditing = watch('config.lockSlug');
const restriction = watch('config.restriction');
const restrictionId = watch('config.restrictionModelId');
const {trans} = useTrans();
return (
<SlugEditor
hideButton={disableSlugEditing}
placeholder={name}
suffix={
restriction && restrictionId === 'urlParam'
? trans(message(':restriction_name', {values: {restriction}}))
: undefined
}
className="text-sm"
pattern="[A-Za-z0-9_-]+"
minLength={3}
maxLength={20}
value={value}
onChange={newSlug => {
setValue('slug', newSlug);
}}
/>
);
}

View File

@@ -0,0 +1,28 @@
import {FormSelect, Option} from '@common/ui/forms/select/select';
import {Trans} from '@common/i18n/trans';
import {ChannelContentConfig} from '@common/admin/channels/channel-editor/channel-content-config';
interface Props {
config: ChannelContentConfig;
className?: string;
}
export function ChannelPaginationTypeField({className}: Props) {
return (
<FormSelect
className={className}
selectionMode="single"
name="config.paginationType"
label={<Trans message="Pagination type" />}
>
<Option value="infiniteScroll">
<Trans message="Infinite scroll" />
</Option>
<Option value="lengthAware">
<Trans message="List of page buttons" />
</Option>
<Option value="simple">
<Trans message="Next/previous page buttons only" />
</Option>
</FormSelect>
);
}

View File

@@ -0,0 +1,79 @@
import {useFormContext} from 'react-hook-form';
import {FormSelect, Option} from '@common/ui/forms/select/select';
import {Trans} from '@common/i18n/trans';
import {InfoDialogTrigger} from '@common/ui/overlays/dialog/info-dialog-trigger/info-dialog-trigger';
import {Fragment, ReactNode} from 'react';
import {UpdateChannelPayload} from '@common/admin/channels/requests/use-update-channel';
import {ChannelContentConfig} from '@common/admin/channels/channel-editor/channel-content-config';
import {FormTextField} from '@common/ui/forms/input-field/text-field/text-field';
import clsx from 'clsx';
import {ChannelsDocsLink} from '@common/admin/channels/channels-docs-link';
interface Props {
children?: ReactNode;
config: ChannelContentConfig;
className?: string;
}
export function ContentAutoUpdateField({children, config, className}: Props) {
const {watch, setValue} = useFormContext<UpdateChannelPayload>();
const modelConfig = config.models[watch('config.contentModel')];
const selectedMethodConfig =
config.autoUpdateMethods[watch('config.autoUpdateMethod')!];
if (
watch('config.contentType') !== 'autoUpdate' ||
!modelConfig.autoUpdateMethods?.length
) {
return null;
}
return (
<div className={clsx('items-end gap-14 md:flex', className)}>
<FormSelect
required
className="flex-auto"
selectionMode="single"
name="config.autoUpdateMethod"
onSelectionChange={value => {
if (config.autoUpdateMethods[value].provider) {
setValue(
'config.autoUpdateProvider',
config.autoUpdateMethods[value].provider,
);
}
}}
label={
<Fragment>
<Trans message="Auto update method" />
<InfoDialogTrigger
body={
<Fragment>
<div className="mb-20">
<Trans message="This option will automatically update channel content every 24 hours using the specified method." />
</div>
<ChannelsDocsLink hash="automatically-update-content-with-specified-method" />
</Fragment>
}
/>
</Fragment>
}
>
{modelConfig.autoUpdateMethods.map(method => (
<Option value={method} key={method}>
<Trans {...config.autoUpdateMethods[method].label} />
</Option>
))}
</FormSelect>
{selectedMethodConfig?.value ? (
<FormTextField
name="config.autoUpdateValue"
required
className="flex-auto"
label={<Trans {...selectedMethodConfig?.value.label} />}
type={selectedMethodConfig?.value.inputType}
/>
) : null}
{children}
</div>
);
}

View File

@@ -0,0 +1,60 @@
import {useFormContext} from 'react-hook-form';
import {FormSelect, Option} from '@common/ui/forms/select/select';
import {Trans} from '@common/i18n/trans';
import {UpdateChannelPayload} from '@common/admin/channels/requests/use-update-channel';
import {ReactNode} from 'react';
import {ChannelContentConfig} from '@common/admin/channels/channel-editor/channel-content-config';
import clsx from 'clsx';
interface Props {
config: ChannelContentConfig;
className?: string;
}
export function ContentLayoutFields({config, className}: Props) {
return (
<div className={clsx('items-end gap-14 md:flex', className)}>
<LayoutField
config={config}
name="config.layout"
label={<Trans message="Layout" />}
/>
<LayoutField
config={config}
name="config.nestedLayout"
label={<Trans message="Layout when nested" />}
/>
</div>
);
}
interface LayoutFieldProps extends Props {
name: string;
label: ReactNode;
}
function LayoutField({config, name, label}: LayoutFieldProps) {
const {watch} = useFormContext<UpdateChannelPayload>();
const contentModel = watch('config.contentModel');
const modelConfig = config.models[contentModel];
if (!modelConfig.layoutMethods?.length) {
return null;
}
return (
<FormSelect
className="w-full flex-auto"
selectionMode="single"
name={name}
label={label}
>
{modelConfig.layoutMethods.map(method => {
const label = config.layoutMethods[method].label;
return (
<Option key={method} value={method}>
<Trans {...label} />
</Option>
);
})}
</FormSelect>
);
}

View File

@@ -0,0 +1,46 @@
import {useFormContext} from 'react-hook-form';
import {FormSelect, Option} from '@common/ui/forms/select/select';
import {Trans} from '@common/i18n/trans';
import {UpdateChannelPayload} from '@common/admin/channels/requests/use-update-channel';
import React from 'react';
import {ChannelContentConfig} from '@common/admin/channels/channel-editor/channel-content-config';
interface Props {
config: ChannelContentConfig;
className?: string;
exclude?: string[];
}
export function ContentModelField({config, className, exclude}: Props) {
const {setValue, getValues} = useFormContext<UpdateChannelPayload>();
return (
<FormSelect
className={className}
selectionMode="single"
name="config.contentModel"
label={<Trans message="Type of content" />}
onSelectionChange={newValue => {
const modelConfig = config.models[newValue];
if (
getValues('config.contentType') === 'autoUpdate' &&
!modelConfig.autoUpdateMethods?.length
) {
(setValue as any)('config.contentType', 'manual');
}
setValue('config.autoUpdateMethod', modelConfig.autoUpdateMethods?.[0]);
setValue(
'config.contentOrder',
modelConfig.sortMethods[0] || 'channelables.order:asc',
);
setValue('config.layout', modelConfig.layoutMethods[0]);
}}
>
{Object.entries(config.models)
.filter(([model]) => !exclude?.includes(model))
.map(([model, {label}]) => (
<Option value={model} key={model}>
<Trans {...label} />
</Option>
))}
</FormSelect>
);
}

View File

@@ -0,0 +1,39 @@
import {useFormContext} from 'react-hook-form';
import {FormSelect, Option} from '@common/ui/forms/select/select';
import {Trans} from '@common/i18n/trans';
import {UpdateChannelPayload} from '@common/admin/channels/requests/use-update-channel';
import {ChannelContentConfig} from '@common/admin/channels/channel-editor/channel-content-config';
interface Props {
config: ChannelContentConfig;
className?: string;
}
export function ContentOrderField({config, className}: Props) {
const {watch} = useFormContext<UpdateChannelPayload>();
const contentType = watch('config.contentType');
const modelConfig = config.models[watch('config.contentModel')];
const sortMethods = [...modelConfig.sortMethods, 'channelables.order:asc'];
return (
<FormSelect
className={className}
selectionMode="single"
name="config.contentOrder"
label={<Trans message="How to order content" />}
>
{sortMethods.map(method => {
const sortConfig = config.sortingMethods[method];
if (
!sortConfig.contentTypes ||
sortConfig.contentTypes.includes(contentType)
) {
return (
<Option value={method} key={method}>
<Trans {...sortConfig.label} />
</Option>
);
}
})}
</FormSelect>
);
}

View File

@@ -0,0 +1,54 @@
import {useFormContext} from 'react-hook-form';
import {FormSelect, Option} from '@common/ui/forms/select/select';
import {Trans} from '@common/i18n/trans';
import {UpdateChannelPayload} from '@common/admin/channels/requests/use-update-channel';
import {ChannelContentConfig} from '@common/admin/channels/channel-editor/channel-content-config';
interface Props {
config: ChannelContentConfig;
className?: string;
}
export function ContentTypeField({config, className}: Props) {
const {setValue} = useFormContext<UpdateChannelPayload>();
return (
<FormSelect
className={className}
selectionMode="single"
name="config.contentType"
label={<Trans message="Content" />}
onSelectionChange={newValue => {
// if content type is "auto update" select first model that
// can be auto updated, otherwise select first available model
let model = Object.entries(config.models)[0];
if (newValue === 'autoUpdate') {
const newModel = Object.entries(config.models).find(
([, modelConfig]) => modelConfig.autoUpdateMethods?.length,
);
if (newModel) {
model = newModel;
}
}
const [modelName, modelConfig] = model;
setValue('config.contentModel', modelName);
setValue('config.restrictionModelId', undefined);
setValue(
'config.autoUpdateMethod',
newValue === 'autoUpdate' ? modelConfig.autoUpdateMethods?.[0] : '',
);
setValue('config.contentOrder', modelConfig.sortMethods[0]);
(setValue as any)('config.restriction', null);
}}
>
<Option value="listAll">
<Trans message="List all content of specified type" />
</Option>
<Option value="manual">
<Trans message="Manage content manually" />
</Option>
<Option value="autoUpdate">
<Trans message="Automatically update content with specified method" />
</Option>
</FormSelect>
);
}