Skip to content

Commit 6e8a34b

Browse files
committed
Improve hook system and documentation
1 parent 8efc247 commit 6e8a34b

File tree

4 files changed

+115
-19
lines changed

4 files changed

+115
-19
lines changed

docs/PLUGINS.md

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
- [Object field](#object-field)
1313
- [Restrictions](#restrictions)
1414
- [Json field](#json-field)
15-
15+
- [Hooks](#hooks)
1616

1717
Each plugin should be created handle a specific part of the data.
1818
Avoid creating a single plugin to handle all the data, as this will make the code harder to maintain and understand.
@@ -389,3 +389,91 @@ The `json` field is an escape-hatch that allows the user to input any JSON data.
389389
```
390390

391391
![JSON](images/field-json.png)
392+
393+
## Hooks
394+
395+
> [!WARNING]
396+
> The hooks are an advanced feature and should be used with caution.
397+
398+
Hooks are functions that can be added to the plugins to perform actions at specific points in their lifecycle.
399+
400+
Available hooks:
401+
- `onAfterInit(targetInstance: Plugin, data: any) => void` - Executed after the target plugin's `init` function. Can be a promise.
402+
- `onAfterEditSchema(targetInstance: Plugin, formData: any, schema: PluginEditSchema) => PluginEditSchema` - Allows changing a plugin's schema. Receives the schema returned by the target plugin's `editSchema` function and the data entered in the form. Should return the modified schema.
403+
404+
Hooks should be registered in the plugin's constructor:
405+
406+
```ts
407+
import { Plugin } from '@stac-manager/data-core';
408+
409+
export class PluginName extends Plugin {
410+
name = 'Plugin Name';
411+
412+
constructor() {
413+
super();
414+
this.registerHook(
415+
'Target plugin name',
416+
'onAfterInit',
417+
(targetInstance: Plugin, data: any) => {
418+
// Do something.
419+
}
420+
);
421+
422+
this.registerHook(
423+
'Target plugin name',
424+
'onAfterEditSchema',
425+
(targetInstance: Plugin, formData: any, schema: PluginEditSchema) => {
426+
// Do something.
427+
return schema;
428+
}
429+
);
430+
}
431+
}
432+
```
433+
434+
**Real world example**
435+
Whenever an STAC extension plugin is added, it should add the extension to the `stac_extensions` field of the CollectionsCore plugin. This will allow the interface to show the extension as an option in the dropdown.
436+
437+
This can be achieved with th `onAfterEditSchema` hook:
438+
```ts
439+
import { Plugin } from '@stac-manager/data-core';
440+
441+
export class PluginName extends Plugin {
442+
name = 'Plugin Name';
443+
444+
constructor() {
445+
super();
446+
this.registerHook(
447+
'CollectionsCore',
448+
'onAfterEditSchema',
449+
(targetInstance: Plugin, formData: any, schema: PluginEditSchema) => {
450+
const stac_extensions = schema.properties
451+
.stac_extensions as SchemaFieldArray<SchemaFieldString>;
452+
453+
// Set the new extension value in the schema.
454+
stac_extensions.items.enum!.push([value, label]);
455+
456+
return schema;
457+
}
458+
);
459+
}
460+
}
461+
```
462+
463+
> [!TIP]
464+
> Given that this is a common enough use-case there is a helper function (`addStacExtensionOption`) that can be used.
465+
> ```ts
466+
>import { Plugin } from '@stac-manager/data-core';
467+
>import { addStacExtensionOption } from '@stac-manager/data-plugins';
468+
>
469+
>class PluginName extends Plugin {
470+
> constructor() {
471+
> super();
472+
>
473+
> addStacExtensionOption(
474+
> this,
475+
> 'Item Assets Definition',
476+
> 'https://stac-extensions.github.io/item-assets/v1.0.0/schema.json'
477+
> );
478+
> }
479+
>}

packages/data-core/lib/plugin-utils/plugin.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,21 @@ export abstract class Plugin {
5454
*
5555
* @param targetName - The name of the target plugin to which the hook will be
5656
* applied.
57-
* @param hooks - The hook details.
57+
* @param hookName - The name of the hook.
58+
* @param hook - The hook function.
5859
*/
59-
registerHook(targetName: string, hooks: Omit<PluginHook, 'name'>) {
60-
this[Plugin.HOOKS].push({ name: targetName, ...hooks });
60+
registerHook<K extends keyof Omit<PluginHook, 'name'>>(
61+
targetName: string,
62+
hookName: K,
63+
hook: PluginHook[K]
64+
) {
65+
const hookEntry = this[Plugin.HOOKS].find((h) => h.name === targetName);
66+
67+
if (hookEntry) {
68+
hookEntry[hookName] = hook;
69+
} else {
70+
this[Plugin.HOOKS].push({ name: targetName, [hookName]: hook });
71+
}
6172
}
6273
}
6374

packages/data-core/lib/plugin-utils/resolve.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ export const resolvePlugins = (plugins: PluginConfigItem[], data: any) => {
5050
* [Plugin.HOOKS]: [
5151
* {
5252
* name: 'pluginA', // Target plugin
53-
* onAfterInit: async (target, data) => { }, // Executes after pluginA's init function.
54-
* onAfterEditSchema: (target, formData, origEditSchema) => { } // Composes with pluginA's editSchema function and returns a new one.
53+
* onAfterInit: async (targetInstance, data) => { }, // Executes after pluginA's init function.
54+
* onAfterEditSchema: (targetInstance, formData, origEditSchema) => { } // Composes with pluginA's editSchema function and returns a new one.
5555
* },
5656
* {
5757
* name: 'pluginB', // Target plugin
58-
* onAfterInit: async (target, data) => { }, // Executes after pluginB's init function.
58+
* onAfterInit: async (targetInstance, data) => { }, // Executes after pluginB's init function.
5959
* }
6060
* ];
6161
* }

packages/data-plugins/lib/utils.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {
22
Plugin,
3-
PluginEditSchema,
43
SchemaField,
54
SchemaFieldArray,
65
SchemaFieldString
@@ -217,19 +216,17 @@ export function addStacExtensionOption(
217216
) {
218217
// Quick way to get the name.
219218
const name = new PluginCore().name;
220-
$this.registerHook(name, {
221-
onAfterEditSchema: (pl, formData: any, schema: PluginEditSchema) => {
222-
if (!schema || typeof schema === 'symbol') {
223-
return schema;
224-
}
219+
$this.registerHook(name, 'onAfterEditSchema', (pl, formData, schema) => {
220+
if (!schema || typeof schema === 'symbol') {
221+
return schema;
222+
}
225223

226-
const stac_extensions = schema.properties
227-
.stac_extensions as SchemaFieldArray<SchemaFieldString>;
224+
const stac_extensions = schema.properties
225+
.stac_extensions as SchemaFieldArray<SchemaFieldString>;
228226

229-
// Set the new extension value in the schema.
230-
stac_extensions.items.enum!.push([value, label]);
227+
// Set the new extension value in the schema.
228+
stac_extensions.items.enum!.push([value, label]);
231229

232-
return schema;
233-
}
230+
return schema;
234231
});
235232
}

0 commit comments

Comments
 (0)