Skip to content

Commit c1b76de

Browse files
Register action hook (#64)
* register action hook Signed-off-by: bowenlan-amzn <[email protected]>
1 parent 0e173f4 commit c1b76de

File tree

9 files changed

+121
-18
lines changed

9 files changed

+121
-18
lines changed

.github/workflows/cypress-workflow.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,25 @@ jobs:
3333
- name: Build OpenSearch
3434
working-directory: ./OpenSearch
3535
run: ./gradlew publishToMavenLocal -Dbuild.snapshot=false
36+
- name: Checkout OpenSearch2
37+
uses: actions/checkout@v2
38+
with:
39+
repository: 'opensearch-project/OpenSearch'
40+
path: OpenSearch2
41+
ref: '1.x'
42+
- name: Build OpenSearch2
43+
working-directory: ./OpenSearch2
44+
run: ./gradlew publishToMavenLocal -Dbuild.snapshot=false
3645
# dependencies: common-utils
3746
- name: Checkout common-utils
3847
uses: actions/checkout@v2
3948
with:
4049
repository: 'opensearch-project/common-utils'
4150
path: common-utils
42-
ref: '1.0'
51+
ref: 'main'
4352
- name: Build common-utils
4453
working-directory: ./common-utils
45-
run: ./gradlew publishToMavenLocal -Dopensearch.version=1.0.0
54+
run: ./gradlew publishToMavenLocal -Dopensearch.version=1.1.0 -Dbuild.snapshot=false
4655
# dependencies: job-scheduler
4756
- name: Checkout job-scheduler
4857
uses: actions/checkout@v2

models/interfaces.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ export interface Retry {
153153
export interface UIAction<Data> {
154154
action: Data;
155155
id: string;
156-
type: ActionType;
156+
type: ActionType | string;
157157
render: (uiAction: UIAction<Data>, onChangeAction: (uiAction: UIAction<Data>) => void) => JSX.Element | null;
158158
clone: (action: Data) => UIAction<Data>;
159159
content: () => JSX.Element | string | null;

public/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,14 @@
2626

2727
import { PluginInitializerContext } from "opensearch-dashboards/public";
2828
import { IndexManagementPlugin } from "./plugin";
29+
import { Action, UIAction } from "../models/interfaces";
2930

30-
export interface IndexManagementPluginSetup {}
31+
// export for other plugins to register action
32+
export { Action, UIAction } from "../models/interfaces";
33+
34+
export interface IndexManagementPluginSetup {
35+
registerAction: (actionType: string, uiActionCtor: new (action: Action) => UIAction<any>, defaultAction: Action) => void;
36+
}
3137
export interface IndexManagementPluginStart {}
3238

3339
export function plugin(initializerContext: PluginInitializerContext) {

public/pages/VisualCreatePolicy/components/States/State.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import ConfirmationModal from "../../../../components/ConfirmationModal";
1919
import Badge from "../Badge";
2020
import TransitionContent from "../Transition/TransitionContent";
2121
import { makeId } from "../../../../utils/helpers";
22-
import { getUIActionFromData } from "../../utils/helpers";
22+
import { actionRepoSingleton } from "../../utils/helpers";
2323

2424
interface StateProps {
2525
state: StateData;
@@ -112,7 +112,7 @@ const State = ({ state, isInitialState, idx, onClickEditState, onClickDeleteStat
112112
<EuiFlexGroup>
113113
{state.actions.map((action) => (
114114
<EuiFlexItem grow={false} key={makeId()}>
115-
<EuiPanel>{getUIActionFromData(action).content()}</EuiPanel>
115+
<EuiPanel>{actionRepoSingleton.getUIActionFromData(action).content()}</EuiPanel>
116116
</EuiFlexItem>
117117
))}
118118
</EuiFlexGroup>

public/pages/VisualCreatePolicy/containers/CreateAction/CreateAction.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { EuiFlyoutBody, EuiFlyoutFooter, EuiTitle, EuiFormRow, EuiSelect, EuiSpa
1414
import { UIAction, Action } from "../../../../../models/interfaces";
1515
import { actions } from "../../utils/constants";
1616
import TimeoutRetrySettings from "../../components/TimeoutRetrySettings";
17-
import { capitalizeFirstLetter, getUIAction } from "../../utils/helpers";
17+
import { actionRepoSingleton, capitalizeFirstLetter } from "../../utils/helpers";
1818
import FlyoutFooter from "../../components/FlyoutFooter";
1919
import EuiFormCustomLabel from "../../components/EuiFormCustomLabel";
2020

@@ -43,7 +43,7 @@ export default class CreateAction extends Component<CreateActionProps, CreateAct
4343
// This should be ephemeral and not change the actual list of actions yet as they might click cancel so we put it separate
4444
onChangeSelectedAction = (event: ChangeEvent<HTMLSelectElement>) => {
4545
const selectedAction = event.target.value;
46-
const uiAction = getUIAction(selectedAction);
46+
const uiAction = actionRepoSingleton.getUIAction(selectedAction);
4747
this.setState({ action: uiAction });
4848
};
4949

@@ -61,11 +61,7 @@ export default class CreateAction extends Component<CreateActionProps, CreateAct
6161
const { action } = this.state;
6262
const { editAction } = this.props;
6363

64-
const actionOptions = actions.map((action) => {
65-
const key =
66-
Object.keys(action)
67-
.filter((k) => k !== "timeout" && k !== "retry")
68-
.pop() || "";
64+
const actionOptions = actionRepoSingleton.getAllActionTypes().map((key) => {
6965
return {
7066
value: key,
7167
text: key

public/pages/VisualCreatePolicy/containers/CreateState/CreateState.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ import CreateTransition from "../CreateTransition";
3535
import CreateAction from "../CreateAction";
3636
import Actions from "./Actions";
3737
import Transitions from "./Transitions";
38-
import { getOrderInfo, getUIActionFromData } from "../../utils/helpers";
3938
import { makeId } from "../../../../utils/helpers";
39+
import { actionRepoSingleton, getOrderInfo } from "../../utils/helpers";
4040

4141
interface CreateStateProps {
4242
policy: Policy;
@@ -69,7 +69,7 @@ export default class CreateState extends Component<CreateStateProps, CreateState
6969
editAction: null,
7070
createTransition: false,
7171
editTransition: null,
72-
actions: props.state?.actions?.map((action) => getUIActionFromData(action)) || [],
72+
actions: props.state?.actions?.map((action) => actionRepoSingleton.getUIActionFromData(action)) || [],
7373
transitions: props.state?.transitions?.map((transition) => ({ id: makeId(), transition })) || [],
7474
afterBeforeState,
7575
order,

public/pages/VisualCreatePolicy/utils/helpers.test.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
* GitHub history for details.
1010
*/
1111

12-
import { capitalizeFirstLetter, convertTemplatesToArray, getOrderInfo } from "./helpers";
13-
import { ISMTemplate } from "../../../../models/interfaces";
12+
import { actionRepoSingleton, capitalizeFirstLetter, convertTemplatesToArray, getOrderInfo } from "./helpers";
13+
import { Action, ISMTemplate, UIAction } from "../../../../models/interfaces";
14+
import { makeId } from "../../../utils/helpers";
1415

1516
test("converts all ism template formats into a list of ism templates", () => {
1617
expect(convertTemplatesToArray(null)).toEqual([]);
@@ -48,3 +49,40 @@ test("getOrderInfo returns correct order info", () => {
4849
expect(getOrderInfo(null, [state]).order).toBe("after");
4950
expect(getOrderInfo(null, [state]).afterBeforeState).toBe(state.name);
5051
});
52+
53+
interface DummyAction extends Action {
54+
dummy: {};
55+
}
56+
57+
const DEFAULT_DUMMY: DummyAction = {
58+
dummy: {},
59+
};
60+
61+
class DummyUIAction implements UIAction<DummyAction> {
62+
id: string;
63+
action: DummyAction;
64+
type = "dummy";
65+
66+
constructor(action: DummyAction, id: string = makeId()) {
67+
this.action = action;
68+
this.id = id;
69+
}
70+
71+
content = () => `Dummy content.`;
72+
73+
clone = (action: DummyAction) => new DummyUIAction(action, this.id);
74+
75+
render = (action: UIAction<DummyAction>, onChangeAction: (action: UIAction<DummyAction>) => void) => {
76+
return null;
77+
};
78+
79+
toAction = () => this.action;
80+
}
81+
82+
test("action repository usage", () => {
83+
expect(actionRepoSingleton.getAllActionTypes().length).toBe(13);
84+
actionRepoSingleton.registerAction("dummy", DummyUIAction, DEFAULT_DUMMY);
85+
expect(actionRepoSingleton.getAllActionTypes().length).toBe(14);
86+
expect(actionRepoSingleton.getUIAction("dummy") instanceof DummyUIAction).toBe(true);
87+
expect(actionRepoSingleton.getUIActionFromData(DEFAULT_DUMMY) instanceof DummyUIAction).toBe(true);
88+
});

public/pages/VisualCreatePolicy/utils/helpers.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,53 @@ export const getUIAction = (actionType: string): UIAction<any> => {
100100
}
101101
};
102102

103+
class ActionRepository {
104+
repository: { [actionType: string]: [new (action: Action) => UIAction<any>, Action] } = {
105+
allocation: [AllocationUIAction, DEFAULT_ALLOCATION],
106+
close: [CloseUIAction, DEFAULT_CLOSE],
107+
delete: [DeleteUIAction, DEFAULT_DELETE],
108+
force_merge: [ForceMergeUIAction, DEFAULT_FORCE_MERGE],
109+
index_priority: [IndexPriorityUIAction, DEFAULT_INDEX_PRIORITY],
110+
notification: [NotificationUIAction, DEFAULT_NOTIFICATION],
111+
open: [OpenUIAction, DEFAULT_OPEN],
112+
read_only: [ReadOnlyUIAction, DEFAULT_READ_ONLY],
113+
read_write: [ReadWriteUIAction, DEFAULT_READ_WRITE],
114+
replica_count: [ReplicaCountUIAction, DEFAULT_REPLICA_COUNT],
115+
rollover: [RolloverUIAction, DEFAULT_ROLLOVER],
116+
rollup: [RollupUIAction, DEFAULT_ROLLUP],
117+
snapshot: [SnapshotUIAction, DEFAULT_SNAPSHOT],
118+
};
119+
120+
getAllActionTypes = () => {
121+
return Object.keys(this.repository);
122+
};
123+
124+
registerAction = (actionType: string, uiActionCtor: new (action: Action) => UIAction<any>, defaultAction: Action) => {
125+
if (this.repository.hasOwnProperty(actionType)) {
126+
throw new Error(`Cannot register an action twice in the repository [type=${actionType}]`);
127+
}
128+
129+
this.repository[actionType] = [uiActionCtor, defaultAction];
130+
};
131+
132+
getUIActionFromData = (action: Action) => {
133+
const actionType = Object.keys(action)
134+
.filter((key) => key !== "timeout" && key !== "retry")
135+
.pop();
136+
if (!actionType) throw new Error(`Failed to get action using type [${actionType}]`);
137+
const uiAction = this.getUIAction(actionType);
138+
return uiAction.clone(action);
139+
};
140+
141+
getUIAction = (actionType: string): UIAction<any> => {
142+
const uiAction = this.repository[actionType];
143+
if (!uiAction) throw new Error(`Action type [${actionType}] not supported`);
144+
return new uiAction[0](uiAction[1]);
145+
};
146+
}
147+
148+
export const actionRepoSingleton = new ActionRepository();
149+
103150
// Takes in the ismTemplates which could be a single object, array, or not defined and returns them reformatted as a list
104151
export const convertTemplatesToArray = (ismTemplates: ISMTemplate[] | ISMTemplate | null | undefined): ISMTemplate[] => {
105152
const templates = [];

public/plugin.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import { AppMountParameters, CoreSetup, CoreStart, Plugin, PluginInitializerContext } from "../../../src/core/public";
2828
import { IndexManagementPluginSetup } from ".";
2929
import { IndexManagementPluginStart } from ".";
30+
import { actionRepoSingleton } from "./pages/VisualCreatePolicy/utils/helpers";
3031

3132
export class IndexManagementPlugin implements Plugin<IndexManagementPluginSetup, IndexManagementPluginStart> {
3233
constructor(private readonly initializerContext: PluginInitializerContext) {
@@ -49,10 +50,16 @@ export class IndexManagementPlugin implements Plugin<IndexManagementPluginSetup,
4950
return renderApp(coreStart, params);
5051
},
5152
});
52-
return {};
53+
return {
54+
registerAction: (actionType, uiActionCtor, defaultAction) => {
55+
actionRepoSingleton.registerAction(actionType, uiActionCtor, defaultAction);
56+
},
57+
};
5358
}
5459

5560
public start(core: CoreStart): IndexManagementPluginStart {
61+
Object.freeze(actionRepoSingleton.repository);
62+
// After this point, calling registerAction will throw error because "Object is not extensible"
5663
return {};
5764
}
5865
}

0 commit comments

Comments
 (0)