1import { FieldConfigOptionsRegistry } from '../field/FieldConfigOptionsRegistry';
2import { standardFieldConfigEditorRegistry } from '../field/standardFieldConfigEditorRegistry';
3import { FieldConfigProperty, FieldConfigPropertyItem } from '../types/fieldOverrides';
4import { FieldConfigEditorBuilder } from '../utils/OptionsUIBuilders';
5import { SetFieldConfigOptionsArgs } from './PanelPlugin';
6
7/**
8 * Helper functionality to create a field config registry.
9 *
10 * @param config - configuration to base the registry on.
11 * @param pluginName - name of the plugin that will use the registry.
12 * @internal
13 */
14export function createFieldConfigRegistry<TFieldConfigOptions>(
15  config: SetFieldConfigOptionsArgs<TFieldConfigOptions> = {},
16  pluginName: string
17): FieldConfigOptionsRegistry {
18  const registry = new FieldConfigOptionsRegistry();
19  const standardConfigs = standardFieldConfigEditorRegistry.list();
20  const standardOptionsExtensions: Record<string, FieldConfigPropertyItem[]> = {};
21
22  // Add custom options
23  if (config.useCustomConfig) {
24    const builder = new FieldConfigEditorBuilder<TFieldConfigOptions>();
25    config.useCustomConfig(builder);
26
27    for (const customProp of builder.getRegistry().list()) {
28      customProp.isCustom = true;
29      // need to do something to make the custom items not conflict with standard ones
30      // problem is id (registry index) is used as property path
31      // so sort of need a property path on the FieldPropertyEditorItem
32      customProp.id = 'custom.' + customProp.id;
33
34      if (isStandardConfigExtension(customProp, standardConfigs)) {
35        const currentExtensions = standardOptionsExtensions[customProp.category![0]] ?? [];
36        currentExtensions.push(customProp);
37        standardOptionsExtensions[customProp.category![0]] = currentExtensions;
38      } else {
39        registry.register(customProp);
40      }
41    }
42  }
43
44  for (let fieldConfigProp of standardConfigs) {
45    if (config.disableStandardOptions) {
46      const isDisabled = config.disableStandardOptions.indexOf(fieldConfigProp.id as FieldConfigProperty) > -1;
47      if (isDisabled) {
48        continue;
49      }
50    }
51    if (config.standardOptions) {
52      const customDefault: any = config.standardOptions[fieldConfigProp.id as FieldConfigProperty]?.defaultValue;
53      const customSettings: any = config.standardOptions[fieldConfigProp.id as FieldConfigProperty]?.settings;
54      if (customDefault) {
55        fieldConfigProp = {
56          ...fieldConfigProp,
57          defaultValue: customDefault,
58        };
59      }
60
61      if (customSettings) {
62        fieldConfigProp = {
63          ...fieldConfigProp,
64          settings: fieldConfigProp.settings ? { ...fieldConfigProp.settings, ...customSettings } : customSettings,
65        };
66      }
67    }
68
69    registry.register(fieldConfigProp);
70
71    if (fieldConfigProp.category && standardOptionsExtensions[fieldConfigProp.category[0]]) {
72      for (let extensionProperty of standardOptionsExtensions[fieldConfigProp.category[0]]) {
73        registry.register(extensionProperty);
74      }
75    }
76  }
77
78  // assert that field configs do not use array path syntax
79  for (const item of registry.list()) {
80    if (item.path.indexOf('[') > 0) {
81      throw new Error(`[${pluginName}] Field config paths do not support arrays: ${item.id}`);
82    }
83  }
84
85  return registry;
86}
87
88function isStandardConfigExtension(property: FieldConfigPropertyItem, standardProperties: FieldConfigPropertyItem[]) {
89  return Boolean(
90    standardProperties.find((p) => property.category && p.category && property.category[0] === p.category[0])
91  );
92}
93