fix: clean up dependencies and config schema (#704)
This commit is contained in:
parent
778e6bac75
commit
ecb1218646
@ -156,8 +156,6 @@
|
|||||||
"symbol-observable": "4.0.0",
|
"symbol-observable": "4.0.0",
|
||||||
"unified": "10.1.2",
|
"unified": "10.1.2",
|
||||||
"unist-util-visit": "4.1.2",
|
"unist-util-visit": "4.1.2",
|
||||||
"uploadcare-widget": "3.21.0",
|
|
||||||
"uploadcare-widget-tab-effects": "1.6.0",
|
|
||||||
"url": "0.11.0",
|
"url": "0.11.0",
|
||||||
"url-join": "5.0.0",
|
"url-join": "5.0.0",
|
||||||
"uuid": "9.0.0",
|
"uuid": "9.0.0",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Navigate, useParams } from 'react-router-dom';
|
import { Navigate, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
selectCollection,
|
selectCollection,
|
||||||
@ -16,6 +16,8 @@ interface CollectionRouteProps {
|
|||||||
|
|
||||||
const CollectionRoute = ({ isSearchResults, isSingleSearchResult }: CollectionRouteProps) => {
|
const CollectionRoute = ({ isSearchResults, isSingleSearchResult }: CollectionRouteProps) => {
|
||||||
const { name, searchTerm } = useParams();
|
const { name, searchTerm } = useParams();
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const noRedirect = searchParams.has('noredirect');
|
||||||
|
|
||||||
const collectionSelector = useMemo(() => selectCollection(name), [name]);
|
const collectionSelector = useMemo(() => selectCollection(name), [name]);
|
||||||
const collection = useAppSelector(collectionSelector);
|
const collection = useAppSelector(collectionSelector);
|
||||||
@ -27,7 +29,12 @@ const CollectionRoute = ({ isSearchResults, isSingleSearchResult }: CollectionRo
|
|||||||
return <Navigate to={defaultPath} />;
|
return <Navigate to={defaultPath} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collection && 'files' in collection && collection.files?.length === 1) {
|
if (collection && 'files' in collection && collection.files?.length === 1 && !noRedirect) {
|
||||||
|
const href = window.location.href;
|
||||||
|
if (!href.includes('noredirect')) {
|
||||||
|
window.history.replaceState(null, document.title, `${href}?noredirect`);
|
||||||
|
console.log('REPLACE STATE', document.title, `${href}?noredirect`);
|
||||||
|
}
|
||||||
return <Navigate to={`/collections/${collection.name}/entries/${collection.files[0].name}`} />;
|
return <Navigate to={`/collections/${collection.name}/entries/${collection.files[0].name}`} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,31 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import type { FC } from 'react';
|
import classNames from '@staticcms/core/lib/util/classNames.util';
|
||||||
|
|
||||||
import type { FieldError } from '@staticcms/core/interface';
|
import type { FieldError } from '@staticcms/core/interface';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
export interface ErrorMessageProps {
|
export interface ErrorMessageProps {
|
||||||
errors: FieldError[];
|
errors: FieldError[];
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ErrorMessage: FC<ErrorMessageProps> = ({ errors }) => {
|
const ErrorMessage: FC<ErrorMessageProps> = ({ errors, className }) => {
|
||||||
return errors.length ? (
|
return errors.length ? (
|
||||||
<div
|
<div
|
||||||
key="error"
|
key="error"
|
||||||
data-testid="error"
|
data-testid="error"
|
||||||
className="flex
|
className={classNames(
|
||||||
|
`
|
||||||
|
flex
|
||||||
w-full
|
w-full
|
||||||
text-xs
|
text-xs
|
||||||
text-red-500
|
text-red-500
|
||||||
px-3
|
px-3
|
||||||
pt-1"
|
pt-1
|
||||||
|
`,
|
||||||
|
className,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{errors[0].message}
|
{errors[0].message}
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,7 +58,6 @@ const Pill: FC<PillProps> = ({
|
|||||||
`
|
`
|
||||||
text-xs
|
text-xs
|
||||||
font-medium
|
font-medium
|
||||||
mr-2
|
|
||||||
px-3
|
px-3
|
||||||
py-1
|
py-1
|
||||||
rounded-lg
|
rounded-lg
|
||||||
|
@ -80,7 +80,7 @@ const EditorControl = ({
|
|||||||
[field.name, fieldName, parentPath],
|
[field.name, fieldName, parentPath],
|
||||||
);
|
);
|
||||||
|
|
||||||
const [dirty, setDirty] = useState(!isEmpty(value));
|
const [dirty, setDirty] = useState(!isEmpty(widget.getValidValue(value, field as UnknownField)));
|
||||||
|
|
||||||
const fieldErrorsSelector = useMemo(
|
const fieldErrorsSelector = useMemo(
|
||||||
() => selectFieldErrors(path, i18n, isMeta),
|
() => selectFieldErrors(path, i18n, isMeta),
|
||||||
@ -114,10 +114,12 @@ const EditorControl = ({
|
|||||||
|
|
||||||
const handleChangeDraftField = useCallback(
|
const handleChangeDraftField = useCallback(
|
||||||
(value: ValueOrNestedValue) => {
|
(value: ValueOrNestedValue) => {
|
||||||
setDirty(true);
|
setDirty(
|
||||||
|
oldDirty => oldDirty || !isEmpty(widget.getValidValue(value, field as UnknownField)),
|
||||||
|
);
|
||||||
changeDraftField({ path, field, value, i18n, isMeta });
|
changeDraftField({ path, field, value, i18n, isMeta });
|
||||||
},
|
},
|
||||||
[changeDraftField, field, i18n, isMeta, path],
|
[changeDraftField, field, i18n, isMeta, path, widget],
|
||||||
);
|
);
|
||||||
|
|
||||||
const config = useMemo(() => configState.config, [configState.config]);
|
const config = useMemo(() => configState.config, [configState.config]);
|
||||||
|
@ -113,6 +113,9 @@ const viewFilters = {
|
|||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -149,52 +152,42 @@ function getConfigSchema() {
|
|||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
name: { type: 'string', examples: ['test-repo'] },
|
name: { type: 'string', examples: ['test-repo'] },
|
||||||
|
repo: { type: 'string' },
|
||||||
|
branch: { type: 'string' },
|
||||||
|
api_root: { type: 'string' },
|
||||||
|
site_domain: { type: 'string' },
|
||||||
|
base_url: { type: 'string' },
|
||||||
|
auth_endpoint: { type: 'string' },
|
||||||
|
app_id: { type: 'string' },
|
||||||
|
auth_type: {
|
||||||
|
type: 'string',
|
||||||
|
examples: ['implicit', 'pkce'],
|
||||||
|
enum: ['implicit', 'public_pkcerepo'],
|
||||||
|
},
|
||||||
|
proxy_url: { type: 'string' },
|
||||||
|
large_media_url: { type: 'string' },
|
||||||
|
login: { type: 'boolean' },
|
||||||
|
identity_url: { type: 'string' },
|
||||||
|
gateway_url: { type: 'string' },
|
||||||
auth_scope: {
|
auth_scope: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
examples: ['repo', 'public_repo'],
|
examples: ['repo', 'public_repo'],
|
||||||
enum: ['repo', 'public_repo'],
|
enum: ['repo', 'public_repo'],
|
||||||
},
|
},
|
||||||
},
|
commit_messages: {
|
||||||
required: ['name'],
|
|
||||||
},
|
|
||||||
local_backend: {
|
|
||||||
oneOf: [
|
|
||||||
{ type: 'boolean' },
|
|
||||||
{
|
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
url: { type: 'string', examples: ['http://localhost:8081/api/v1'] },
|
create: { type: 'string' },
|
||||||
allowed_hosts: {
|
update: { type: 'string' },
|
||||||
type: 'array',
|
delete: { type: 'string' },
|
||||||
items: { type: 'string' },
|
uploadMedia: { type: 'string' },
|
||||||
},
|
deleteMedia: { type: 'string' },
|
||||||
},
|
},
|
||||||
additionalProperties: false,
|
additionalProperties: false,
|
||||||
},
|
},
|
||||||
],
|
|
||||||
},
|
|
||||||
locale: { type: 'string', examples: ['en', 'fr', 'de'] },
|
|
||||||
i18n: i18nRoot,
|
|
||||||
site_url: { type: 'string', examples: ['https://example.com'] },
|
|
||||||
display_url: { type: 'string', examples: ['https://example.com'] },
|
|
||||||
logo_url: { type: 'string', examples: ['https://example.com/images/logo.svg'] },
|
|
||||||
media_folder: { type: 'string', examples: ['assets/uploads'] },
|
|
||||||
public_folder: { type: 'string', examples: ['/uploads'] },
|
|
||||||
media_folder_relative: { type: 'boolean' },
|
|
||||||
media_library: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
name: { type: 'string', examples: ['uploadcare'] },
|
|
||||||
config: { type: 'object' },
|
|
||||||
},
|
|
||||||
required: [],
|
|
||||||
},
|
|
||||||
slug: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
encoding: { type: 'string', enum: ['unicode', 'ascii'] },
|
|
||||||
clean_accents: { type: 'boolean' },
|
|
||||||
},
|
},
|
||||||
|
required: ['name'],
|
||||||
|
additionalProperties: false,
|
||||||
},
|
},
|
||||||
collections: {
|
collections: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
@ -204,34 +197,8 @@ function getConfigSchema() {
|
|||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
name: { type: 'string' },
|
name: { type: 'string' },
|
||||||
label: { type: 'string' },
|
|
||||||
label_singular: { type: 'string' },
|
|
||||||
description: { type: 'string' },
|
description: { type: 'string' },
|
||||||
folder: { type: 'string' },
|
icon: { type: 'string' },
|
||||||
files: {
|
|
||||||
type: 'array',
|
|
||||||
items: {
|
|
||||||
// ------- Each file: -------
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
name: { type: 'string' },
|
|
||||||
label: { type: 'string' },
|
|
||||||
label_singular: { type: 'string' },
|
|
||||||
description: { type: 'string' },
|
|
||||||
file: { type: 'string' },
|
|
||||||
editor: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
preview: { type: 'boolean' },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fields: fieldsConfig(),
|
|
||||||
},
|
|
||||||
required: ['name', 'label', 'file', 'fields'],
|
|
||||||
},
|
|
||||||
uniqueItemProperties: ['name'],
|
|
||||||
},
|
|
||||||
identifier_field: { type: 'string' },
|
|
||||||
summary: { type: 'string' },
|
summary: { type: 'string' },
|
||||||
summary_fields: {
|
summary_fields: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
@ -239,28 +206,17 @@ function getConfigSchema() {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
slug: { type: 'string' },
|
filter: {
|
||||||
path: { type: 'string' },
|
|
||||||
create: { type: 'boolean' },
|
|
||||||
publish: { type: 'boolean' },
|
|
||||||
hide: { type: 'boolean' },
|
|
||||||
editor: {
|
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
preview: { type: 'boolean' },
|
value: { type: 'string' },
|
||||||
|
field: { type: 'string' },
|
||||||
},
|
},
|
||||||
|
required: ['value', 'field'],
|
||||||
|
additionalProperties: false,
|
||||||
},
|
},
|
||||||
format: { type: 'string', enum: Object.keys(formatExtensions) },
|
label_singular: { type: 'string' },
|
||||||
extension: { type: 'string' },
|
label: { type: 'string' },
|
||||||
frontmatter_delimiter: {
|
|
||||||
type: ['string', 'array'],
|
|
||||||
minItems: 2,
|
|
||||||
maxItems: 2,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fields: fieldsConfig(),
|
|
||||||
sortable_fields: {
|
sortable_fields: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@ -275,6 +231,7 @@ function getConfigSchema() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
required: ['field'],
|
required: ['field'],
|
||||||
|
additionalProperties: false,
|
||||||
},
|
},
|
||||||
fields: {
|
fields: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
@ -284,9 +241,47 @@ function getConfigSchema() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
required: ['fields'],
|
required: ['fields'],
|
||||||
|
additionalProperties: false,
|
||||||
},
|
},
|
||||||
view_filters: viewFilters,
|
view_filters: viewFilters,
|
||||||
view_groups: viewGroups,
|
view_groups: viewGroups,
|
||||||
|
i18n: i18nCollection,
|
||||||
|
hide: { type: 'boolean' },
|
||||||
|
editor: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
preview: { type: 'boolean' },
|
||||||
|
frame: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
identifier_field: { type: 'string' },
|
||||||
|
path: { type: 'string' },
|
||||||
|
extension: { type: 'string' },
|
||||||
|
format: { type: 'string', enum: Object.keys(formatExtensions) },
|
||||||
|
frontmatter_delimiter: {
|
||||||
|
type: ['string', 'array'],
|
||||||
|
minItems: 2,
|
||||||
|
maxItems: 2,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
slug: { type: 'string' },
|
||||||
|
media_folder: { type: 'string' },
|
||||||
|
public_folder: { type: 'string' },
|
||||||
|
media_library: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
max_file_size: { type: 'number' },
|
||||||
|
folder_support: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
folder: { type: 'string' },
|
||||||
|
fields: fieldsConfig(),
|
||||||
|
create: { type: 'boolean' },
|
||||||
|
delete: { type: 'boolean' },
|
||||||
nested: {
|
nested: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
@ -299,11 +294,49 @@ function getConfigSchema() {
|
|||||||
index_file: { type: 'string' },
|
index_file: { type: 'string' },
|
||||||
},
|
},
|
||||||
required: ['index_file'],
|
required: ['index_file'],
|
||||||
|
additionalProperties: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
required: ['depth'],
|
required: ['depth'],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
files: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
// ------- Each file: -------
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
name: { type: 'string' },
|
||||||
|
label: { type: 'string' },
|
||||||
|
file: { type: 'string' },
|
||||||
|
fields: fieldsConfig(),
|
||||||
|
label_singular: { type: 'string' },
|
||||||
|
description: { type: 'string' },
|
||||||
|
media_folder: { type: 'string' },
|
||||||
|
public_folder: { type: 'string' },
|
||||||
|
media_library: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
max_file_size: { type: 'number' },
|
||||||
|
folder_support: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
},
|
},
|
||||||
i18n: i18nCollection,
|
i18n: i18nCollection,
|
||||||
|
editor: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
preview: { type: 'boolean' },
|
||||||
|
frame: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['name', 'label', 'file', 'fields'],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
uniqueItemProperties: ['name'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
required: ['name', 'label'],
|
required: ['name', 'label'],
|
||||||
oneOf: [{ required: ['files'] }, { required: ['folder', 'fields'] }],
|
oneOf: [{ required: ['files'] }, { required: ['folder', 'fields'] }],
|
||||||
@ -328,15 +361,62 @@ function getConfigSchema() {
|
|||||||
},
|
},
|
||||||
uniqueItemProperties: ['name'],
|
uniqueItemProperties: ['name'],
|
||||||
},
|
},
|
||||||
|
locale: { type: 'string', examples: ['en', 'fr', 'de'] },
|
||||||
|
site_id: { type: 'string' },
|
||||||
|
site_url: { type: 'string', examples: ['https://example.com'] },
|
||||||
|
display_url: { type: 'string', examples: ['https://example.com'] },
|
||||||
|
base_url: { type: 'string' },
|
||||||
|
logo_url: { type: 'string', examples: ['https://example.com/images/logo.svg'] },
|
||||||
|
media_folder: { type: 'string', examples: ['assets/uploads'] },
|
||||||
|
public_folder: { type: 'string', examples: ['/uploads'] },
|
||||||
|
media_folder_relative: { type: 'boolean' },
|
||||||
|
media_library: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
max_file_size: { type: 'number' },
|
||||||
|
folder_support: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
load_config_file: { type: 'boolean' },
|
||||||
|
slug: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
encoding: { type: 'string', enum: ['unicode', 'ascii'] },
|
||||||
|
clean_accents: { type: 'boolean' },
|
||||||
|
sanitize_replacement: { type: 'string' },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
i18n: i18nRoot,
|
||||||
|
local_backend: {
|
||||||
|
oneOf: [
|
||||||
|
{ type: 'boolean' },
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
url: { type: 'string', examples: ['http://localhost:8081/api/v1'] },
|
||||||
|
allowed_hosts: {
|
||||||
|
type: 'array',
|
||||||
|
items: { type: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
editor: {
|
editor: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
preview: { type: 'boolean' },
|
preview: { type: 'boolean' },
|
||||||
|
frame: { type: 'boolean' },
|
||||||
},
|
},
|
||||||
|
additionalProperties: false,
|
||||||
},
|
},
|
||||||
|
search: { type: 'string' },
|
||||||
},
|
},
|
||||||
required: ['backend', 'collections'],
|
required: ['backend', 'collections', 'media_folder'],
|
||||||
anyOf: [{ required: ['media_folder'] }, { required: ['media_library'] }],
|
additionalProperties: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,8 +121,9 @@ export interface FieldsErrors {
|
|||||||
[field: string]: FieldError[];
|
[field: string]: FieldError[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FieldGetValidValueMethod<T = unknown> = (
|
export type FieldGetValidValueMethod<T = unknown, F extends BaseField = UnknownField> = (
|
||||||
value: T | undefined | null,
|
value: T | undefined | null,
|
||||||
|
field: F,
|
||||||
) => T | undefined | null;
|
) => T | undefined | null;
|
||||||
|
|
||||||
export type FieldGetDefaultMethod<T = unknown, F extends BaseField = UnknownField> = (
|
export type FieldGetDefaultMethod<T = unknown, F extends BaseField = UnknownField> = (
|
||||||
@ -363,7 +364,7 @@ export interface Widget<T = unknown, F extends BaseField = UnknownField> {
|
|||||||
control: ComponentType<WidgetControlProps<T, F>>;
|
control: ComponentType<WidgetControlProps<T, F>>;
|
||||||
preview?: WidgetPreviewComponent<T, F>;
|
preview?: WidgetPreviewComponent<T, F>;
|
||||||
validator: FieldValidationMethod<T, F>;
|
validator: FieldValidationMethod<T, F>;
|
||||||
getValidValue: FieldGetValidValueMethod<T>;
|
getValidValue: FieldGetValidValueMethod<T, F>;
|
||||||
getDefaultValue?: FieldGetDefaultMethod<T, F>;
|
getDefaultValue?: FieldGetDefaultMethod<T, F>;
|
||||||
schema?: PropertiesSchema<unknown>;
|
schema?: PropertiesSchema<unknown>;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ export default function useBreadcrumbs(
|
|||||||
const crumbs: Breadcrumb[] = [
|
const crumbs: Breadcrumb[] = [
|
||||||
{
|
{
|
||||||
name: collection.label,
|
name: collection.label,
|
||||||
to: `/collections/${collection.name}`,
|
to: `/collections/${collection.name}?noredirect`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ export async function validate(
|
|||||||
widget: Widget<any, any>,
|
widget: Widget<any, any>,
|
||||||
t: t,
|
t: t,
|
||||||
): Promise<FieldError[]> {
|
): Promise<FieldError[]> {
|
||||||
const validValue = widget.getValidValue(value);
|
const validValue = widget.getValidValue(value, field);
|
||||||
const errors: FieldError[] = [];
|
const errors: FieldError[] = [];
|
||||||
const validations: FieldValidationMethod<ValueOrNestedValue>[] = [
|
const validations: FieldValidationMethod<ValueOrNestedValue>[] = [
|
||||||
validatePresence,
|
validatePresence,
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
ENTRIES_SUCCESS,
|
ENTRIES_SUCCESS,
|
||||||
ENTRY_DELETE_SUCCESS,
|
ENTRY_DELETE_SUCCESS,
|
||||||
ENTRY_FAILURE,
|
ENTRY_FAILURE,
|
||||||
|
ENTRY_PERSIST_SUCCESS,
|
||||||
ENTRY_REQUEST,
|
ENTRY_REQUEST,
|
||||||
ENTRY_SUCCESS,
|
ENTRY_SUCCESS,
|
||||||
FILTER_ENTRIES_FAILURE,
|
FILTER_ENTRIES_FAILURE,
|
||||||
@ -551,6 +552,19 @@ function entries(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ENTRY_PERSIST_SUCCESS: {
|
||||||
|
const payload = action.payload;
|
||||||
|
const { collectionName } = payload;
|
||||||
|
|
||||||
|
const pages = { ...state.pages };
|
||||||
|
delete pages[collectionName];
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
pages,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
33
packages/core/src/types/uploadcare.d.ts
vendored
33
packages/core/src/types/uploadcare.d.ts
vendored
@ -1,33 +0,0 @@
|
|||||||
declare module 'uploadcare-widget-tab-effects';
|
|
||||||
|
|
||||||
declare module 'uploadcare-widget' {
|
|
||||||
interface UploadcareFileGroupInfo {
|
|
||||||
cdnUrl: string;
|
|
||||||
name: string;
|
|
||||||
isImage: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Uploadcare: {
|
|
||||||
loadFileGroup: (groupId: string | undefined) => {
|
|
||||||
done: (callback: (group: UploadcareFileGroupInfo) => void) => void;
|
|
||||||
};
|
|
||||||
fileFrom: (uploadedOrUrl: 'uploaded' | 'url', url: string) => Promise<UploadcareFileGroupInfo>;
|
|
||||||
registerTab: (tab: string, tabContent: unknown) => void;
|
|
||||||
openDialog: (
|
|
||||||
files:
|
|
||||||
| UploadcareFileGroupInfo
|
|
||||||
| UploadcareFileGroupInfo[]
|
|
||||||
| Promise<UploadcareFileGroupInfo | UploadcareFileGroupInfo[]>,
|
|
||||||
settings: Record<string, unknown>,
|
|
||||||
) => {
|
|
||||||
done: (
|
|
||||||
callback: (values: {
|
|
||||||
promise: () => Promise<UploadcareFileGroupInfo>;
|
|
||||||
files: () => Promise<UploadcareFileGroupInfo>[];
|
|
||||||
}) => void,
|
|
||||||
) => void;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Uploadcare;
|
|
||||||
}
|
|
@ -279,7 +279,7 @@ const CodeControl: FC<WidgetControlProps<string | { [key: string]: string }, Cod
|
|||||||
{field.hint}
|
{field.hint}
|
||||||
</Hint>
|
</Hint>
|
||||||
) : null}
|
) : null}
|
||||||
<ErrorMessage errors={errors} />
|
<ErrorMessage errors={errors} className="pt-2 pb-3" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -11,6 +11,15 @@ const CodeWidget = (): WidgetParam<string | { [key: string]: string }, CodeField
|
|||||||
previewComponent,
|
previewComponent,
|
||||||
options: {
|
options: {
|
||||||
schema,
|
schema,
|
||||||
|
getValidValue: (value, field) => {
|
||||||
|
if (!value || typeof value === 'string') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeKey = field.keys ? field.keys.code : 'code';
|
||||||
|
|
||||||
|
return value[codeKey];
|
||||||
|
},
|
||||||
getDefaultValue: (
|
getDefaultValue: (
|
||||||
defaultValue: string | { [key: string]: string } | null | undefined,
|
defaultValue: string | { [key: string]: string } | null | undefined,
|
||||||
field: CodeField,
|
field: CodeField,
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
export default {
|
export default {
|
||||||
properties: {
|
properties: {
|
||||||
|
default: {
|
||||||
|
oneOf: [{ type: 'string' }, { type: 'object' }],
|
||||||
|
},
|
||||||
default_language: { type: 'string' },
|
default_language: { type: 'string' },
|
||||||
allow_language_selection: { type: 'boolean' },
|
allow_language_selection: { type: 'boolean' },
|
||||||
output_code_only: { type: 'boolean' },
|
|
||||||
keys: {
|
keys: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: { code: { type: 'string' }, lang: { type: 'string' } },
|
properties: { code: { type: 'string' }, lang: { type: 'string' } },
|
||||||
},
|
},
|
||||||
default: {
|
output_code_only: { type: 'boolean' },
|
||||||
oneOf: [{ type: 'string' }, { type: 'object' }],
|
code_mirror_config: { type: 'object' },
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
export default {
|
export default {
|
||||||
properties: {
|
properties: {
|
||||||
default: { type: 'string' },
|
default: { type: 'string' },
|
||||||
|
allow_input: { type: 'boolean' },
|
||||||
|
enable_alpha: { type: 'boolean' },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
export default {
|
export default {
|
||||||
properties: {
|
properties: {
|
||||||
|
default: { type: 'string' },
|
||||||
format: { type: 'string' },
|
format: { type: 'string' },
|
||||||
date_format: { oneOf: [{ type: 'string' }, { type: 'boolean' }] },
|
date_format: { oneOf: [{ type: 'string' }, { type: 'boolean' }] },
|
||||||
time_format: { oneOf: [{ type: 'string' }, { type: 'boolean' }] },
|
time_format: { oneOf: [{ type: 'string' }, { type: 'boolean' }] },
|
||||||
picker_utc: { type: 'boolean' },
|
picker_utc: { type: 'boolean' },
|
||||||
default: { type: 'string' },
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -12,5 +12,17 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
media_folder: { type: 'string' },
|
||||||
|
public_folder: { type: 'string' },
|
||||||
|
choose_url: { type: 'boolean' },
|
||||||
|
multiple: { type: 'boolean' },
|
||||||
|
media_library: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
max_file_size: { type: 'number' },
|
||||||
|
folder_support: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -12,5 +12,17 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
media_folder: { type: 'string' },
|
||||||
|
public_folder: { type: 'string' },
|
||||||
|
choose_url: { type: 'boolean' },
|
||||||
|
multiple: { type: 'boolean' },
|
||||||
|
media_library: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
max_file_size: { type: 'number' },
|
||||||
|
folder_support: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -142,7 +142,7 @@ const ListFieldWrapper: FC<ListFieldWrapperProps> = ({
|
|||||||
{hint}
|
{hint}
|
||||||
</Hint>
|
</Hint>
|
||||||
) : null}
|
) : null}
|
||||||
<ErrorMessage errors={errors} />
|
<ErrorMessage errors={errors} className="pb-3" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,27 @@
|
|||||||
export default {
|
export default {
|
||||||
properties: {
|
properties: {
|
||||||
|
default: {
|
||||||
|
oneOf: [
|
||||||
|
{ type: 'boolean' },
|
||||||
|
{ type: 'string' },
|
||||||
|
{ type: 'number' },
|
||||||
|
{
|
||||||
|
type: 'array',
|
||||||
|
minItems: 1,
|
||||||
|
items: { oneOf: [{ type: 'boolean' }, { type: 'string' }, { type: 'number' }] },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
allow_add: { type: 'boolean' },
|
allow_add: { type: 'boolean' },
|
||||||
collapsed: { type: 'boolean' },
|
collapsed: { type: 'boolean' },
|
||||||
summary: { type: 'string' },
|
summary: { type: 'string' },
|
||||||
label_singular: { type: 'string' },
|
label_singular: { type: 'string' },
|
||||||
i18n: { type: 'boolean' },
|
fields: { type: 'object' },
|
||||||
min: { type: 'number' },
|
|
||||||
max: { type: 'number' },
|
max: { type: 'number' },
|
||||||
|
min: { type: 'number' },
|
||||||
|
i18n: { type: 'boolean' },
|
||||||
|
add_to_top: { type: 'boolean' },
|
||||||
|
types: { type: 'object' },
|
||||||
|
type_key: { type: 'string' },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,17 @@
|
|||||||
export default {
|
export default {
|
||||||
properties: {
|
properties: {
|
||||||
default: { type: 'string' },
|
default: { type: 'string' },
|
||||||
|
media_folder: { type: 'string' },
|
||||||
|
public_folder: { type: 'string' },
|
||||||
|
choose_url: { type: 'boolean' },
|
||||||
|
multiple: { type: 'boolean' },
|
||||||
|
media_library: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
max_file_size: { type: 'number' },
|
||||||
|
folder_support: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -134,7 +134,7 @@ const ObjectFieldWrapper: FC<ObjectFieldWrapperProps> = ({
|
|||||||
{hint}
|
{hint}
|
||||||
</Hint>
|
</Hint>
|
||||||
) : null}
|
) : null}
|
||||||
<ErrorMessage errors={errors} />
|
<ErrorMessage errors={errors} className="pl-4 pt-2 pb-3" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
export default {
|
export default {
|
||||||
properties: {
|
properties: {
|
||||||
|
default: { type: 'object' },
|
||||||
collapsed: { type: 'boolean' },
|
collapsed: { type: 'boolean' },
|
||||||
|
summary: { type: 'string' },
|
||||||
i18n: { type: 'boolean' },
|
i18n: { type: 'boolean' },
|
||||||
|
fields: { type: 'object' },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -322,7 +322,7 @@ const RelationControl: FC<WidgetControlProps<string | string[], RelationField>>
|
|||||||
label={
|
label={
|
||||||
<>
|
<>
|
||||||
{Array.isArray(selectedValue) && selectedValue.length > 0 ? (
|
{Array.isArray(selectedValue) && selectedValue.length > 0 ? (
|
||||||
<div className="flex flex-wrap gap-0.5 w-full pr-4 p-2">
|
<div className="flex flex-wrap gap-2 w-full p-2 pr-0 max-w-fit">
|
||||||
{selectedValue.map(selectValue => {
|
{selectedValue.map(selectValue => {
|
||||||
const option = uniqueOptionsByValue[selectValue];
|
const option = uniqueOptionsByValue[selectValue];
|
||||||
return (
|
return (
|
||||||
|
@ -1,14 +1,5 @@
|
|||||||
export default {
|
export default {
|
||||||
properties: {
|
properties: {
|
||||||
collection: { type: 'string' },
|
|
||||||
value_field: { type: 'string' },
|
|
||||||
search_fields: { type: 'array', minItems: 1, items: { type: 'string' } },
|
|
||||||
file: { type: 'string' },
|
|
||||||
multiple: { type: 'boolean' },
|
|
||||||
min: { type: 'integer' },
|
|
||||||
max: { type: 'integer' },
|
|
||||||
display_fields: { type: 'array', minItems: 1, items: { type: 'string' } },
|
|
||||||
options_length: { type: 'integer' },
|
|
||||||
default: {
|
default: {
|
||||||
oneOf: [
|
oneOf: [
|
||||||
{ type: 'string' },
|
{ type: 'string' },
|
||||||
@ -20,6 +11,15 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
collection: { type: 'string' },
|
||||||
|
value_field: { type: 'string' },
|
||||||
|
search_fields: { type: 'array', minItems: 1, items: { type: 'string' } },
|
||||||
|
file: { type: 'string' },
|
||||||
|
display_fields: { type: 'array', minItems: 1, items: { type: 'string' } },
|
||||||
|
multiple: { type: 'boolean' },
|
||||||
|
min: { type: 'integer' },
|
||||||
|
max: { type: 'integer' },
|
||||||
|
options_length: { type: 'integer' },
|
||||||
},
|
},
|
||||||
oneOf: [
|
oneOf: [
|
||||||
{
|
{
|
||||||
|
@ -126,7 +126,7 @@ const SelectControl: FC<WidgetControlProps<string | number | (string | number)[]
|
|||||||
<Select
|
<Select
|
||||||
label={
|
label={
|
||||||
Array.isArray(stringValue) ? (
|
Array.isArray(stringValue) ? (
|
||||||
<div className="flex wrap gap-0.5">
|
<div className="flex wrap gap-2 max-w-fit">
|
||||||
{stringValue.map(selectValue => {
|
{stringValue.map(selectValue => {
|
||||||
const label = optionsByValue[selectValue]?.label ?? selectValue;
|
const label = optionsByValue[selectValue]?.label ?? selectValue;
|
||||||
return (
|
return (
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
export default {
|
export default {
|
||||||
properties: {
|
properties: {
|
||||||
multiple: { type: 'boolean' },
|
|
||||||
min: { type: 'integer' },
|
|
||||||
max: { type: 'integer' },
|
|
||||||
default: {
|
default: {
|
||||||
oneOf: [
|
oneOf: [
|
||||||
{ type: 'string' },
|
{ type: 'string' },
|
||||||
@ -32,6 +29,9 @@ export default {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
multiple: { type: 'boolean' },
|
||||||
|
min: { type: 'integer' },
|
||||||
|
max: { type: 'integer' },
|
||||||
},
|
},
|
||||||
required: ['options'],
|
required: ['options'],
|
||||||
};
|
};
|
||||||
|
20
yarn.lock
20
yarn.lock
@ -8470,7 +8470,7 @@ escape-goat@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-3.0.0.tgz#e8b5fb658553fe8a3c4959c316c6ebb8c842b19c"
|
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-3.0.0.tgz#e8b5fb658553fe8a3c4959c316c6ebb8c842b19c"
|
||||||
integrity sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==
|
integrity sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==
|
||||||
|
|
||||||
escape-html@1.0.3, escape-html@^1.0.3, escape-html@~1.0.3:
|
escape-html@1.0.3, escape-html@~1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||||
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
|
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
|
||||||
@ -11905,11 +11905,6 @@ jotai@^1.7.2:
|
|||||||
resolved "https://registry.yarnpkg.com/jotai/-/jotai-1.13.1.tgz#20cc46454cbb39096b12fddfa635b873b3668236"
|
resolved "https://registry.yarnpkg.com/jotai/-/jotai-1.13.1.tgz#20cc46454cbb39096b12fddfa635b873b3668236"
|
||||||
integrity sha512-RUmH1S4vLsG3V6fbGlKzGJnLrDcC/HNb5gH2AeA9DzuJknoVxSGvvg8OBB7lke+gDc4oXmdVsaKn/xDUhWZ0vw==
|
integrity sha512-RUmH1S4vLsG3V6fbGlKzGJnLrDcC/HNb5gH2AeA9DzuJknoVxSGvvg8OBB7lke+gDc4oXmdVsaKn/xDUhWZ0vw==
|
||||||
|
|
||||||
jquery@^3.6.0:
|
|
||||||
version "3.6.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.4.tgz#ba065c188142100be4833699852bf7c24dc0252f"
|
|
||||||
integrity sha512-v28EW9DWDFpzcD9O5iyJXg3R3+q+mET5JhnjJzQUZMHOv67bpSIHq81GEYpPNZHG+XXHsfSme3nxp/hndKEcsQ==
|
|
||||||
|
|
||||||
js-base64@3.7.5:
|
js-base64@3.7.5:
|
||||||
version "3.7.5"
|
version "3.7.5"
|
||||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.5.tgz#21e24cf6b886f76d6f5f165bfcd69cc55b9e3fca"
|
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.5.tgz#21e24cf6b886f76d6f5f165bfcd69cc55b9e3fca"
|
||||||
@ -18605,19 +18600,6 @@ update-browserslist-db@^1.0.10:
|
|||||||
escalade "^3.1.1"
|
escalade "^3.1.1"
|
||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
|
|
||||||
uploadcare-widget-tab-effects@1.6.0:
|
|
||||||
version "1.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/uploadcare-widget-tab-effects/-/uploadcare-widget-tab-effects-1.6.0.tgz#6de4664b0b2fa47100b5a3e0afc1d41b35b8f429"
|
|
||||||
integrity sha512-RoWxeZnk41qm8Mo19R8Zvshsuqetc4y+gFtxA89x+noLCSFItuviGZJBf7rcX3ocwn+aFNKbXp44dlaVDoYRIA==
|
|
||||||
|
|
||||||
uploadcare-widget@3.21.0:
|
|
||||||
version "3.21.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/uploadcare-widget/-/uploadcare-widget-3.21.0.tgz#db67e7f97d257c3ab8da65328121502f8ab6b1f8"
|
|
||||||
integrity sha512-9C/WLwK3Anx+76rDzg/pe1vBv41j4HapgxfbyVLS+3oolB3bd9NvURAkvfyEif8QUnt7MwK2Ubw3f7UP/a3v9w==
|
|
||||||
dependencies:
|
|
||||||
escape-html "^1.0.3"
|
|
||||||
jquery "^3.6.0"
|
|
||||||
|
|
||||||
uri-js@^4.2.2:
|
uri-js@^4.2.2:
|
||||||
version "4.4.1"
|
version "4.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user