MM-62172: CPA/User Properties - System Console (#29672)
* system properties - user properties * update * fix processing * refinements, fix cancel changes, fix type inclusion when saving/creating, i18n * fix: - property name value trimmed - name unique validation - name required validation - name max-length - user properties section titlecase - new property default incremented name - new property auto-focus/select - max fields count - table design/styling * add useUserPropertyFields test
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
e400e67732
Коммит
0085826203
@@ -31,6 +31,8 @@ export type StatusOK = {
|
||||
status: 'OK';
|
||||
};
|
||||
|
||||
export const isStatusOK = (x: StatusOK | Record<string, unknown>): x is StatusOK => (x as StatusOK)?.status === 'OK';
|
||||
|
||||
export type FetchPaginatedThreadOptions = {
|
||||
fetchThreads?: boolean;
|
||||
collapsedThreads?: boolean;
|
||||
|
||||
@@ -13,6 +13,13 @@ export type RelationOneToManyUnique<E1 extends {id: string}, E2 extends {id: str
|
||||
|
||||
export type IDMappedObjects<E extends {id: string}> = RelationOneToOne<E, E>;
|
||||
|
||||
export type IDMappedCollection<T extends {id: string}> = {
|
||||
data: IDMappedObjects<T>;
|
||||
order: Array<T['id']>;
|
||||
errors?: RelationOneToOne<T, Error>;
|
||||
warnings?: RelationOneToOne<T, {[Key in keyof T]?: string}>;
|
||||
};
|
||||
|
||||
export type DeepPartial<T> = {
|
||||
|
||||
// For each field of T, make it optional and...
|
||||
@@ -44,6 +51,10 @@ Pick<T, Exclude<keyof T, Keys>> & {[K in Keys]-?: Required<Pick<T, K>> & Partial
|
||||
export type Intersection<T1, T2> =
|
||||
Omit<Omit<T1&T2, keyof(Omit<T1, keyof(T2)>)>, keyof(Omit<T2, keyof(T1)>)>;
|
||||
|
||||
/** https://stackoverflow.com/a/66605669 */
|
||||
type Only<T, U> = {[P in keyof T]: T[P]} & {[P in keyof U]?: never};
|
||||
export type Either<T, U> = Only<T, U> | Only<U, T>;
|
||||
|
||||
export type PartialExcept<T extends Record<string, unknown>, TKeysNotPartial extends keyof T> = Partial<T> & Pick<T, TKeysNotPartial>;
|
||||
|
||||
export function isArrayOf<T>(v: unknown, check: (e: unknown) => boolean): v is T[] {
|
||||
@@ -73,3 +84,30 @@ export function isRecordOf<T>(v: unknown, check: (e: unknown) => boolean): v is
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export const collectionFromArray = <T extends {id: string}>(arr: T[] = []): IDMappedCollection<T> => {
|
||||
return arr.reduce((current, item) => {
|
||||
current.data = {...current.data, [item.id]: item};
|
||||
current.order.push(item.id);
|
||||
return current;
|
||||
}, {data: {} as IDMappedObjects<T>, order: []} as IDMappedCollection<T>);
|
||||
};
|
||||
|
||||
export const collectionToArray = <T extends {id: string}>({data, order}: IDMappedCollection<T>): T[] => {
|
||||
return order.map((id) => data[id]);
|
||||
};
|
||||
|
||||
export const collectionReplaceItem = <T extends {id: string}>(collection: IDMappedCollection<T>, item: T) => {
|
||||
return {...collection, data: {...collection.data, [item.id]: item}};
|
||||
};
|
||||
|
||||
export const collectionAddItem = <T extends {id: string}>(collection: IDMappedCollection<T>, item: T) => {
|
||||
return {...collection, data: {...collection.data, [item.id]: item}, order: [...collection.order, item.id]};
|
||||
};
|
||||
|
||||
export const collectionRemoveItem = <T extends {id: string}>(collection: IDMappedCollection<T>, item: T) => {
|
||||
const data = {...collection.data};
|
||||
Reflect.deleteProperty(data, item.id);
|
||||
const order = collection.order.filter((id) => id !== item.id);
|
||||
return {...collection, data, order};
|
||||
};
|
||||
|
||||
Ссылка в новой задаче
Block a user