Skip to content

Commit

Permalink
feat: create flow structure based on the flow schema
Browse files Browse the repository at this point in the history
fixes #349
  • Loading branch information
leleueri authored and gcusnieux committed Jun 10, 2021
1 parent c617c91 commit 330e8f8
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 18 deletions.
46 changes: 33 additions & 13 deletions src/policy-studio/gv-policy-studio.js
Original file line number Diff line number Diff line change
Expand Up @@ -841,12 +841,7 @@ export class GvPolicyStudio extends KeyboardElement(LitElement) {

_onSubmitFlow({ detail: { values } }) {
const selectedFlow = this.getSelectedFlow();
selectedFlow.name = values.name || '';
selectedFlow.condition = values.condition || '';
selectedFlow['path-operator'] = values['path-operator'];
selectedFlow.methods = values.methods;
selectedFlow.consumers = values.consumers;
selectedFlow._dirty = true;
Object.assign(selectedFlow, values, { _dirty: true });
this.isDirty = true;
this._refresh();
}
Expand Down Expand Up @@ -1196,23 +1191,48 @@ export class GvPolicyStudio extends KeyboardElement(LitElement) {
_addFlow(collection, duplicate = null) {
const flow =
duplicate == null
? {
name: '',
pre: [],
post: [],
_dirty: true,
'path-operator': { path: '/', operator: 'STARTS_WITH' },
}
? this._createFlowFromSchema()
: {
...duplicate,
_id: null,
_dirty: true,
};

collection.push(flow);
this.isDirty = true;
return collection;
}

_createFlowFromSchema() {
const newFlow = {
name: '',
pre: [],
post: [],
_dirty: true,
};

return this._instantiate(this.flowSchema.properties, newFlow);
}

_instantiate(propertiesDefinition, initiator = {}) {
const property = { ...initiator };

if (propertiesDefinition) {
for (const key of Object.keys(propertiesDefinition)) {
const entry = propertiesDefinition[key];

if (entry.type === 'object') {
property[key] = this._instantiate(entry.properties, (initiator = {}));
}
if (entry.default !== undefined) {
property[key] = entry.default;
}
}
}

return property;
}

_deleteFlow(collection, flow) {
const index = collection.indexOf(flow);
collection.splice(index, 1);
Expand Down
15 changes: 15 additions & 0 deletions stories/policy-studio/gv-policy-studio.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,18 @@ export const AM = makeStory(conf, {
},
],
});

export const AMEditable = makeStory(conf, {
items: [
{
policies: amPolicies.data.map((policy) => {
policy.icon = icon;
return policy;
}),
definition: amDefinition,
flowSchema: amForm,
'@gv-policy-studio:fetch-documentation': fetchPolicyDocumentation.bind(this),
'can-add': true,
},
],
});
91 changes: 89 additions & 2 deletions stories/policy-studio/gv-policy-studio.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ describe('P O L I C Y S T U D I O', () => {
component = page.create('gv-policy-studio', {});
component.policies = policies.data;
component.resourceTypes = resourceTypes.data;
component.flowSchema = {};
});

afterEach(() => {
Expand Down Expand Up @@ -151,6 +152,61 @@ describe('P O L I C Y S T U D I O', () => {
expect(component.getSelectedFlow()).toBeDefined();
expect(component._tabId).toEqual('design');

component.flowSchema = {
type: 'object',
id: 'apim',
properties: {
name: {
title: 'Name',
description: 'The name of flow. If empty, the name will be generated with the path and methods',
type: 'string',
},
'path-operator': {
type: 'object',
title: 'Path',
properties: {
operator: {
title: 'Operator path',
description: 'The operator path',
type: 'string',
enum: ['EQUALS', 'STARTS_WITH'],
default: 'STARTS_WITH',
'x-schema-form': {
titleMap: {
EQUALS: 'Equals',
STARTS_WITH: 'Starts with',
},
},
},
path: {
title: 'Path',
description: 'The path of flow (must start by /)',
type: 'string',
pattern: '^/',
default: '/',
},
},
required: ['path', 'operator'],
},
methods: {
title: 'Methods',
description: 'The HTTP methods of flow (ALL if empty)',
type: 'array',
items: {
type: 'string',
enum: ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'TRACE'],
},
},
condition: {
title: 'Condition',
description: 'The extra condition of flow',
type: 'string',
},
},
required: [],
disabled: [],
};

component.updateComplete.then(() => {
component._onAddFlowPlan({ detail: { planIndex: 1 } });

Expand All @@ -163,6 +219,10 @@ describe('P O L I C Y S T U D I O', () => {
expect(createdFlow.post).toEqual([]);
expect(createdFlow.pre).toEqual([]);
expect(createdFlow._id).toBeDefined();
expect(createdFlow['path-operator']).toBeDefined();
expect(createdFlow['path-operator'].operator).toBeDefined();
expect(createdFlow['path-operator'].path).toBeDefined();
expect(createdFlow.type).not.toBeDefined();
done();
});
});
Expand All @@ -181,16 +241,44 @@ describe('P O L I C Y S T U D I O', () => {
describe('F L O W S', () => {
test('should add flow', async () => {
component.definition = { flows: [] };
component.flowSchema = {
type: 'object',
id: 'am',
properties: {
name: {
title: 'Name',
description: 'The name of flow. If empty, the name will be generated with the path and methods',
type: 'string',
default: 'New Flow',
},
type: {
title: 'Type',
description: 'The type of flow',
type: 'string',
default: 'ROOT',
enum: ['ROOT', 'LOGIN', 'CONSENT', 'REGISTER'],
},
condition: {
title: 'Condition',
description: 'The condition of flow',
type: 'string',
},
},
required: [],
disabled: [],
};

await component._onAddFlow();

expect(component.definition.flows.length).toEqual(1);
const createdFlow = component.definition.flows[0];
expect(createdFlow._dirty).toEqual(true);
expect(createdFlow._id).toBeDefined();
expect(createdFlow.name).toEqual('');
expect(createdFlow.name).toEqual('New Flow');
expect(createdFlow.post).toEqual([]);
expect(createdFlow.pre).toEqual([]);
expect(createdFlow.type).toEqual('ROOT');
expect(createdFlow['path-operator']).not.toBeDefined();
});

test('should duplicate flow', async () => {
Expand Down Expand Up @@ -239,7 +327,6 @@ describe('P O L I C Y S T U D I O', () => {
expect(component.definition.flows[0].name).toEqual(updatedFlow.name);
expect(component.definition.flows[0]['path-operator']).toEqual({ path: '/', operator: 'STARTS_WITH' });
expect(component.definition.flows[0].methods).toEqual(['GET', 'POST']);
expect(component.definition.flows[0].condition).toEqual('');
});

test('should update definition when submit flow schema', async () => {
Expand Down
8 changes: 5 additions & 3 deletions stories/resources/schemas/am.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
{
"type": "object",
"id": "apim",
"id": "am",
"properties": {
"name": {
"title": "Name",
"description": "The name of flow. If empty, the name will be generated with the path and methods",
"type": "string"
"type": "string",
"default": "New Flow"
},
"type": {
"title": "Type",
"description": "The type of flow",
"type": "string",
"default": "ROOT",
"enum": ["ROOT", "LOGIN", "CONSENT", "REGISTER"]
},
"condition": {
Expand All @@ -20,5 +22,5 @@
}
},
"required": [],
"disabled": ["type", "condition"]
"disabled": []
}

0 comments on commit 330e8f8

Please sign in to comment.