-
-
{label}
-
+
+
+
+ {label}
+
+
{description}
- {readOnly ?
-
:
+ {readOnly ? (
+
+ ) : (
{value &&
}
{!value &&
}
-
{value ? 'On' : 'Off'}
+
{value ? 'On' : 'Off'}
- }
+ )}
@@ -519,23 +574,22 @@ export class NgBoxBooleanRenderer extends Component {
}
export class NgArrayRenderer extends Component {
-
canShowActions(path) {
const breadcrumbAsArray = this.props.breadcrumb || [];
const pathAsArray = path || this.props.path || [];
- if (this.props.breadcrumb === undefined)
- return true;
+ if (this.props.breadcrumb === undefined) return true;
- if (path)
- return isEqual(pathAsArray, breadcrumbAsArray)
+ if (path) return isEqual(pathAsArray, breadcrumbAsArray);
- return pathAsArray.length >= breadcrumbAsArray.length &&
+ return (
+ pathAsArray.length >= breadcrumbAsArray.length &&
(pathAsArray.join('-').startsWith(pathAsArray.join('-')) ||
pathAsArray.join('-').startsWith(pathAsArray.join('-')))
+ );
}
- isAnObject = v => typeof v === 'object' && v !== null && !Array.isArray(v);
+ isAnObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
defaultValues = (current) => ({
number: () => 0,
@@ -544,23 +598,22 @@ export class NgArrayRenderer extends Component {
array: () => [],
select: () => current?.props?.options[0] || '',
form: () => ({
- ...this.generateDefaultValue(current.schema)
+ ...this.generateDefaultValue(current.schema),
}),
- object: () => { },
- json: () => { },
- })
-
- generateDefaultValue = obj => {
- return Object.entries(obj)
- .reduce((acc, current) => {
- const type = current[1] ? current[1].type : undefined;
- const value = this.defaultValues(current[1])[type];
- return {
- ...acc,
- [current[0]]: value ? value() : ''
- }
- }, {})
- }
+ object: () => {},
+ json: () => {},
+ });
+
+ generateDefaultValue = (obj) => {
+ return Object.entries(obj).reduce((acc, current) => {
+ const type = current[1] ? current[1].type : undefined;
+ const value = this.defaultValues(current[1])[type];
+ return {
+ ...acc,
+ [current[0]]: value ? value() : '',
+ };
+ }, {});
+ };
render() {
const schema = this.props.schema;
@@ -568,19 +621,21 @@ export class NgArrayRenderer extends Component {
const readOnly = this.props.readOnly;
const ItemRenderer = schema.itemRenderer || this.props.rawSchema.itemRenderer;
- const showActions = this.canShowActions()
+ const showActions = this.canShowActions();
- if (readOnly && Array.isArray(this.props.value) && this.props.value.length === 0)
- return null;
+ if (readOnly && Array.isArray(this.props.value) && this.props.value.length === 0) return null;
return (
-
+
{Array.isArray(this.props.value) &&
this.props.value.map((value, idx) => {
- const path = [...this.props.path, String(idx)]
+ const path = [...this.props.path, String(idx)];
const showItem = this.canShowActions(path);
return (
@@ -591,10 +646,13 @@ export class NgArrayRenderer extends Component {
width: '100%',
outline: showItem ? 'rgb(65, 65, 62) solid 1px' : 'none',
padding: showItem ? '6px' : 0,
- marginBottom: showItem ? '6px' : 0
- }} key={path}>
- {!ItemRenderer && (
- readOnly ? :
+ marginBottom: showItem ? '6px' : 0,
+ }}
+ key={path}>
+ {!ItemRenderer &&
+ (readOnly ? (
+
+ ) : (
- )}
+ ))}
{ItemRenderer && (
)}
- {showActions && !readOnly && }
+ {showActions && !readOnly && (
+
+ )}
);
})}
- {showActions && !readOnly &&
}
+ {showActions && !readOnly && (
+
+ )}
);
@@ -686,18 +747,22 @@ export class NgObjectRenderer extends Component {
const readOnly = this.props.readOnly;
const ItemRenderer = schema.itemRenderer || this.props.rawSchema.itemRenderer;
- if (readOnly && Object.entries(this.props.value || {}).length === 0)
- return null;
+ if (readOnly && Object.entries(this.props.value || {}).length === 0) return null;
return (
- {readOnly ? {
- return <>
- {`${entry[0]} - ${entry[1]}`}
-
- >
- })} /> :
+ {readOnly ? (
+ {
+ return (
+ <>
+ {`${entry[0]} - ${entry[1]}`}
+
+ >
+ );
+ })}
+ />
+ ) : (
(
- {
- const newObject = this.props.value ? { ...this.props.value } : {};
- newObject[key] = e;
- this.props.onChange(newObject);
- }}
- {...props}
- />
- )
+ {
+ const newObject = this.props.value ? { ...this.props.value } : {};
+ newObject[key] = e;
+ this.props.onChange(newObject);
+ }}
+ {...props}
+ />
+ )
: null
}
/>
- }
+ )}
);
}
@@ -990,21 +1055,23 @@ export class NgSelectRenderer extends Component {
return (
{readOnly && }
- {!readOnly &&
);
}
-}
\ No newline at end of file
+}
diff --git a/otoroshi/javascript/src/forms/entities/JwtVerifier.js b/otoroshi/javascript/src/forms/entities/JwtVerifier.js
index 826c3e2f1c..56839d7823 100644
--- a/otoroshi/javascript/src/forms/entities/JwtVerifier.js
+++ b/otoroshi/javascript/src/forms/entities/JwtVerifier.js
@@ -7,7 +7,7 @@ const AlgoSettingsForm = {
label: 'Signature',
collapsable: true,
props: {
- showSummary: true
+ showSummary: true,
},
schema: {
type: {
@@ -22,71 +22,74 @@ const AlgoSettingsForm = {
{ label: 'JWK Set (only for verification)', value: 'JWKSAlgoSettings' },
{ label: 'RSASSA-PKCS1 + SHA from KeyPair', value: 'RSAKPAlgoSettings' },
{ label: 'ECDSA + SHA from KeyPair', value: 'ESKPAlgoSettings' },
- { label: 'Otoroshi KeyPair from token kid (only for verification)', value: 'KidAlgoSettings' }
- ]
- }
+ {
+ label: 'Otoroshi KeyPair from token kid (only for verification)',
+ value: 'KidAlgoSettings',
+ },
+ ],
+ },
},
onlyExposedCerts: {
type: 'bool',
- label: 'Use only exposed keypairs'
+ label: 'Use only exposed keypairs',
},
size: {
type: 'dots',
label: 'SHA size',
props: {
- options: [256, 384, 512]
- }
+ options: [256, 384, 512],
+ },
},
secret: {
type: 'string',
- label: 'HMAC secret'
+ label: 'HMAC secret',
},
base64: {
type: 'bool',
- label: 'Base64 encoded secret'
+ label: 'Base64 encoded secret',
},
publicKey: {
type: 'text',
- label: 'Public key'
+ label: 'Public key',
},
privateKey: {
type: 'text',
- label: 'Private key'
+ label: 'Private key',
},
certId: {
- type: "select",
- label: "Cert. id",
+ type: 'select',
+ label: 'Cert. id',
props: {
- optionsFrom: "/bo/api/proxy/api/certificates",
+ optionsFrom: '/bo/api/proxy/api/certificates',
optionsTransformer: {
- label: "name",
- value: "id"
- }
- }
+ label: 'name',
+ value: 'id',
+ },
+ },
},
url: {
type: 'string',
- label: 'URL'
+ label: 'URL',
},
timeout: {
type: 'number',
- label: 'HTTP call timeout'
+ label: 'HTTP call timeout',
},
ttl: {
type: 'number',
- label: 'Cache TTL for the keyset'
+ label: 'Cache TTL for the keyset',
},
headers: {
- type: "object",
- label: "Headers"
+ type: 'object',
+ label: 'Headers',
},
kty: {
type: 'select',
label: 'Key type',
props: {
- options: ['RSA', 'EC']
- }
- }
+ options: ['RSA', 'EC'],
+ },
+ },
},
flow: (props, v) => {
return {
@@ -96,177 +99,205 @@ const AlgoSettingsForm = {
RSAKPAlgoSettings: ['type', 'size', 'certId'],
ESKPAlgoSettings: ['type', 'size', 'certId'],
ESAlgoSettings: ['type', 'size', 'publicKey', 'privateKey'],
- JWKSAlgoSettings: [
- 'type',
- 'url',
- 'timeout',
- 'ttl',
- 'headers',
- 'kty'
- ],
- [undefined]: ['type']
- }[v.value?.type]
- }
-}
+ JWKSAlgoSettings: ['type', 'url', 'timeout', 'ttl', 'headers', 'kty'],
+ [undefined]: ['type'],
+ }[v.value?.type];
+ },
+};
const VERIFIER_STRATEGIES = [
{
- strategy: 'PassThrough', title: ['Verify'],
+ strategy: 'PassThrough',
+ title: ['Verify'],
desc: 'PassThrough will only verifiy token signing and fields values if provided. ',
- tags: ['verify']
+ tags: ['verify'],
},
{
- strategy: 'Sign', title: ['Verify and re-sign'],
- desc: 'Sign will do the same as PassThrough plus will re-sign the JWT token with the provided algo. settings.',
- tags: ['verify', 'sign']
+ strategy: 'Sign',
+ title: ['Verify and re-sign'],
+ desc:
+ 'Sign will do the same as PassThrough plus will re-sign the JWT token with the provided algo. settings.',
+ tags: ['verify', 'sign'],
},
{
- strategy: 'Transform', title: ['Verify, re-sign and Transform'],
+ strategy: 'Transform',
+ title: ['Verify, re-sign and Transform'],
desc: 'Transform will do the same as Sign plus will be able to transform the token.',
- tags: ['verify', 'sign', 'transform']
- }
-]
+ tags: ['verify', 'sign', 'transform'],
+ },
+];
const StrategyForm = {
type: {
- renderer: props => {
+ renderer: (props) => {
const [open, setOpen] = useState(false);
if (props.readOnly) {
- return
-
- {props.value}
-
-
+ return (
+
+
+ {props.value}
+
+
+ );
} else {
if (!open) {
- return
-
-
+ return (
+
+
+
+ );
} else {
- return
- {VERIFIER_STRATEGIES.map(({ strategy, desc, title, tags }) => {
- return
+
+ );
+ })}
+
+ );
}
}
- }
- }
-}
+ },
+ },
+};
const JwtLocationExamples = {
- renderer: props => {
- if (props.readOnly)
- return null;
+ renderer: (props) => {
+ if (props.readOnly) return null;
else {
- return
-
Examples
-
- A common use case is a request containing a JSON Web token prefixed with Bearer to indicate that the user accessing the resources is authenticated.
- In our example, the token location is the Authorization header.
- To match this case, you must set Authorization for the name entry and Bearer followed by a space for the Remove value entry.
-
-
+ Examples
+
+ A common use case is a request containing a JSON Web token prefixed with Bearer to
+ indicate that the user accessing the resources is authenticated.
+
+ In our example, the token location is the Authorization header.
+
+ To match this case, you must set Authorization for the name entry and Bearer followed by
+ a space for the Remove value entry.
+
+
-
+ }}
+ flow={[
+ {
+ type: 'group',
+ collapsable: false,
+ name: 'A bearer token expected in Authorization header',
+ fields: ['header'],
+ },
+ ]}
+ />
+
+ );
}
- }
-}
+ },
+};
export default {
config_flow: [
{
type: 'group',
name: 'Informations',
fields: ['id', 'name', 'desc'],
- summaryFields: ['name', 'desc']
+ summaryFields: ['name', 'desc'],
},
{
type: 'group',
- name: "Organizations & teams",
- fields: ['_loc']
+ name: 'Organizations & teams',
+ fields: ['_loc'],
},
'source',
'algoSettings',
@@ -277,10 +308,8 @@ export default {
type: 'group',
name: 'Misc.',
collapsed: true,
- fields: [
- 'metadata', 'tags'
- ]
- }
+ fields: ['metadata', 'tags'],
+ },
],
config_schema: {
token: {
@@ -288,26 +317,26 @@ export default {
label: 'JSON Payload',
props: {
mode: 'json',
- editorOnly: true
- }
+ editorOnly: true,
+ },
},
_loc: {
type: 'location',
props: {
- label: 'Location'
- }
+ label: 'Location',
+ },
},
id: {
type: 'string',
- label: 'Id'
+ label: 'Id',
},
name: {
type: 'string',
- label: 'Name'
+ label: 'Name',
},
desc: {
type: 'string',
- label: 'Description'
+ label: 'Description',
},
source: {
type: 'form',
@@ -316,8 +345,8 @@ export default {
props: {
showSummary: true,
ngOptions: {
- spread: true
- }
+ spread: true,
+ },
},
schema: {
type: {
@@ -325,60 +354,60 @@ export default {
label: 'Type',
props: {
ngOptions: {
- spread: true
+ spread: true,
},
options: [
{ value: 'InHeader', label: 'Header' },
{ value: 'InQueryParam', label: 'Query string' },
- { value: 'InCookie', label: 'Cookie' }
- ]
- }
+ { value: 'InCookie', label: 'Cookie' },
+ ],
+ },
},
name: {
type: 'string',
- label: 'Name'
+ label: 'Name',
},
remove: {
type: 'string',
placeholder: 'Bearer ',
label: 'Remove value',
props: {
- subTitle: '(Optional): String to remove from the value to access to the token'
- }
+ subTitle: '(Optional): String to remove from the value to access to the token',
+ },
},
- debug: JwtLocationExamples
+ debug: JwtLocationExamples,
},
flow: [
'type',
{
type: 'group',
collapsable: false,
- visible: props => props?.type === 'InHeader',
+ visible: (props) => props?.type === 'InHeader',
name: 'Header informations',
- fields: ['name', 'remove', 'debug']
+ fields: ['name', 'remove', 'debug'],
},
{
type: 'group',
collapsable: false,
- visible: props => props?.type === 'InQueryParam',
+ visible: (props) => props?.type === 'InQueryParam',
name: 'Query param name',
- fields: ['name']
+ fields: ['name'],
},
{
type: 'group',
collapsable: false,
- visible: props => props?.type === 'InCookie',
+ visible: (props) => props?.type === 'InCookie',
name: 'Cookie name',
- fields: ['name']
- }
- ]
+ fields: ['name'],
+ },
+ ],
},
algoSettings: {
...AlgoSettingsForm,
label: 'Token validation',
props: {
- showSummary: true
- }
+ showSummary: true,
+ },
},
strategy: {
type: 'form',
@@ -387,8 +416,8 @@ export default {
props: {
showSummary: true,
ngOptions: {
- spread: true
- }
+ spread: true,
+ },
},
schema: {
...StrategyForm,
@@ -400,30 +429,32 @@ export default {
schema: {
fields: {
type: 'object',
- label: "Verify token fields",
+ label: 'Verify token fields',
props: {
- placeholderKey: "Field name",
- placeholderValue: "Field value",
- help: "When the JWT token is checked, each field specified here will be verified with the provided value"
- }
+ placeholderKey: 'Field name',
+ placeholderValue: 'Field value',
+ help:
+ 'When the JWT token is checked, each field specified here will be verified with the provided value',
+ },
},
arrayFields: {
type: 'object',
- label: "Verify token array value",
+ label: 'Verify token array value',
props: {
- placeholderKey: "Field name",
- placeholderValue: "One or more comma separated values in the array",
- help: "When the JWT token is checked, each field specified here will be verified if the provided value is contained in the array"
- }
- }
- }
+ placeholderKey: 'Field name',
+ placeholderValue: 'One or more comma separated values in the array',
+ help:
+ 'When the JWT token is checked, each field specified here will be verified if the provided value is contained in the array',
+ },
+ },
+ },
},
algoSettings: AlgoSettingsForm,
transformSettings: {
type: 'form',
collapsable: true,
label: 'Transform settings',
- visible: value => value?.strategy?.type === 'Transform',
+ visible: (value) => value?.strategy?.type === 'Transform',
schema: {
location: {
type: 'form',
@@ -431,61 +462,61 @@ export default {
label: 'Exit Token location',
props: {
ngOptions: {
- spread: true
- }
+ spread: true,
+ },
},
schema: {
type: {
type: 'select',
props: {
ngOptions: {
- spread: true
+ spread: true,
},
options: [
{ value: 'InHeader', label: 'Header' },
{ value: 'InQueryParam', label: 'Query string' },
- { value: 'InCookie', label: 'Cookie' }
- ]
- }
+ { value: 'InCookie', label: 'Cookie' },
+ ],
+ },
},
name: {
type: 'string',
- label: 'Name'
+ label: 'Name',
},
remove: {
type: 'string',
placeholder: 'Bearer ',
label: 'Remove value',
props: {
- subTitle: '(Optional): String to remove from the value to access to the token'
- }
+ subTitle: '(Optional): String to remove from the value to access to the token',
+ },
},
- debug: JwtLocationExamples
+ debug: JwtLocationExamples,
},
flow: [
'type',
{
type: 'group',
collapsable: false,
- visible: props => props?.type === 'InHeader',
+ visible: (props) => props?.type === 'InHeader',
name: 'Header informations',
- fields: ['name', 'remove', 'debug']
+ fields: ['name', 'remove', 'debug'],
},
{
type: 'group',
collapsable: false,
- visible: props => props?.type === 'InQueryParam',
+ visible: (props) => props?.type === 'InQueryParam',
name: 'Query param name',
- fields: ['name']
+ fields: ['name'],
},
{
type: 'group',
collapsable: false,
- visible: props => props?.type === 'InCookie',
+ visible: (props) => props?.type === 'InCookie',
name: 'Cookie name',
- fields: ['name']
- }
- ]
+ fields: ['name'],
+ },
+ ],
},
mappingSettings: {
type: 'form',
@@ -494,57 +525,56 @@ export default {
schema: {
map: {
type: 'object',
- label: "Rename token fields",
+ label: 'Rename token fields',
props: {
- placeholderKey: "Field name",
- placeholderValue: "Field value",
- help: "When the JWT token is transformed, it is possible to change a field name, just specify origin field name and target field name"
- }
+ placeholderKey: 'Field name',
+ placeholderValue: 'Field value',
+ help:
+ 'When the JWT token is transformed, it is possible to change a field name, just specify origin field name and target field name',
+ },
},
values: {
type: 'object',
- label: "Set token fields",
+ label: 'Set token fields',
props: {
- placeholderKey: "Field name",
- placeholderValue: "Field value",
- help: "When the JWT token is transformed, it is possible to add new field with static values, just specify field name and value"
- }
+ placeholderKey: 'Field name',
+ placeholderValue: 'Field value',
+ help:
+ 'When the JWT token is transformed, it is possible to add new field with static values, just specify field name and value',
+ },
},
remove: {
type: 'string',
array: true,
label: 'Remove token fields',
props: {
- help: 'When the JWT token is transformed, it is possible to remove fields'
- }
- }
- }
- }
+ help: 'When the JWT token is transformed, it is possible to remove fields',
+ },
+ },
+ },
+ },
},
- flow: [
- 'location',
- 'mappingSettings'
- ]
- }
+ flow: ['location', 'mappingSettings'],
+ },
},
flow: (_, v) => {
- const strategy = v.value?.type
+ const strategy = v.value?.type;
return {
- 'PassThrough': ['type'],
- 'Sign': ['type', 'algoSettings'],
- 'Transform': ['type', 'algoSettings'],
- [undefined]: ['type']
- }[strategy]
- }
+ PassThrough: ['type'],
+ Sign: ['type', 'algoSettings'],
+ Transform: ['type', 'algoSettings'],
+ [undefined]: ['type'],
+ }[strategy];
+ },
},
metadata: {
type: 'object',
- label: 'Metadata'
+ label: 'Metadata',
},
tags: {
type: 'string',
label: 'Tags',
- array: true
- }
- }
-}
\ No newline at end of file
+ array: true,
+ },
+ },
+};
diff --git a/otoroshi/javascript/src/forms/index.js b/otoroshi/javascript/src/forms/index.js
index 4cdbbaf8b8..a349e3cc5a 100644
--- a/otoroshi/javascript/src/forms/index.js
+++ b/otoroshi/javascript/src/forms/index.js
@@ -1,22 +1,19 @@
-import { Plugins } from "./ng_plugins";
-import { Wizards } from "./wizards";
+import { Plugins } from './ng_plugins';
+import { Wizards } from './wizards';
const ClassifiedForms = {
plugins: Plugins.reduce((acc, c) => {
return {
...acc,
- [c.id.split('.').slice(-1)]: c
- }
+ [c.id.split('.').slice(-1)]: c,
+ };
}, {}),
- wizards: Wizards
-}
+ wizards: Wizards,
+};
-const Forms = ({
+const Forms = {
...ClassifiedForms.plugins,
...ClassifiedForms.wizards,
-})
+};
-export {
- ClassifiedForms,
- Forms
-}
\ No newline at end of file
+export { ClassifiedForms, Forms };
diff --git a/otoroshi/javascript/src/forms/ng_plugins/GraphQLBackend.js b/otoroshi/javascript/src/forms/ng_plugins/GraphQLBackend.js
index 56f1c6444e..fe83b8b443 100644
--- a/otoroshi/javascript/src/forms/ng_plugins/GraphQLBackend.js
+++ b/otoroshi/javascript/src/forms/ng_plugins/GraphQLBackend.js
@@ -1,5 +1,5 @@
import React from 'react';
-import GraphQLForm from "../../pages/RouteDesigner/GraphQLForm";
+import GraphQLForm from '../../pages/RouteDesigner/GraphQLForm';
export default {
id: 'cp:otoroshi.next.plugins.GraphQLBackend',
diff --git a/otoroshi/javascript/src/forms/ng_plugins/Http3Switch.js b/otoroshi/javascript/src/forms/ng_plugins/Http3Switch.js
index 5c1a3fe4a7..7070f55667 100644
--- a/otoroshi/javascript/src/forms/ng_plugins/Http3Switch.js
+++ b/otoroshi/javascript/src/forms/ng_plugins/Http3Switch.js
@@ -12,7 +12,7 @@ export default {
protocols: {
label: 'Protocols',
type: 'string',
- array: true
+ array: true,
},
},
config_flow: ['ma', 'domain', 'protocols'],
diff --git a/otoroshi/javascript/src/forms/ng_plugins/JwtSigner.js b/otoroshi/javascript/src/forms/ng_plugins/JwtSigner.js
index ba849a0db0..68bad5a153 100644
--- a/otoroshi/javascript/src/forms/ng_plugins/JwtSigner.js
+++ b/otoroshi/javascript/src/forms/ng_plugins/JwtSigner.js
@@ -1,36 +1,34 @@
-import { JwtVerifierLauncher } from "../wizards/JwtVerifierLauncher";
+import { JwtVerifierLauncher } from '../wizards/JwtVerifierLauncher';
export default {
- id: "cp:otoroshi.next.plugins.JwtSigner",
+ id: 'cp:otoroshi.next.plugins.JwtSigner',
config_schema: {
- "fail_if_present": {
- type: "box-bool",
- label: "Fail if present",
+ fail_if_present: {
+ type: 'box-bool',
+ label: 'Fail if present',
props: {
- description: "If a token is present in the incoming request, the plugin will reject the call."
- }
+ description:
+ 'If a token is present in the incoming request, the plugin will reject the call.',
+ },
},
- "replace_if_present": {
- type: "box-bool",
- label: "Replace if present",
+ replace_if_present: {
+ type: 'box-bool',
+ label: 'Replace if present',
props: {
- description: "If a token is present in the incoming request, the plugin will always replace the token with a new one."
- }
+ description:
+ 'If a token is present in the incoming request, the plugin will always replace the token with a new one.',
+ },
},
verifier: {
- label: "Verifier",
- type: "JwtVerifierWizard",
+ label: 'Verifier',
+ type: 'JwtVerifierWizard',
props: {
componentLauncher: JwtVerifierLauncher,
componentsProps: {
- allowedNewStrategy: 'Generate'
- }
- }
- }
+ allowedNewStrategy: 'Generate',
+ },
+ },
+ },
},
- config_flow: [
- "verifier",
- "replace_if_present",
- "fail_if_present"
- ]
-}
\ No newline at end of file
+ config_flow: ['verifier', 'replace_if_present', 'fail_if_present'],
+};
diff --git a/otoroshi/javascript/src/forms/ng_plugins/JwtVerification.js b/otoroshi/javascript/src/forms/ng_plugins/JwtVerification.js
index 1a1cc3c4a3..59a8aa4954 100644
--- a/otoroshi/javascript/src/forms/ng_plugins/JwtVerification.js
+++ b/otoroshi/javascript/src/forms/ng_plugins/JwtVerification.js
@@ -1,32 +1,32 @@
import React from 'react';
import { NgCustomFormsRenderer } from '../../components/nginputs';
-import { JwtVerifierLauncher } from "../wizards/JwtVerifierLauncher";
+import { JwtVerifierLauncher } from '../wizards/JwtVerifierLauncher';
export default {
- id: "cp:otoroshi.next.plugins.JwtVerification",
+ id: 'cp:otoroshi.next.plugins.JwtVerification',
config_schema: {
verifiers: {
label: 'Chain of verifiers',
type: 'array',
- itemRenderer: props => {
- return
- }
- }
+ itemRenderer: (props) => {
+ return (
+
+ );
+ },
+ },
},
- config_flow: [
- "verifiers"
- ]
-}
\ No newline at end of file
+ config_flow: ['verifiers'],
+};
diff --git a/otoroshi/javascript/src/forms/ng_plugins/JwtVerificationOnly.js b/otoroshi/javascript/src/forms/ng_plugins/JwtVerificationOnly.js
index 58a050b35f..67839deda8 100644
--- a/otoroshi/javascript/src/forms/ng_plugins/JwtVerificationOnly.js
+++ b/otoroshi/javascript/src/forms/ng_plugins/JwtVerificationOnly.js
@@ -1,29 +1,26 @@
-import { JwtVerifierLauncher } from "../wizards/JwtVerifierLauncher";
+import { JwtVerifierLauncher } from '../wizards/JwtVerifierLauncher';
export default {
- id: "cp:otoroshi.next.plugins.JwtVerificationOnly",
+ id: 'cp:otoroshi.next.plugins.JwtVerificationOnly',
config_schema: {
verifier: {
- label: "Verifier",
- type: "JwtVerifierWizard",
+ label: 'Verifier',
+ type: 'JwtVerifierWizard',
props: {
componentLauncher: JwtVerifierLauncher,
componentsProps: {
allowedStrategy: 'PassThrough',
- allowedNewStrategy: 'PassThrough'
- }
- }
+ allowedNewStrategy: 'PassThrough',
+ },
+ },
},
fail_if_absent: {
- type: "box-bool",
- label: "Fail if absent",
+ type: 'box-bool',
+ label: 'Fail if absent',
props: {
- description: 'If a token is present in the incoming request, the call will fail.'
- }
- }
+ description: 'If a token is present in the incoming request, the call will fail.',
+ },
+ },
},
- config_flow: [
- "verifier",
- "fail_if_absent"
- ]
-}
\ No newline at end of file
+ config_flow: ['verifier', 'fail_if_absent'],
+};
diff --git a/otoroshi/javascript/src/forms/ng_plugins/MockResponses.js b/otoroshi/javascript/src/forms/ng_plugins/MockResponses.js
index ed4dfa09c9..6b46d1ebef 100644
--- a/otoroshi/javascript/src/forms/ng_plugins/MockResponses.js
+++ b/otoroshi/javascript/src/forms/ng_plugins/MockResponses.js
@@ -1,5 +1,5 @@
import React from 'react';
-import MocksDesigner from "../../pages/RouteDesigner/MocksDesigner";
+import MocksDesigner from '../../pages/RouteDesigner/MocksDesigner';
export default {
id: 'cp:otoroshi.next.plugins.MockResponses',
diff --git a/otoroshi/javascript/src/forms/ng_plugins/NgBackend.js b/otoroshi/javascript/src/forms/ng_plugins/NgBackend.js
index 55fb812fb7..30f3a25cb2 100644
--- a/otoroshi/javascript/src/forms/ng_plugins/NgBackend.js
+++ b/otoroshi/javascript/src/forms/ng_plugins/NgBackend.js
@@ -454,7 +454,7 @@ export default {
type: 'group',
name: 'Targets',
fields: ['targets'],
- summaryFields: ['targets.hostname']
+ summaryFields: ['targets.hostname'],
},
'health_check',
'client',
@@ -466,8 +466,8 @@ export default {
type: 'group',
name: 'Targets',
fields: ['targets'],
- summaryFields: ['targets.hostname']
- }
- ]
- }
-}
+ summaryFields: ['targets.hostname'],
+ },
+ ],
+ },
+};
diff --git a/otoroshi/javascript/src/forms/ng_plugins/NgFrontend.js b/otoroshi/javascript/src/forms/ng_plugins/NgFrontend.js
index 7a30f702b1..6974c3da2c 100644
--- a/otoroshi/javascript/src/forms/ng_plugins/NgFrontend.js
+++ b/otoroshi/javascript/src/forms/ng_plugins/NgFrontend.js
@@ -33,7 +33,7 @@ export default {
label: 'Exact',
props: {
labelColumn: 3,
- }
+ },
},
domains: {
label: 'domains',
@@ -46,8 +46,8 @@ export default {
label: 'Strip path',
props: {
labelColumn: 3,
- }
- }
+ },
+ },
},
flow: [
'domains',
diff --git a/otoroshi/javascript/src/forms/ng_plugins/OtoroshiChallenge.js b/otoroshi/javascript/src/forms/ng_plugins/OtoroshiChallenge.js
index 2cd55ac711..d2feffb2cf 100644
--- a/otoroshi/javascript/src/forms/ng_plugins/OtoroshiChallenge.js
+++ b/otoroshi/javascript/src/forms/ng_plugins/OtoroshiChallenge.js
@@ -174,30 +174,30 @@ export default {
label: 'name',
value: 'id',
},
- "port": {
- "type": "number"
+ port: {
+ type: 'number',
},
- "protocol": {
- "type": "string"
+ protocol: {
+ type: 'string',
},
- "principal": {
- "type": "string"
+ principal: {
+ type: 'string',
},
- "password": {
- "type": "string"
+ password: {
+ type: 'string',
},
- "ntlmDomain": {
- "type": "string"
+ ntlmDomain: {
+ type: 'string',
},
- "encoding": {
- "type": "string"
+ encoding: {
+ type: 'string',
},
- "nonProxyHosts": {
- "type": "string",
+ nonProxyHosts: {
+ type: 'string',
array: true,
- "label": "Non proxy hosts"
- }
- }
+ label: 'Non proxy hosts',
+ },
+ },
},
onlyExposedCerts: {
type: 'boolean',
@@ -288,11 +288,11 @@ export default {
ttl: {
type: 'number',
},
- "kty": {
+ kty: {
type: 'select',
props: {
- options: ['RSA', 'EC']
- }
+ options: ['RSA', 'EC'],
+ },
},
mtlsConfig: {
type: 'form',
diff --git a/otoroshi/javascript/src/forms/ng_plugins/index.js b/otoroshi/javascript/src/forms/ng_plugins/index.js
index 8ea6e8a652..af3a31e5f0 100644
--- a/otoroshi/javascript/src/forms/ng_plugins/index.js
+++ b/otoroshi/javascript/src/forms/ng_plugins/index.js
@@ -1,73 +1,73 @@
-import AdditionalHeadersIn from './AdditionalHeadersIn'
-import AdditionalHeadersOut from './AdditionalHeadersOut'
-import AllowHttpMethods from './AllowHttpMethods'
-import ApikeyCalls from './ApikeyCalls'
-import ApikeyQuotas from './ApikeyQuotas'
-import AuthModule from './AuthModule'
-import BuildMode from './BuildMode'
-import CanaryMode from './CanaryMode'
-import ContextValidation from './ContextValidation'
-import Cors from './Cors'
-import DisableHttp10 from './DisableHttp10'
-import EndlessHttpResponse from './EndlessHttpResponse'
-import EurekaServerSink from './EurekaServerSink'
-import EurekaTarget from './EurekaTarget'
-import ExternalEurekaTarget from './ExternalEurekaTarget'
-import ForceHttpsTraffic from './ForceHttpsTraffic'
-import GlobalMaintenanceMode from './GlobalMaintenanceMode'
-import GlobalPerIpAddressThrottling from './GlobalPerIpAddressThrottling'
-import GlobalThrottling from './GlobalThrottling'
-import GraphQLBackend from './GraphQLBackend'
-import GraphQLProxy from './GraphQLProxy'
-import GraphQLQuery from './GraphQLQuery'
-import GzipResponseCompressor from './GzipResponseCompressor'
-import HeadersValidation from './HeadersValidation'
-import HtmlPatcher from './HtmlPatcher'
-import Http3Switch from './Http3Switch'
-import IpAddressAllowedList from './IpAddressAllowedList'
-import IpAddressBlockList from './IpAddressBlockList'
-import JQ from './JQ'
-import JQRequest from './JQRequest'
-import JQResponse from './JQResponse'
-import JsonToXmlRequest from './JsonToXmlRequest'
-import JsonToXmlResponse from './JsonToXmlResponse'
-import JwtSigner from './JwtSigner'
-import JwtVerification from './JwtVerification'
-import JwtVerificationOnly from './JwtVerificationOnly'
-import MaintenanceMode from './MaintenanceMode'
-import MissingHeadersIn from './MissingHeadersIn'
-import MissingHeadersOut from './MissingHeadersOut'
-import MockResponses from './MockResponses'
-import NgAuthModuleExpectedUser from './NgAuthModuleExpectedUser'
-import NgAuthModuleUserExtractor from './NgAuthModuleUserExtractor'
-import NgBackend from './NgBackend'
-import NgFrontend from './NgFrontend'
-import NgLegacyApikeyCall from './NgLegacyApikeyCall'
-import OtoroshiChallenge from './OtoroshiChallenge'
-import OtoroshiInfos from './OtoroshiInfos'
-import OverrideHost from './OverrideHost'
-import PublicPrivatePaths from './PublicPrivatePaths'
-import QueryTransformer from './QueryTransformer'
-import RBAC from './RBAC'
-import ReadOnlyCalls from './ReadOnlyCalls'
-import Redirection from './Redirection'
-import RemoveHeadersIn from './RemoveHeadersIn'
-import RemoveHeadersOut from './RemoveHeadersOut'
-import Robots from './Robots'
-import RoutingRestrictions from './RoutingRestrictions'
-import S3Backend from './S3Backend'
-import SOAPAction from './SOAPAction'
-import SendOtoroshiHeadersBack from './SendOtoroshiHeadersBack'
-import SnowMonkeyChaos from './SnowMonkeyChaos'
-import StaticBackend from './StaticBackend'
-import StaticResponse from './StaticResponse'
-import TcpTunnel from './TcpTunnel'
-import TunnelPlugin from './TunnelPlugin'
-import UdpTunnel from './UdpTunnel'
-import W3CTracing from './W3CTracing'
-import XForwardedHeaders from './XForwardedHeaders'
-import XmlToJsonRequest from './XmlToJsonRequest'
-import XmlToJsonResponse from './XmlToJsonResponse'
+import AdditionalHeadersIn from './AdditionalHeadersIn';
+import AdditionalHeadersOut from './AdditionalHeadersOut';
+import AllowHttpMethods from './AllowHttpMethods';
+import ApikeyCalls from './ApikeyCalls';
+import ApikeyQuotas from './ApikeyQuotas';
+import AuthModule from './AuthModule';
+import BuildMode from './BuildMode';
+import CanaryMode from './CanaryMode';
+import ContextValidation from './ContextValidation';
+import Cors from './Cors';
+import DisableHttp10 from './DisableHttp10';
+import EndlessHttpResponse from './EndlessHttpResponse';
+import EurekaServerSink from './EurekaServerSink';
+import EurekaTarget from './EurekaTarget';
+import ExternalEurekaTarget from './ExternalEurekaTarget';
+import ForceHttpsTraffic from './ForceHttpsTraffic';
+import GlobalMaintenanceMode from './GlobalMaintenanceMode';
+import GlobalPerIpAddressThrottling from './GlobalPerIpAddressThrottling';
+import GlobalThrottling from './GlobalThrottling';
+import GraphQLBackend from './GraphQLBackend';
+import GraphQLProxy from './GraphQLProxy';
+import GraphQLQuery from './GraphQLQuery';
+import GzipResponseCompressor from './GzipResponseCompressor';
+import HeadersValidation from './HeadersValidation';
+import HtmlPatcher from './HtmlPatcher';
+import Http3Switch from './Http3Switch';
+import IpAddressAllowedList from './IpAddressAllowedList';
+import IpAddressBlockList from './IpAddressBlockList';
+import JQ from './JQ';
+import JQRequest from './JQRequest';
+import JQResponse from './JQResponse';
+import JsonToXmlRequest from './JsonToXmlRequest';
+import JsonToXmlResponse from './JsonToXmlResponse';
+import JwtSigner from './JwtSigner';
+import JwtVerification from './JwtVerification';
+import JwtVerificationOnly from './JwtVerificationOnly';
+import MaintenanceMode from './MaintenanceMode';
+import MissingHeadersIn from './MissingHeadersIn';
+import MissingHeadersOut from './MissingHeadersOut';
+import MockResponses from './MockResponses';
+import NgAuthModuleExpectedUser from './NgAuthModuleExpectedUser';
+import NgAuthModuleUserExtractor from './NgAuthModuleUserExtractor';
+import NgBackend from './NgBackend';
+import NgFrontend from './NgFrontend';
+import NgLegacyApikeyCall from './NgLegacyApikeyCall';
+import OtoroshiChallenge from './OtoroshiChallenge';
+import OtoroshiInfos from './OtoroshiInfos';
+import OverrideHost from './OverrideHost';
+import PublicPrivatePaths from './PublicPrivatePaths';
+import QueryTransformer from './QueryTransformer';
+import RBAC from './RBAC';
+import ReadOnlyCalls from './ReadOnlyCalls';
+import Redirection from './Redirection';
+import RemoveHeadersIn from './RemoveHeadersIn';
+import RemoveHeadersOut from './RemoveHeadersOut';
+import Robots from './Robots';
+import RoutingRestrictions from './RoutingRestrictions';
+import S3Backend from './S3Backend';
+import SOAPAction from './SOAPAction';
+import SendOtoroshiHeadersBack from './SendOtoroshiHeadersBack';
+import SnowMonkeyChaos from './SnowMonkeyChaos';
+import StaticBackend from './StaticBackend';
+import StaticResponse from './StaticResponse';
+import TcpTunnel from './TcpTunnel';
+import TunnelPlugin from './TunnelPlugin';
+import UdpTunnel from './UdpTunnel';
+import W3CTracing from './W3CTracing';
+import XForwardedHeaders from './XForwardedHeaders';
+import XmlToJsonRequest from './XmlToJsonRequest';
+import XmlToJsonResponse from './XmlToJsonResponse';
export const Backend = NgBackend;
export const Frontend = NgFrontend;
diff --git a/otoroshi/javascript/src/forms/wizards/JwtVerifierLauncher.js b/otoroshi/javascript/src/forms/wizards/JwtVerifierLauncher.js
index a83f8a1b46..71f287624f 100644
--- a/otoroshi/javascript/src/forms/wizards/JwtVerifierLauncher.js
+++ b/otoroshi/javascript/src/forms/wizards/JwtVerifierLauncher.js
@@ -1,13 +1,13 @@
-import React from "react";
-import { Button } from "../../components/Button";
-import { NgForm } from "../../components/nginputs";
-import { findJwtVerifierById } from "../../services/BackOfficeServices";
+import React from 'react';
+import { Button } from '../../components/Button';
+import { NgForm } from '../../components/nginputs';
+import { findJwtVerifierById } from '../../services/BackOfficeServices';
import JwtVerifierForm from '../entities/JwtVerifier';
export class JwtVerifierLauncher extends React.Component {
state = {
- verifier: undefined
- }
+ verifier: undefined,
+ };
componentDidMount() {
this.loadVerifier(this.props.value);
@@ -21,80 +21,84 @@ export class JwtVerifierLauncher extends React.Component {
loadVerifier = (value) => {
if (value && typeof value === 'string') {
- findJwtVerifierById(value)
- .then(verifier => {
- this.setState({ verifier })
- });
+ findJwtVerifierById(value).then((verifier) => {
+ this.setState({ verifier });
+ });
} else
this.setState({
- verifier: undefined
- })
- }
+ verifier: undefined,
+ });
+ };
render() {
const { verifier } = this.state;
const { openComponent, onChange } = this.props;
if (!verifier) {
- return
+ return (
+
+ );
} else {
- return
-
{
- return
- onChange(undefined)} >
- Unselect
-
- openComponent({})}
- className="mx-1 btn-sm" >
- Choose another
-
- openComponent({
- mode: 'update_in_wizard',
- jwtVerifier: verifier
- })} >
- Edit
-
-
- }
- }
- }}
- flow={[
- {
- type: 'group',
- name: props => {
- if (!props.value)
- return 'Selected verifier'
- else {
- return `${props.value.name} - ${props.value.desc}`
- }
+ return (
+
+
{
+ return (
+
+ onChange(undefined)}>
+
+ Unselect
+
+ openComponent({})} className="mx-1 btn-sm">
+
+ Choose another
+
+
+ openComponent({
+ mode: 'update_in_wizard',
+ jwtVerifier: verifier,
+ })
+ }>
+
+ Edit
+
+
+ );
+ },
},
- fields: ['actions']
- }
- ]}
- />
-
+ }}
+ flow={[
+ {
+ type: 'group',
+ name: (props) => {
+ if (!props.value) return 'Selected verifier';
+ else {
+ return `${props.value.name} - ${props.value.desc}`;
+ }
+ },
+ fields: ['actions'],
+ },
+ ]}
+ />
+
+ );
}
}
-}
\ No newline at end of file
+}
diff --git a/otoroshi/javascript/src/forms/wizards/JwtVerifierWizard.js b/otoroshi/javascript/src/forms/wizards/JwtVerifierWizard.js
index b93dc15cbe..4fa54891b0 100644
--- a/otoroshi/javascript/src/forms/wizards/JwtVerifierWizard.js
+++ b/otoroshi/javascript/src/forms/wizards/JwtVerifierWizard.js
@@ -11,137 +11,159 @@ import { FeedbackButton } from '../../pages/RouteDesigner/FeedbackButton';
import { v4 as uuid } from 'uuid';
function WizardStepButton(props) {
- return
+ return (
+
+ );
}
function Breadcrumb({ value, onClick }) {
- return
{value.map((part, i) => {
- return onClick(i)}>
- {part}
- {(i + 1) < value.length && }
-
- })}
+ return (
+
+ {value.map((part, i) => {
+ return (
+ onClick(i)}>
+ {part}
+ {i + 1 < value.length && }
+
+ );
+ })}
+
+ );
}
function Header({ onClose, mode }) {
- return
+ return (
+
+ );
}
function WizardActions({ nextStep, prevStep, step, goBack }) {
- return
-
-
-
+ return (
+
+
+
+
+ );
}
function Selector({ setMode, disableSelectMode }) {
- return
-
Getting started
-
- {[
- { title: 'NEW', text: 'Create a new JWT verifier', mode: 'creation' },
- { title: 'SELECT', text: 'Use an existing JWT verifier', mode: 'edition', disabled: disableSelectMode },
- { title: 'CLONE', text: 'Create a new one fron an existing JWT verifier', mode: 'clone' }
- ].map(({ title, text, mode, disabled }) => disabled ? null :
setMode(mode)}>
- {title}
-
-
- )}
+ return (
+
+
Getting started
+
+ {[
+ { title: 'NEW', text: 'Create a new JWT verifier', mode: 'creation' },
+ {
+ title: 'SELECT',
+ text: 'Use an existing JWT verifier',
+ mode: 'edition',
+ disabled: disableSelectMode,
+ },
+ { title: 'CLONE', text: 'Create a new one fron an existing JWT verifier', mode: 'clone' },
+ ].map(({ title, text, mode, disabled }) =>
+ disabled ? null : (
+ setMode(mode)}>
+
+ {title}
+
+
+
+ )
+ )}
+
-
+ );
}
function JwtVerifierSelector({ handleSelect, allowedStrategy, mode }) {
const [verifiers, setVerifiers] = useState([]);
useEffect(() => {
- BackOfficeServices.findAllJwtVerifiers()
- .then(setVerifiers)
+ BackOfficeServices.findAllJwtVerifiers().then(setVerifiers);
}, []);
- return
-
-
Select {mode === 'clone' ? 'the verifier to clone' : 'a verifier'}
-
-
-
{
- handleSelect(verifiers.find(v => v.id === id))
- }}
- options={verifiers.filter(verifier => allowedStrategy ? verifier.strategy.type === allowedStrategy : true)}
- optionsTransformer={arr => arr.map(item => ({ value: item.id, label: item.name }))} />
+ return (
+
+
+
Select {mode === 'clone' ? 'the verifier to clone' : 'a verifier'}
+
+
+ {
+ handleSelect(verifiers.find((v) => v.id === id));
+ }}
+ options={verifiers.filter((verifier) =>
+ allowedStrategy ? verifier.strategy.type === allowedStrategy : true
+ )}
+ optionsTransformer={(arr) => arr.map((item) => ({ value: item.id, label: item.name }))}
+ />
+
-
+ );
}
function GoBackSelection({ goBack }) {
- return
-
-
- Go back to selection
-
-
+ return (
+
+
+
+ Go back to selection
+
+
+ );
}
export class JwtVerifierWizard extends React.Component {
init = () => {
if (this.props.jwtVerifier) {
if (!this.props.allowedNewStrategy) {
- return this.props.jwtVerifier
+ return this.props.jwtVerifier;
} else {
return {
strict: false,
@@ -149,11 +171,10 @@ export class JwtVerifierWizard extends React.Component {
type: 'PassThrough',
verificationSettings: { fields: { iss: 'The Issuer' }, arrayFields: {} },
},
- ...this.props.jwtVerifier
- }
+ ...this.props.jwtVerifier,
+ };
}
- }
- else {
+ } else {
return {
type: 'global',
strict: false,
@@ -162,264 +183,318 @@ export class JwtVerifierWizard extends React.Component {
strategy: {
type: 'PassThrough',
verificationSettings: { fields: { iss: 'The Issuer' }, arrayFields: {} },
- }
- }
+ },
+ };
}
- }
+ };
state = {
step: 1,
jwtVerifier: this.init(),
- breadcrumb: [
- 'Informations'
- ],
- mode: this.props.mode || 'selector'
- }
+ breadcrumb: ['Informations'],
+ mode: this.props.mode || 'selector',
+ };
onChange = (field, value) => {
this.setState({
jwtVerifier: {
...this.state.jwtVerifier,
- [field]: value
- }
- })
- }
+ [field]: value,
+ },
+ });
+ };
prevStep = () => {
- if (this.state.step - 1 > 0)
- this.setState({ step: this.state.step - 1 });
+ if (this.state.step - 1 > 0) this.setState({ step: this.state.step - 1 });
};
nextStep = () => {
this.setState({
- step: this.state.step + 1
+ step: this.state.step + 1,
});
};
updateBreadcrumb = (value, i) => {
if (i >= this.state.breadcrumb.length) {
this.setState({
- breadcrumb: [...this.state.breadcrumb, value]
+ breadcrumb: [...this.state.breadcrumb, value],
});
- }
- else {
+ } else {
this.setState({
breadcrumb: this.state.breadcrumb.map((v, j) => {
- if (j === i)
- return value
- return v
- })
- })
+ if (j === i) return value;
+ return v;
+ }),
+ });
}
- }
+ };
render() {
const { step, jwtVerifier, mode } = this.state;
if (mode === 'update_in_wizard') {
- return
-
-
-
-
-
this.setState({ jwtVerifier })} />
-
-
-
BackOfficeServices.updateJwtVerifier(jwtVerifier)}
- onSuccess={this.props.hide}
- icon={() => }
- text="Save the verifier"
+ return (
+
+
+
+
+
+
this.setState({ jwtVerifier })}
/>
+
+
+ BackOfficeServices.updateJwtVerifier(jwtVerifier)}
+ onSuccess={this.props.hide}
+ icon={() => }
+ text="Save the verifier"
+ />
+
-
+ );
} else {
const STEPS = [
{
component: InformationsStep,
props: {
name: jwtVerifier.name,
- onChange: value => {
- this.onChange('name', value)
+ onChange: (value) => {
+ this.onChange('name', value);
this.updateBreadcrumb(value, 0);
- }
- }
+ },
+ },
},
{
component: StrategyStep,
hide: this.props.allowedNewStrategy ? true : undefined,
props: {
value: jwtVerifier.strategy?.type,
- onChange: value => {
- if (value?.strategy)
- this.updateBreadcrumb(value.strategy, 1);
- this.setState({
- jwtVerifier: {
- ...jwtVerifier,
- strategy: {
- ...(jwtVerifier.strategy || {}),
- type: value?.strategy
- }
+ onChange: (value) => {
+ if (value?.strategy) this.updateBreadcrumb(value.strategy, 1);
+ this.setState(
+ {
+ jwtVerifier: {
+ ...jwtVerifier,
+ strategy: {
+ ...(jwtVerifier.strategy || {}),
+ type: value?.strategy,
+ },
+ },
+ },
+ () => {
+ if (value?.strategy) this.nextStep();
}
- }, () => {
- if (value?.strategy)
- this.nextStep()
- })
- }
- }
+ );
+ },
+ },
},
{
component: DefaultTokenStep,
hide: this.props.allowedNewStrategy ? true : undefined,
onChange: (_, index) => {
this.updateBreadcrumb(`${this.state.jwtVerifier.source?.type || ''} Location`, index);
- }
+ },
},
{
component: TokenSignatureStep,
props: {
root: 'algoSettings',
value: jwtVerifier,
- title: this.props.allowedNewStrategy === 'PassThrough' ? 'Verify token with' : undefined,
- onChange: (value, index) => this.setState({ jwtVerifier: value }, () => {
- this.updateBreadcrumb(`${this.state.jwtVerifier.algoSettings?.type || ''} Algo.`, index);
- })
- }
+ title:
+ this.props.allowedNewStrategy === 'PassThrough' ? 'Verify token with' : undefined,
+ onChange: (value, index) =>
+ this.setState({ jwtVerifier: value }, () => {
+ this.updateBreadcrumb(
+ `${this.state.jwtVerifier.algoSettings?.type || ''} Algo.`,
+ index
+ );
+ }),
+ },
},
{
component: TokenSignatureStep,
- condition: value => ['Sign', 'Transform'].includes(value.strategy?.type),
+ condition: (value) => ['Sign', 'Transform'].includes(value.strategy?.type),
props: {
value: jwtVerifier['strategy'],
root: 'algoSettings',
title: 'Resign token with',
- onChange: (value, index) => this.setState({
- jwtVerifier: {
- ...jwtVerifier,
- ['strategy']: value
- }
- }, () => {
- this.updateBreadcrumb(`${this.state.jwtVerifier.strategy?.algoSettings?.type || ''} Resign Algo.`, index);
- })
- }
+ onChange: (value, index) =>
+ this.setState(
+ {
+ jwtVerifier: {
+ ...jwtVerifier,
+ ['strategy']: value,
+ },
+ },
+ () => {
+ this.updateBreadcrumb(
+ `${this.state.jwtVerifier.strategy?.algoSettings?.type || ''} Resign Algo.`,
+ index
+ );
+ }
+ ),
+ },
},
{
component: TokenTransformStep,
- condition: value => 'Transform' === value.strategy?.type,
+ condition: (value) => 'Transform' === value.strategy?.type,
props: {
value: jwtVerifier.strategy?.transformSettings,
onChange: (value, index) => {
- this.setState({
- jwtVerifier: {
- ...jwtVerifier,
- strategy: {
- ...(jwtVerifier.strategy || {}),
- transformSettings: value
- }
+ this.setState(
+ {
+ jwtVerifier: {
+ ...jwtVerifier,
+ strategy: {
+ ...(jwtVerifier.strategy || {}),
+ transformSettings: value,
+ },
+ },
+ },
+ () => {
+ const transformSettings =
+ this.state.jwtVerifier.strategy?.transformSettings || {};
+ const sameLocation =
+ transformSettings.location === undefined ? true : transformSettings.location;
+ const outLocation = transformSettings.out_location?.source?.type || '';
+ this.updateBreadcrumb(
+ `${
+ sameLocation ? this.state.jwtVerifier.source?.type : outLocation
+ } Out location.`,
+ index
+ );
}
- }, () => {
- const transformSettings = this.state.jwtVerifier.strategy?.transformSettings || {};
- const sameLocation = transformSettings.location === undefined ? true : transformSettings.location;
- const outLocation = transformSettings.out_location?.source?.type || '';
- this.updateBreadcrumb(`${sameLocation ? this.state.jwtVerifier.source?.type : outLocation} Out location.`, index);
- })
- }
- }
- }
- ]
- .filter(item => item.hide === undefined)
+ );
+ },
+ },
+ },
+ ].filter((item) => item.hide === undefined);
const showSummary = !STEPS.find((item, i) => {
- return step === (i + 1) && (item.condition ? item.condition(jwtVerifier) : true)
+ return step === i + 1 && (item.condition ? item.condition(jwtVerifier) : true);
});
return (
-
+
- {mode === 'selector' &&
this.setState({ mode })} disableSelectMode={this.props.disableSelectMode} />}
-
- {mode !== 'selector' && <>
- {['edition', 'clone'].includes(mode) ?
- {
- if (this.props.onConfirm && mode === 'edition') {
- this.props.onConfirm(verifier.id);
- } else {
- this.setState({
- mode: 'continue',
- jwtVerifier: {
- ...verifier,
- id: `jwt_verifier_${uuid()}`
- }
- })
- }
- }} /> :
- <>
- this.setState({ step: i + 1 })} />
-
- {STEPS.map(({ component, props, condition, onChange }, i) => {
- if (step === (i + 1) && (condition ? condition(jwtVerifier) : true)) {
- const defaultProps = {
- value: jwtVerifier,
- onChange: value => this.setState({ jwtVerifier: value }, onChange)
- };
-
- const allProps = props ? {
- ...props,
- onChange: e => props.onChange(e, i)
- } : defaultProps;
-
- return React.createElement(component, { key: component.Type, ...allProps });
+ {mode === 'selector' && (
+
this.setState({ mode })}
+ disableSelectMode={this.props.disableSelectMode}
+ />
+ )}
+
+ {mode !== 'selector' && (
+ <>
+ {['edition', 'clone'].includes(mode) ? (
+ {
+ if (this.props.onConfirm && mode === 'edition') {
+ this.props.onConfirm(verifier.id);
} else {
- return null;
+ this.setState({
+ mode: 'continue',
+ jwtVerifier: {
+ ...verifier,
+ id: `jwt_verifier_${uuid()}`,
+ },
+ });
}
- })}
- {showSummary &&
+ ) : (
+ <>
+ this.setState({ step: i + 1 })}
+ />
+
+ {STEPS.map(({ component, props, condition, onChange }, i) => {
+ if (step === i + 1 && (condition ? condition(jwtVerifier) : true)) {
+ const defaultProps = {
+ value: jwtVerifier,
+ onChange: (value) => this.setState({ jwtVerifier: value }, onChange),
+ };
+
+ const allProps = props
+ ? {
+ ...props,
+ onChange: (e) => props.onChange(e, i),
+ }
+ : defaultProps;
+
+ return React.createElement(component, {
+ key: component.Type,
+ ...allProps,
+ });
+ } else {
+ return null;
}
- }} />}
- {!showSummary && {
- this.setState({
- mode: this.props.mode || 'selector'
- })
- }} />}
-
- >}
- >}
- {['edition', 'clone'].includes(mode) && {
- this.setState({
- mode: this.props.mode || 'selector'
- })
- }} />}
+ })}
+ {showSummary && (
+
+ )}
+ {!showSummary && (
+ {
+ this.setState({
+ mode: this.props.mode || 'selector',
+ });
+ }}
+ />
+ )}
+
+ >
+ )}
+ >
+ )}
+ {['edition', 'clone'].includes(mode) && (
+ {
+ this.setState({
+ mode: this.props.mode || 'selector',
+ });
+ }}
+ />
+ )}
@@ -437,33 +512,31 @@ function WizardLastStep({ value, breadcrumb, onConfirm }) {
const create = () => {
setCreating(true);
- BackOfficeServices.createNewJwtVerifier()
- .then(template => {
- BackOfficeServices.createJwtVerifier({
- ...template,
- name: value.name || 'Default name',
- source: value.source,
- algoSettings: {
- ...template.algoSettings,
- ...value.algoSettings,
- },
- strategy: {
- ...template.strategy,
- ...value.strategy,
- type: value.strategy.type
- }
- })
- .then(res => {
- if (res.error) {
- setError(true);
- } else if (onConfirm) {
- onConfirm(template.id)
- } else {
- setVerifier(template);
- }
- })
- })
- }
+ BackOfficeServices.createNewJwtVerifier().then((template) => {
+ BackOfficeServices.createJwtVerifier({
+ ...template,
+ name: value.name || 'Default name',
+ source: value.source,
+ algoSettings: {
+ ...template.algoSettings,
+ ...value.algoSettings,
+ },
+ strategy: {
+ ...template.strategy,
+ ...value.strategy,
+ type: value.strategy.type,
+ },
+ }).then((res) => {
+ if (res.error) {
+ setError(true);
+ } else if (onConfirm) {
+ onConfirm(template.id);
+ } else {
+ setVerifier(template);
+ }
+ });
+ });
+ };
return (
<>
@@ -471,32 +544,44 @@ function WizardLastStep({ value, breadcrumb, onConfirm }) {
Creation steps
-
+
{breadcrumb.map((part, i) => {
- return
+ return (
+
+ );
})}
- {!creating &&
-
- Confirm
- }
-
- {(verifier || error) &&
history.push(`/jwt-verifiers/edit/${verifier.id}`)}
- >
-
- {error ? 'Something wrong happened : try to check your configuration' : 'See the created verifier'}
- }
+ {!creating && (
+
+
+ Confirm
+
+ )}
+
+ {(verifier || error) && (
+
history.push(`/jwt-verifiers/edit/${verifier.id}`)}>
+
+ {error
+ ? 'Something wrong happened : try to check your configuration'
+ : 'See the created verifier'}
+
+ )}
>
- )
+ );
}
function InformationsStep({ name, onChange }) {
@@ -520,107 +605,120 @@ function InformationsStep({ name, onChange }) {
/>
>
- )
+ );
}
function StrategyStep({ value, onChange }) {
-
const schema = {
strategy: {
- renderer: props => {
- return
- {[
- {
- strategy: 'PassThrough', title: ['Verify'],
- desc: 'PassThrough will only verifiy token signing and fields values if provided. ',
- tags: ['verify']
- },
- {
- strategy: 'Sign', title: ['Verify and re-sign'],
- desc: 'Sign will do the same as PassThrough plus will re-sign the JWT token with the provided algo. settings.',
- tags: ['verify', 'sign']
- },
- {
- strategy: 'Transform', title: ['Verify, re-sign and Transform'],
- desc: 'Transform will do the same as Sign plus will be able to transform the token.',
- tags: ['verify', 'sign', 'transform']
- }
- ].map(({ strategy, desc, title, tags }) => {
- return
props.onChange(strategy)}
- key={strategy}
- >
-
- {title.map((t, i) =>
0 ? '1px' : 0
- }} key={t}>
- {t}
-
)}
-
-
-
-
- {[
- 'Generate', 'Verify', 'Sign', 'Transform'
- ]
- .filter(tag => tags.includes(tag.toLocaleLowerCase()))
- .map(tag =>
{
+ return (
+
+ {[
+ {
+ strategy: 'PassThrough',
+ title: ['Verify'],
+ desc: 'PassThrough will only verifiy token signing and fields values if provided. ',
+ tags: ['verify'],
+ },
+ {
+ strategy: 'Sign',
+ title: ['Verify and re-sign'],
+ desc:
+ 'Sign will do the same as PassThrough plus will re-sign the JWT token with the provided algo. settings.',
+ tags: ['verify', 'sign'],
+ },
+ {
+ strategy: 'Transform',
+ title: ['Verify, re-sign and Transform'],
+ desc:
+ 'Transform will do the same as Sign plus will be able to transform the token.',
+ tags: ['verify', 'sign', 'transform'],
+ },
+ ].map(({ strategy, desc, title, tags }) => {
+ return (
+
props.onChange(strategy)}
+ key={strategy}>
+
+ {title.map((t, i) => (
+
0 ? '1px' : 0,
+ }}
+ key={t}>
+ {t}
+
+ ))}
+
+
+
+
-
- {tag}
-
)}
-
-
-
- })}
-
- }
- }
- }
+ background: '#515151',
+ width: '100%',
+ }}>
+ {['Generate', 'Verify', 'Sign', 'Transform']
+ .filter((tag) => tags.includes(tag.toLocaleLowerCase()))
+ .map((tag) => (
+
+
+ {tag}
+
+ ))}
+
+
+
+ );
+ })}
+
+ );
+ },
+ },
+ };
- const flow = [
- 'strategy'
- ];
+ const flow = ['strategy'];
return (
<>
What kind of strategy will be used
-
+
>
- )
+ );
}
const TokenLocationForm = {
@@ -633,111 +731,113 @@ const TokenLocationForm = {
type: 'select',
props: {
ngOptions: {
- spread: true
+ spread: true,
},
options: [
{ value: 'InHeader', label: 'Header' },
{ value: 'InQueryParam', label: 'Query string' },
- { value: 'InCookie', label: 'Cookie' }
- ]
- }
+ { value: 'InCookie', label: 'Cookie' },
+ ],
+ },
},
name: {
type: 'string',
- label: 'Name'
+ label: 'Name',
},
remove: {
type: 'string',
placeholder: 'Bearer ',
label: 'Remove value',
props: {
- subTitle: '(Optional): String to remove from the value to access to the token'
- }
+ subTitle: '(Optional): String to remove from the value to access to the token',
+ },
},
debug: {
renderer: () => {
- return
-
+
-
- }
- }
+ result: {
+ type: 'form',
+ label: 'Form values',
+ schema: {
+ headerName: {
+ type: 'string',
+ label: 'Name',
+ props: {
+ disabled: true,
+ defaultValue: 'Authorization',
+ },
+ },
+ remove: {
+ type: 'string',
+ label: 'Remove value',
+ props: {
+ disabled: true,
+ defaultValue: 'Bearer ',
+ },
+ },
+ },
+ flow: ['headerName', 'remove'],
+ },
+ }}
+ flow={[
+ {
+ type: 'group',
+ collapsable: false,
+ name: 'A bearer token expected in Authorization header',
+ fields: ['header', 'result'],
+ },
+ ]}
+ />
+
+ );
+ },
+ },
},
flow: [
'type',
{
type: 'group',
collapsable: false,
- visible: props => props?.type === 'InHeader',
+ visible: (props) => props?.type === 'InHeader',
name: 'Header informations',
- fields: ['name', 'remove', 'debug']
+ fields: ['name', 'remove', 'debug'],
},
{
type: 'group',
collapsable: false,
- visible: props => props?.type === 'InQueryParam',
+ visible: (props) => props?.type === 'InQueryParam',
name: 'Query param name',
- fields: ['name']
+ fields: ['name'],
},
{
type: 'group',
collapsable: false,
- visible: props => props?.type === 'InCookie',
+ visible: (props) => props?.type === 'InCookie',
name: 'Cookie name',
- fields: ['name']
- }
- ]
- }
- }
-}
+ fields: ['name'],
+ },
+ ],
+ },
+ },
+};
function DefaultTokenStep({ value, onChange }) {
-
return (
<>
The location of the token
@@ -748,11 +848,10 @@ function DefaultTokenStep({ value, onChange }) {
onChange={onChange}
/>
>
- )
+ );
}
function TokenSignatureStep({ root, value, onChange, title }) {
-
const schema = {
[root]: {
type: 'form',
@@ -769,71 +868,74 @@ function TokenSignatureStep({ root, value, onChange, title }) {
{ label: 'JWK Set (only for verification)', value: 'JWKSAlgoSettings' },
{ label: 'RSASSA-PKCS1 + SHA from KeyPair', value: 'RSAKPAlgoSettings' },
{ label: 'ECDSA + SHA from KeyPair', value: 'ESKPAlgoSettings' },
- { label: 'Otoroshi KeyPair from token kid (only for verification)', value: 'KidAlgoSettings' }
- ]
- }
+ {
+ label: 'Otoroshi KeyPair from token kid (only for verification)',
+ value: 'KidAlgoSettings',
+ },
+ ],
+ },
},
onlyExposedCerts: {
type: 'bool',
- label: 'Use only exposed keypairs'
+ label: 'Use only exposed keypairs',
},
size: {
type: 'dots',
label: 'SHA size',
props: {
- options: [256, 384, 512]
- }
+ options: [256, 384, 512],
+ },
},
secret: {
type: 'string',
- label: 'HMAC secret'
+ label: 'HMAC secret',
},
base64: {
type: 'bool',
- label: 'Base64 encoded secret'
+ label: 'Base64 encoded secret',
},
publicKey: {
type: 'text',
- label: 'Public key'
+ label: 'Public key',
},
privateKey: {
type: 'text',
- label: 'Private key'
+ label: 'Private key',
},
certId: {
- type: "select",
- label: "Cert. id",
+ type: 'select',
+ label: 'Cert. id',
props: {
- optionsFrom: "/bo/api/proxy/api/certificates",
+ optionsFrom: '/bo/api/proxy/api/certificates',
optionsTransformer: {
- label: "name",
- value: "id"
- }
- }
+ label: 'name',
+ value: 'id',
+ },
+ },
},
url: {
type: 'string',
- label: 'URL'
+ label: 'URL',
},
timeout: {
type: 'number',
- label: 'HTTP call timeout'
+ label: 'HTTP call timeout',
},
ttl: {
type: 'number',
- label: 'Cache TTL for the keyset'
+ label: 'Cache TTL for the keyset',
},
headers: {
- type: "object",
- label: "Headers"
+ type: 'object',
+ label: 'Headers',
},
kty: {
type: 'select',
label: 'Key type',
props: {
- options: ['RSA', 'EC']
- }
- }
+ options: ['RSA', 'EC'],
+ },
+ },
},
flow: (props, v) => {
return {
@@ -843,19 +945,12 @@ function TokenSignatureStep({ root, value, onChange, title }) {
RSAKPAlgoSettings: ['type', 'size', 'certId'],
ESKPAlgoSettings: ['type', 'size', 'certId'],
ESAlgoSettings: ['type', 'size', 'publicKey', 'privateKey'],
- JWKSAlgoSettings: [
- 'type',
- 'url',
- 'timeout',
- 'ttl',
- 'headers',
- 'kty'
- ],
- [undefined]: ['type']
- }[v.value?.type]
- }
- }
- }
+ JWKSAlgoSettings: ['type', 'url', 'timeout', 'ttl', 'headers', 'kty'],
+ [undefined]: ['type'],
+ }[v.value?.type];
+ },
+ },
+ };
const flow = [root];
@@ -863,14 +958,9 @@ function TokenSignatureStep({ root, value, onChange, title }) {
<>
{title || 'Generate token with'}
-
+
>
- )
+ );
}
function TokenTransformStep({ value, onChange }) {
@@ -879,34 +969,26 @@ function TokenTransformStep({ value, onChange }) {
type: 'bool',
label: 'Use the same location than the entry token',
props: {
- defaultValue: true
- }
+ defaultValue: true,
+ },
},
out_location: {
- visible: props => props?.location === false,
+ visible: (props) => props?.location === false,
label: 'New location',
type: 'form',
- ...TokenLocationForm
- }
- }
+ ...TokenLocationForm,
+ },
+ };
- const flow = [
- 'location',
- 'out_location'
- ];
+ const flow = ['location', 'out_location'];
return (
<>
Location of the generated token
-
+
>
- )
+ );
}
function LoaderItem({ text, timeout, started }) {
@@ -927,11 +1009,14 @@ function LoaderItem({ text, timeout, started }) {
minHeight: '42px',
alignItems: 'center',
justifyContent: 'flex-start',
- marginBottom: '6px'
- }} className="mt-3">
- {started &&
-
- }
+ marginBottom: '6px',
+ }}
+ className="mt-3">
+ {started && (
+
+
+
+ )}
{!started &&
}
);
-};
\ No newline at end of file
+}
diff --git a/otoroshi/javascript/src/forms/wizards/index.js b/otoroshi/javascript/src/forms/wizards/index.js
index 1148f36cf7..1cf5f8ed9e 100644
--- a/otoroshi/javascript/src/forms/wizards/index.js
+++ b/otoroshi/javascript/src/forms/wizards/index.js
@@ -1,5 +1,5 @@
-import { JwtVerifierWizard } from "./JwtVerifierWizard";
+import { JwtVerifierWizard } from './JwtVerifierWizard';
export const Wizards = {
- 'JwtVerifierWizard': JwtVerifierWizard
-}
\ No newline at end of file
+ JwtVerifierWizard: JwtVerifierWizard,
+};
diff --git a/otoroshi/javascript/src/pages/JwtVerifiersPage.js b/otoroshi/javascript/src/pages/JwtVerifiersPage.js
index fd47d29a23..e3356ceb1b 100644
--- a/otoroshi/javascript/src/pages/JwtVerifiersPage.js
+++ b/otoroshi/javascript/src/pages/JwtVerifiersPage.js
@@ -5,7 +5,7 @@ import { JwtVerifier } from '../components/JwtVerifier';
import { Button } from '../components/Button';
import { ClassifiedForms } from '../forms';
import { FeedbackButton } from './RouteDesigner/FeedbackButton';
-import PageTitle from '../components/PageTitle'
+import PageTitle from '../components/PageTitle';
import { Dropdown } from '../components/Dropdown';
import { YAMLExportButton } from '../components/exporters/YAMLButton';
import { JsonExportButton } from '../components/exporters/JSONButton';
@@ -14,13 +14,13 @@ import { ENTITIES, FormSelector } from '../components/FormSelector';
export class JwtVerifiersPage extends Component {
state = {
- showWizard: false
- }
+ showWizard: false,
+ };
columns = [
{ title: 'Name', content: (item) => item.name },
{ title: 'Description', content: (item) => item.desc },
- { title: 'Strategy', content: (item) => item.strategy?.type }
+ { title: 'Strategy', content: (item) => item.strategy?.type },
];
componentDidMount() {
@@ -32,41 +32,44 @@ export class JwtVerifiersPage extends Component {
const pathname = window.location.href;
const isEditPage = pathname.includes('edit');
- const SaveButton = isEditPage ?
}
- /> : null;
+ const SaveButton = isEditPage ? (
+ }
+ />
+ ) : null;
- return
- {isEditPage &&
-
-
-
- {
- const what = window.location.pathname.split('/')[3];
- const id = window.location.pathname.split('/')[5];
- window
- .newConfirm('Delete this verifier ?')
- .then((ok) => {
+ return (
+
+ {isEditPage && (
+
+
+
+ {
+ const what = window.location.pathname.split('/')[3];
+ const id = window.location.pathname.split('/')[5];
+ window.newConfirm('Delete this verifier ?').then((ok) => {
if (ok) {
- BackOfficeServices.deleteJwtVerifier(id)
- .then(() => {
- history.push('/' + what);
- });
+ BackOfficeServices.deleteJwtVerifier(id).then(() => {
+ history.push('/' + what);
+ });
}
});
- }}
- icon="fa-trash"
- text="Delete" />
- }
- {SaveButton}
-
- })
- }
+ }}
+ icon="fa-trash"
+ text="Delete"
+ />
+
+ )}
+ {SaveButton}
+
+ );
+ });
+ };
gotoVerifier = (verifier) => {
window.location = `/bo/dashboard/jwt-verifiers/edit/${verifier.id}`;
@@ -75,15 +78,20 @@ export class JwtVerifiersPage extends Component {
render() {
const { showWizard } = this.state;
- const JwtVerifierWizard = ClassifiedForms.wizards.JwtVerifierWizard
+ const JwtVerifierWizard = ClassifiedForms.wizards.JwtVerifierWizard;
return (
- {showWizard &&
this.setState({ showWizard: false })} disableSelectMode={true} />}
+ {showWizard && (
+ this.setState({ showWizard: false })}
+ disableSelectMode={true}
+ />
+ )}
item.id}
formPassProps={{
global: true,
- showHeader: window.location.href.includes('edit')
+ showHeader: window.location.href.includes('edit'),
}}
injectBottomBar={({ closeEditForm, state, setState }) => {
- return
- setState({ showAdvancedForm })}
- entity={ENTITIES.JWT_VERIFIERS}
- />
-
- Cancel
-
-
+ return (
+
+ setState({ showAdvancedForm })}
+ entity={ENTITIES.JWT_VERIFIERS}
+ />
+
+ Cancel
+
+
+ );
}}
injectTopBar={() => (
{
this.setState({
- showWizard: true
- })
+ showWizard: true,
+ });
}}
style={{ _backgroundColor: '#f9b000', _borderColor: '#f9b000', marginLeft: 5 }}>
Create with wizard
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/Designer.js b/otoroshi/javascript/src/pages/RouteDesigner/Designer.js
index 510a872874..9811824a86 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/Designer.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/Designer.js
@@ -15,7 +15,7 @@ import {
getPlugins,
} from '../../services/BackOfficeServices';
-import { Backend, Frontend, Plugins } from '../../forms/ng_plugins'
+import { Backend, Frontend, Plugins } from '../../forms/ng_plugins';
import {
EXCLUDED_PLUGINS,
@@ -113,7 +113,9 @@ const Dot = ({
const RemoveButton = ({ onRemove }) => {
return (
-
+
);
@@ -548,7 +550,6 @@ class Designer extends React.Component {
@@ -603,10 +604,12 @@ class Designer extends React.Component {
loadData = () => {
Promise.all([
nextClient.find(nextClient.ENTITIES.BACKENDS),
- this.props.value ? Promise.resolve(this.props.value) : nextClient.fetch(
- this.props.serviceMode ? nextClient.ENTITIES.SERVICES : nextClient.ENTITIES.ROUTES,
- this.props.routeId
- ),
+ this.props.value
+ ? Promise.resolve(this.props.value)
+ : nextClient.fetch(
+ this.props.serviceMode ? nextClient.ENTITIES.SERVICES : nextClient.ENTITIES.ROUTES,
+ this.props.routeId
+ ),
getCategories(),
Promise.resolve(
Plugins.map((plugin) => {
@@ -1188,8 +1191,7 @@ class Designer extends React.Component {
};
}
- if (this.props.setValue)
- this.props.setValue(newRoute);
+ if (this.props.setValue) this.props.setValue(newRoute);
return nextClient
.update(
@@ -1212,8 +1214,7 @@ class Designer extends React.Component {
this.setState({ route: r }, () => {
this.injectSaveButton();
- if (this.props.setValue)
- this.props.setValue(r);
+ if (this.props.setValue) this.props.setValue(r);
resolve();
});
@@ -2077,8 +2078,8 @@ class EditView extends React.Component {
collapsable: isPluginWithConfiguration ? true : false,
collapsed: false,
label: 'Informations',
- schema: PLUGIN_INFORMATIONS_SCHEMA
- }
+ schema: PLUGIN_INFORMATIONS_SCHEMA,
+ },
};
if (isPluginWithConfiguration)
formSchema = {
@@ -2372,10 +2373,7 @@ const BackendSelector = ({
backgroundColor: '#373735',
position: 'relative',
}}>
-
+
{
@@ -2383,9 +2381,7 @@ const BackendSelector = ({
}}>
Create a new backend
-
setUsingExistingBackend(true)}>
+ setUsingExistingBackend(true)}>
Select an existing backend
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/DesignerConfig.js b/otoroshi/javascript/src/pages/RouteDesigner/DesignerConfig.js
index 82bc1863a9..fdd8564daa 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/DesignerConfig.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/DesignerConfig.js
@@ -1,22 +1,22 @@
export const PLUGIN_INFORMATIONS_SCHEMA = {
enabled: {
type: 'bool',
- label: 'Enabled'
+ label: 'Enabled',
},
debug: {
type: 'bool',
- label: 'Debug'
+ label: 'Debug',
},
include: {
label: 'Include',
type: 'string',
- array: true
+ array: true,
},
exclude: {
label: 'Exclude',
type: 'string',
- array: true
- }
+ array: true,
+ },
};
export const EXCLUDED_PLUGINS = {
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/FeedbackButton.js b/otoroshi/javascript/src/pages/RouteDesigner/FeedbackButton.js
index 70edccb729..53b3793174 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/FeedbackButton.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/FeedbackButton.js
@@ -66,13 +66,12 @@ export function FeedbackButton({
.then(() => {
const diff = Date.now() - timer;
if (diff > 150) {
- if (onSuccess)
- setTimeout(onSuccess, 250)
+ if (onSuccess) setTimeout(onSuccess, 250);
onResult('success');
} else {
setTimeout(() => {
onResult('success');
- setTimeout(onSuccess, 250)
+ setTimeout(onSuccess, 250);
}, 150 - diff);
}
})
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/GraphQLForm.js b/otoroshi/javascript/src/pages/RouteDesigner/GraphQLForm.js
index 35e7fa630e..38e5a6a88f 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/GraphQLForm.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/GraphQLForm.js
@@ -764,17 +764,20 @@ const Type = ({
);
};
-const Header = ({ schemaView, toggleSchema, hide }) => <>
-
-
GraphQL Schema Editor
-
-
-
-
-
->
+const Header = ({ schemaView, toggleSchema, hide }) => (
+ <>
+
+
GraphQL Schema Editor
+
+
+
+
+
+ >
+);
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/ImportServiceDescriptor.js b/otoroshi/javascript/src/pages/RouteDesigner/ImportServiceDescriptor.js
index 65f183da76..0109d97c86 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/ImportServiceDescriptor.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/ImportServiceDescriptor.js
@@ -39,12 +39,11 @@ export function ImportServiceDescriptor({ hide }) {
text="Migrate and start editing"
className="mt-3"
onPress={() =>
- convertAsRoute(service)
- .then((res) => {
- history.push(`/routes/${res.id}?tab=informations`, {
- routeFromService: res,
- })
- })
+ convertAsRoute(service).then((res) => {
+ history.push(`/routes/${res.id}?tab=informations`, {
+ routeFromService: res,
+ });
+ })
}
icon={() => }
/>
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/Informations.js b/otoroshi/javascript/src/pages/RouteDesigner/Informations.js
index a74d047855..5806830705 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/Informations.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/Informations.js
@@ -4,181 +4,183 @@ import { nextClient } from '../../services/BackOfficeServices';
import { useHistory, useLocation } from 'react-router-dom';
import { useEntityFromURI } from '../../util';
import { FeedbackButton } from './FeedbackButton';
-import { RouteForm } from './form'
+import { RouteForm } from './form';
import { Button } from '../../components/Button';
import { ENTITIES, FormSelector } from '../../components/FormSelector';
-export const Informations = forwardRef(({ isCreation, value, setValue, setSaveButton, routeId }, ref) => {
- const history = useHistory();
- const location = useLocation()
- const [showAdvancedForm, toggleAdvancedForm] = useState(false)
+export const Informations = forwardRef(
+ ({ isCreation, value, setValue, setSaveButton, routeId }, ref) => {
+ const history = useHistory();
+ const location = useLocation();
+ const [showAdvancedForm, toggleAdvancedForm] = useState(false);
- const { capitalize, lowercase, fetchName, link } = useEntityFromURI();
+ const { capitalize, lowercase, fetchName, link } = useEntityFromURI();
- const isOnRouteCompositions = location.pathname.includes('route-compositions');
- const entityName = isOnRouteCompositions ? 'route composition' : 'route'
+ const isOnRouteCompositions = location.pathname.includes('route-compositions');
+ const entityName = isOnRouteCompositions ? 'route composition' : 'route';
- useImperativeHandle(ref, () => ({
- onTestingButtonClick() {
- history.push(`/${link}/${value.id}?tab=flow`, { showTryIt: true });
- },
- }));
+ useImperativeHandle(ref, () => ({
+ onTestingButtonClick() {
+ history.push(`/${link}/${value.id}?tab=flow`, { showTryIt: true });
+ },
+ }));
- useEffect(() => {
- setSaveButton( }
- />);
- }, [value]);
+ useEffect(() => {
+ setSaveButton(
+ }
+ />
+ );
+ }, [value]);
- function saveRoute() {
- if (isCreation || location.state?.routeFromService) {
- return nextClient
- .create(nextClient.ENTITIES[fetchName], value)
- .then(() => history.push(`/${link}/${value.id}?tab=flow`));
- } else {
- return nextClient.update(nextClient.ENTITIES[fetchName], value)
- .then((res) => {
+ function saveRoute() {
+ if (isCreation || location.state?.routeFromService) {
+ return nextClient
+ .create(nextClient.ENTITIES[fetchName], value)
+ .then(() => history.push(`/${link}/${value.id}?tab=flow`));
+ } else {
+ return nextClient.update(nextClient.ENTITIES[fetchName], value).then((res) => {
if (!res.error) setValue(res);
});
- }
- };
-
- const schema = {
- id: {
- type: 'string',
- visible: false
- },
- name: {
- type: 'string',
- label: `${capitalize} name`,
- placeholder: `Your ${lowercase} name`,
- help: `The name of your ${lowercase}. Only for debug and human readability purposes.`,
- // constraints: [constraints.required()],
- },
- enabled: {
- type: 'bool',
- label: 'Enabled',
- props: {
- }
- },
- capture: {
- type: 'bool',
- label: 'Capture route traffic',
- props: {
- labelColumn: 3
- }
- },
- debug_flow: {
- type: 'bool',
- label: 'Debug the route',
- props: {
- labelColumn: 3
- }
- },
- export_reporting: {
- type: 'bool',
- label: 'Export reporting',
- props: {
- labelColumn: 3
- }
- },
- description: {
- type: 'string',
- label: 'Description',
- placeholder: 'Your route description',
- help: 'The description of your route. Only for debug and human readability purposes.',
- },
- groups: {
- type: 'array-select',
- label: 'Groups',
- props: {
- optionsFrom: "/bo/api/proxy/api/groups",
- optionsTransformer: arr => arr.map(item => ({ value: item.id, label: item.name })),
- }
- },
- metadata: {
- type: 'object',
- label: 'Metadata'
- },
- tags: {
- type: 'string',
- array: true,
- label: 'Tags'
- },
- _loc: {
- type: 'location',
- props: {
- label: 'Location'
}
}
- };
- const flow = [
- {
- type: 'group',
- name: 'Expose your route',
- fields: ['enabled']
- },
- '_loc',
- {
- type: 'group',
- name: 'Route',
- fields: [
- 'name',
- 'description',
- 'groups',
- {
- type: 'grid',
- name: 'Flags',
- fields: ['debug_flow', 'export_reporting', 'capture']
- }
- ]
- },
- {
- type: 'group',
- name: 'Misc.',
- collapsed: true,
- fields: [
- 'metadata', 'tags'
- ]
- }
- ];
+ const schema = {
+ id: {
+ type: 'string',
+ visible: false,
+ },
+ name: {
+ type: 'string',
+ label: `${capitalize} name`,
+ placeholder: `Your ${lowercase} name`,
+ help: `The name of your ${lowercase}. Only for debug and human readability purposes.`,
+ // constraints: [constraints.required()],
+ },
+ enabled: {
+ type: 'bool',
+ label: 'Enabled',
+ props: {},
+ },
+ capture: {
+ type: 'bool',
+ label: 'Capture route traffic',
+ props: {
+ labelColumn: 3,
+ },
+ },
+ debug_flow: {
+ type: 'bool',
+ label: 'Debug the route',
+ props: {
+ labelColumn: 3,
+ },
+ },
+ export_reporting: {
+ type: 'bool',
+ label: 'Export reporting',
+ props: {
+ labelColumn: 3,
+ },
+ },
+ description: {
+ type: 'string',
+ label: 'Description',
+ placeholder: 'Your route description',
+ help: 'The description of your route. Only for debug and human readability purposes.',
+ },
+ groups: {
+ type: 'array-select',
+ label: 'Groups',
+ props: {
+ optionsFrom: '/bo/api/proxy/api/groups',
+ optionsTransformer: (arr) => arr.map((item) => ({ value: item.id, label: item.name })),
+ },
+ },
+ metadata: {
+ type: 'object',
+ label: 'Metadata',
+ },
+ tags: {
+ type: 'string',
+ array: true,
+ label: 'Tags',
+ },
+ _loc: {
+ type: 'location',
+ props: {
+ label: 'Location',
+ },
+ },
+ };
- if (!value) return null;
+ const flow = [
+ {
+ type: 'group',
+ name: 'Expose your route',
+ fields: ['enabled'],
+ },
+ '_loc',
+ {
+ type: 'group',
+ name: 'Route',
+ fields: [
+ 'name',
+ 'description',
+ 'groups',
+ {
+ type: 'grid',
+ name: 'Flags',
+ fields: ['debug_flow', 'export_reporting', 'capture'],
+ },
+ ],
+ },
+ {
+ type: 'group',
+ name: 'Misc.',
+ collapsed: true,
+ fields: ['metadata', 'tags'],
+ },
+ ];
- return (
- <>
- {showAdvancedForm ?
-
- :
- {
- setValue(v)
- }}
- />}
+ if (!value) return null;
-
- {!isOnRouteCompositions && }
- history.push(`/${link}`)}
- text="Cancel"
- />
-
- >
- );
-});
\ No newline at end of file
+ return (
+ <>
+ {showAdvancedForm ? (
+
+ ) : (
+ {
+ setValue(v);
+ }}
+ />
+ )}
+
+
+ {!isOnRouteCompositions && (
+
+ )}
+ history.push(`/${link}`)}
+ text="Cancel"
+ />
+
+ >
+ );
+ }
+);
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/MocksDesigner.js b/otoroshi/javascript/src/pages/RouteDesigner/MocksDesigner.js
index ca14eb9d84..b37e862bbf 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/MocksDesigner.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/MocksDesigner.js
@@ -4,7 +4,12 @@ import { FeedbackButton } from './FeedbackButton';
import { createTooltip } from '../../tooltips';
import { NgForm } from '../../components/nginputs/form';
-import { NgBooleanRenderer, NgNumberRenderer, NgSelectRenderer, NgStringRenderer } from '../../components/nginputs/inputs';
+import {
+ NgBooleanRenderer,
+ NgNumberRenderer,
+ NgSelectRenderer,
+ NgStringRenderer,
+} from '../../components/nginputs/inputs';
import { PillButton } from '../../components/PillButton';
const CodeInput = React.lazy(() => Promise.resolve(require('../../components/inputs/CodeInput')));
@@ -1102,19 +1107,22 @@ class NewEndpoint extends React.Component {
}
function Header({ hide, onDesigner, setDesigner }) {
- return <>
-
-
Mock responses
-
-
-
-
-
- >
+ return (
+ <>
+
+
Mock responses
+
+
+
+
+
+ >
+ );
}
export const HTTP_COLORS = {
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/RouteComposition.js b/otoroshi/javascript/src/pages/RouteDesigner/RouteComposition.js
index f04c8b2718..95dc589ef8 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/RouteComposition.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/RouteComposition.js
@@ -6,7 +6,7 @@ import { FeedbackButton } from './FeedbackButton';
import cloneDeep from 'lodash/cloneDeep';
import { useHistory, useRouteMatch } from 'react-router-dom';
import { NgForm } from '../../components/nginputs';
-import { Backend, Frontend } from '../../forms/ng_plugins'
+import { Backend, Frontend } from '../../forms/ng_plugins';
const CodeInput = React.lazy(() => Promise.resolve(require('../../components/inputs/CodeInput')));
@@ -83,27 +83,20 @@ class RouteForms extends React.Component {
collapsable: true,
schema: toUpperCaseLabels(Frontend.schema),
props: {
- showSummary: true
- }
+ showSummary: true,
+ },
},
backend: {
type: 'form',
label: 'Backend',
collapsable: true,
props: {
- showSummary: true
+ showSummary: true,
},
- flow: props => {
+ flow: (props) => {
if (props.backend_ref || props.using_backend_ref)
- return [
- 'using_backend_ref',
- 'backend_ref'
- ]
- else
- return [
- 'using_backend_ref',
- ...Backend.flow.otoroshi_full_flow
- ]
+ return ['using_backend_ref', 'backend_ref'];
+ else return ['using_backend_ref', ...Backend.flow.otoroshi_full_flow];
},
schema: {
...toUpperCaseLabels(Backend.schema),
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/RouteWizard.js b/otoroshi/javascript/src/pages/RouteDesigner/RouteWizard.js
index c1db8c0dbf..8909eb9ea0 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/RouteWizard.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/RouteWizard.js
@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { TextInput } from '../../components/inputs';
import { getOldPlugins, getPlugins, nextClient } from '../../services/BackOfficeServices';
-import { Plugins } from '../../forms/ng_plugins'
+import { Plugins } from '../../forms/ng_plugins';
import Loader from '../../components/Loader';
const RouteNameStep = ({ state, onChange }) => (
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/TryIt.js b/otoroshi/javascript/src/pages/RouteDesigner/TryIt.js
index 9c5e22781e..336ad21de3 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/TryIt.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/TryIt.js
@@ -87,10 +87,10 @@ export default function ({ route, hide }) {
setTesterView(
route &&
- route.plugins.find((f) => f.plugin.includes('GraphQLBackend')) &&
- route.plugins.find((f) => f.plugin.includes('GraphQLBackend')).enabled &&
- playgroundUrl &&
- lastQuery
+ route.plugins.find((f) => f.plugin.includes('GraphQLBackend')) &&
+ route.plugins.find((f) => f.plugin.includes('GraphQLBackend')).enabled &&
+ playgroundUrl &&
+ lastQuery
);
}
}, [route]);
@@ -134,7 +134,7 @@ export default function ({ route, hide }) {
if (storedData && r) {
setRequest(r);
}
- } catch (_) { }
+ } catch (_) {}
};
const saveTestingRouteHistory = (request) => {
@@ -286,15 +286,15 @@ export default function ({ route, hide }) {
),
...(format === 'basic'
? {
- 'authorization-header': {
- key: apikeyHeader || request.apikeyHeader,
- value: `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
- },
- }
+ 'authorization-header': {
+ key: apikeyHeader || request.apikeyHeader,
+ value: `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
+ },
+ }
: {
- 'Otoroshi-Client-Id': { key: 'Otoroshi-Client-Id', value: clientId },
- 'Otoroshi-Client-Secret': { key: 'Otoroshi-Client-Secret', value: clientSecret },
- }),
+ 'Otoroshi-Client-Id': { key: 'Otoroshi-Client-Id', value: clientId },
+ 'Otoroshi-Client-Secret': { key: 'Otoroshi-Client-Secret', value: clientSecret },
+ }),
};
};
@@ -311,16 +311,17 @@ export default function ({ route, hide }) {
padding: '5px',
borderRadius: '24px',
backgroundColor: '#373735',
- position: 'relative'
+ position: 'relative',
}}
- rightEnabled={(!testerView || testerView === 'rest')}
+ rightEnabled={!testerView || testerView === 'rest'}
onLeftClick={() => setTesterView('rest')}
onRightClick={() => setTesterView('graphql')}
- leftText='REST Tester'
- rightText='GraphQL Tester' />
+ leftText="REST Tester"
+ rightText="GraphQL Tester"
+ />
)}
-
+
{testerView === 'graphql' ? (
@@ -351,8 +352,7 @@ export default function ({ route, hide }) {
) : (
-
+
- search.length <= 0 ? true : plugin.name.includes(search)
- );
+ [...(step?.ctx?.plugins || [])].find((plugin) =>
+ search.length <= 0 ? true : plugin.name.includes(search)
+ );
const isPluginNameMatchingSearch = (plugin) =>
search.length <= 0 ? true : plugin.name.includes(search);
@@ -791,8 +791,8 @@ const ReportView = ({ report, search, setSearch, unit, setUnit, sort, setSort, f
return unit === 'ms'
? roundNsTo(report.duration_ns)
: unit === 'ns'
- ? report.duration_ns
- : 100;
+ ? report.duration_ns
+ : 100;
else {
const value = [...steps]
.filter(isOnFlow)
@@ -801,8 +801,8 @@ const ReportView = ({ report, search, setSearch, unit, setUnit, sort, setSort, f
const userPluginsFlow =
step.ctx && step.ctx.plugins
? [...(step.ctx?.plugins || [])]
- .filter(isPluginNameMatchingSearch)
- .reduce((subAcc, step) => subAcc + step.duration_ns, 0)
+ .filter(isPluginNameMatchingSearch)
+ .reduce((subAcc, step) => subAcc + step.duration_ns, 0)
: 0;
if (flow === 'user')
@@ -861,8 +861,9 @@ const ReportView = ({ report, search, setSearch, unit, setUnit, sort, setSort, f
setSelectedStep(-1)}
- className={`d-flex-between mt-1 px-3 py-2 report-step btn btn-${informations.state === 'Successful' ? 'success' : 'danger'
- }`}>
+ className={`d-flex-between mt-1 px-3 py-2 report-step btn btn-${
+ informations.state === 'Successful' ? 'success' : 'danger'
+ }`}>
Report
{reportDuration()} {unit}
@@ -884,13 +885,15 @@ const ReportView = ({ report, search, setSearch, unit, setUnit, sort, setSort, f
setSelectedPlugin(-1);
setSelectedStep(step.task);
}}
- className={`d-flex-between mt-1 px-3 py-2 report-step ${step.task === selectedStep ? 'btn-dark' : ''
- }`}>
+ className={`d-flex-between mt-1 px-3 py-2 report-step ${
+ step.task === selectedStep ? 'btn-dark' : ''
+ }`}>
{displaySubList && (
setSteps(
steps.map((s) =>
@@ -907,8 +910,8 @@ const ReportView = ({ report, search, setSearch, unit, setUnit, sort, setSort, f
{unit === 'ms'
? roundNsTo(step.duration_ns)
: unit === 'ns'
- ? step.duration_ns
- : percentage}{' '}
+ ? step.duration_ns
+ : percentage}{' '}
{unit}
)}
@@ -930,17 +933,18 @@ const ReportView = ({ report, search, setSearch, unit, setUnit, sort, setSort, f
key={plugin.name}
style={{ width: 'calc(100% - 12px)', marginLeft: '12px' }}
onClick={() => setSelectedPlugin(plugin.name)}
- className={`d-flex-between mt-1 px-3 py-2 report-step ${step.task === selectedStep && plugin.name === selectedPlugin
- ? 'btn-dark'
- : ''
- }`}>
+ className={`d-flex-between mt-1 px-3 py-2 report-step ${
+ step.task === selectedStep && plugin.name === selectedPlugin
+ ? 'btn-dark'
+ : ''
+ }`}>
{firstLetterUppercase(pluginName)}
{unit === 'ms'
? roundNsTo(plugin.duration_ns)
: unit === 'ns'
- ? plugin.duration_ns
- : pluginPercentage}{' '}
+ ? plugin.duration_ns
+ : pluginPercentage}{' '}
{unit}
@@ -964,8 +968,8 @@ const ReportView = ({ report, search, setSearch, unit, setUnit, sort, setSort, f
? informations
: steps.find((t) => t.task === selectedStep)
: steps
- .find((t) => t.task === selectedStep)
- ?.ctx?.plugins.find((f) => f.name === selectedPlugin),
+ .find((t) => t.task === selectedStep)
+ ?.ctx?.plugins.find((f) => f.name === selectedPlugin),
null,
4
) +
diff --git a/otoroshi/javascript/src/pages/RouteDesigner/index.js b/otoroshi/javascript/src/pages/RouteDesigner/index.js
index 64ade0aa3f..3374c67fd6 100644
--- a/otoroshi/javascript/src/pages/RouteDesigner/index.js
+++ b/otoroshi/javascript/src/pages/RouteDesigner/index.js
@@ -25,28 +25,27 @@ import PageTitle from '../../components/PageTitle';
import Loader from '../../components/Loader';
function BackToButton({ history }) {
- return {
- const what = window.location.pathname.split('/')[3];
- history.push('/' + what);
- }}
- icon="fa-arrow-left"
- text={`Back to ${window.location.pathname.split('/')[3]}`} />
+ return (
+ {
+ const what = window.location.pathname.split('/')[3];
+ history.push('/' + what);
+ }}
+ icon="fa-arrow-left"
+ text={`Back to ${window.location.pathname.split('/')[3]}`}
+ />
+ );
}
function DeleteRouteButton() {
- return {
- const what = window.location.pathname.split('/')[3];
- const id = window.location.pathname.split('/')[4];
- const kind =
- what === 'routes'
- ? nextClient.ENTITIES.ROUTES
- : nextClient.ENTITIES.SERVICES;
- window
- .newConfirm('are you sure you want to delete this entity ?')
- .then((ok) => {
+ return (
+ {
+ const what = window.location.pathname.split('/')[3];
+ const id = window.location.pathname.split('/')[4];
+ const kind = what === 'routes' ? nextClient.ENTITIES.ROUTES : nextClient.ENTITIES.SERVICES;
+ window.newConfirm('are you sure you want to delete this entity ?').then((ok) => {
if (ok) {
nextClient.deleteById(kind, id).then(() => {
// window.location = '/bo/dashboard/' + what;
@@ -54,25 +53,23 @@ function DeleteRouteButton() {
});
}
});
- }}
- icon="fa-trash"
- text="Delete" />
+ }}
+ icon="fa-trash"
+ text="Delete"
+ />
+ );
}
function DuplicateButton({ value, history }) {
- return {
- const what = window.location.pathname.split('/')[3];
- const id = window.location.pathname.split('/')[4];
- const prefix = (id.split('_')[0] || what) + '_';
- const newId = `${prefix}${v4()}`;
- const kind =
- what === 'routes'
- ? nextClient.ENTITIES.ROUTES
- : nextClient.ENTITIES.SERVICES;
- window
- .newConfirm('are you sure you want to duplicate this entity ?')
- .then((ok) => {
+ return (
+ {
+ const what = window.location.pathname.split('/')[3];
+ const id = window.location.pathname.split('/')[4];
+ const prefix = (id.split('_')[0] || what) + '_';
+ const newId = `${prefix}${v4()}`;
+ const kind = what === 'routes' ? nextClient.ENTITIES.ROUTES : nextClient.ENTITIES.SERVICES;
+ window.newConfirm('are you sure you want to duplicate this entity ?').then((ok) => {
if (ok) {
nextClient
.create(kind, {
@@ -83,21 +80,22 @@ function DuplicateButton({ value, history }) {
})
.then(() => {
// window.location = '/bo/dashboard/' + what + '/' + newId + '?tab=informations';
- history.push(
- '/' + what + '/' + newId + '?tab=informations'
- );
+ history.push('/' + what + '/' + newId + '?tab=informations');
});
}
});
- }}
- icon="fa-copy"
- text="Duplicate" />
+ }}
+ icon="fa-copy"
+ text="Duplicate"
+ />
+ );
}
function BackToRouteTab({ history, routeId, viewPlugins }) {
return (
- history.replace(`${routeId}?tab=routes&view_plugins=${viewPlugins}`)}
style={{
@@ -109,13 +107,14 @@ function BackToRouteTab({ history, routeId, viewPlugins }) {
Back to route
- )
+ );
}
function InformationsTab({ isActive, entity, value, history }) {
return (
- {
const to = `/${entity.link}/${value.id}?tab=informations`;
@@ -123,8 +122,8 @@ function InformationsTab({ isActive, entity, value, history }) {
history.replace({
pathname: to,
state: {
- value
- }
+ value,
+ },
});
}}
style={{
@@ -135,14 +134,15 @@ function InformationsTab({ isActive, entity, value, history }) {
Informations
-
- )
+
+ );
}
function RoutesTab({ isActive, entity, value, history }) {
return (
- {
const to = `/${entity.link}/${value.id}?tab=routes`;
@@ -150,8 +150,8 @@ function RoutesTab({ isActive, entity, value, history }) {
history.replace({
pathname: to,
state: {
- value
- }
+ value,
+ },
});
}}
style={{
@@ -162,14 +162,15 @@ function RoutesTab({ isActive, entity, value, history }) {
Routes
-
- )
+
+ );
}
function DesignerTab({ isActive, entity, value, history }) {
return (
- {
const to = `/${entity.link}/${value.id}?tab=flow`;
@@ -177,8 +178,8 @@ function DesignerTab({ isActive, entity, value, history }) {
history.replace({
pathname: to,
state: {
- value
- }
+ value,
+ },
});
}}
style={{
@@ -190,25 +191,38 @@ function DesignerTab({ isActive, entity, value, history }) {
Designer
- )
+ );
}
-function TesterButton({ disabled, setForceTester, viewRef, history, value, isOnViewPlugins, forceHideTester, query }) {
- const disabledHelp = 'Your route is disabled. Navigate to the informations page to turn it on again';
+function TesterButton({
+ disabled,
+ setForceTester,
+ viewRef,
+ history,
+ value,
+ isOnViewPlugins,
+ forceHideTester,
+ query,
+}) {
+ const disabledHelp =
+ 'Your route is disabled. Navigate to the informations page to turn it on again';
const hidden = !(isOnViewPlugins || forceHideTester !== true) || query === 'routes';
return (
-
-
+ {
- setForceTester(true)
- viewRef?.current?.onTestingButtonClick(history, value)
+ setForceTester(true);
+ viewRef?.current?.onTestingButtonClick(history, value);
}}
style={{
marginLeft: 20,
@@ -221,89 +235,110 @@ function TesterButton({ disabled, setForceTester, viewRef, history, value, isOnV
- )
+ );
}
function MoreActionsButton({ value, menu, history }) {
- return
-
-
-
-
- {menu}
-
-
+ return (
+
+
+
+
+
+ {menu}
+
+
+ );
}
-
function ManagerTitle({
- query, isCreation, isOnViewPlugins, entity, menu, pathname,
- value, viewPlugins, viewRef, location, history, saveButton,
- url, setForceTester, forceHideTester, routeId }) {
-
+ query,
+ isCreation,
+ isOnViewPlugins,
+ entity,
+ menu,
+ pathname,
+ value,
+ viewPlugins,
+ viewRef,
+ location,
+ history,
+ saveButton,
+ url,
+ setForceTester,
+ forceHideTester,
+ routeId,
+}) {
const commonsProps = {
- entity, value, history
+ entity,
+ value,
+ history,
};
const tabs = [
{
visible: () => isOnViewPlugins,
- component: () =>
+ component: () => (
+
+ ),
},
{
visible: () => !isOnViewPlugins,
tab: 'informations',
- component: () =>
+ component: () =>
,
},
{
visible: () => ['route-compositions'].includes(entity.link),
- component: () =>
+ component: () =>
,
},
{
visible: () => !isOnViewPlugins,
- component: () =>
+ component: () =>
,
},
{
- component: () =>
+ component: () => (
+
+ ),
},
{
visible: () => !isOnViewPlugins,
- component: () =>
- }
+ component: () =>
,
+ },
];
- return
- {!isCreation &&
- tabs
- .filter(tab => !tab.visible || tab.visible())
- .filter(tab => location.state?.routeFromService ? tab.tab === 'Informations' : true)
- .map(({ component }, i) => {
- const Tab = component;
- return
- })}
- {saveButton}
-
+ return (
+
+ {!isCreation &&
+ tabs
+ .filter((tab) => !tab.visible || tab.visible())
+ .filter((tab) => (location.state?.routeFromService ? tab.tab === 'Informations' : true))
+ .map(({ component }, i) => {
+ const Tab = component;
+ return ;
+ })}
+ {saveButton}
+
+ );
}
class Manager extends React.Component {
@@ -314,10 +349,10 @@ class Manager extends React.Component {
saveButton: undefined,
saveTypeButton: undefined,
forceHideTester: false,
- loading: !this.props.location?.state?.value
- }
+ loading: !this.props.location?.state?.value,
+ };
- viewRef = React.createRef(null)
+ viewRef = React.createRef(null);
componentDidMount() {
if (!this.props.location?.state?.value) {
@@ -333,15 +368,17 @@ class Manager extends React.Component {
if (this.props.match.params.routeId !== prevProps.match.params.routeId)
this.loadRoute('componentDidUpdate');
- if (['saveTypeButton', 'menuRefreshed', 'forceHideTester']
- .some(field => this.state[field] !== prevState[field])) {
- this.setTitle()
+ if (
+ ['saveTypeButton', 'menuRefreshed', 'forceHideTester'].some(
+ (field) => this.state[field] !== prevState[field]
+ )
+ ) {
+ this.setTitle();
}
}
setTitle = () => {
- if (!this.state.value)
- return;
+ if (!this.state.value) return;
const { entity, history, location } = this.props;
@@ -351,7 +388,7 @@ class Manager extends React.Component {
query = new URLSearchParams(`?${location.pathname.split('?')[1]}`).get('tab');
}
- const p = this.props.match.params
+ const p = this.props.match.params;
const isCreation = p.routeId === 'new';
const rawViewPlugins = new URLSearchParams(location.search).get('view_plugins');
@@ -359,55 +396,58 @@ class Manager extends React.Component {
const isOnViewPlugins = (viewPlugins !== -1) & (query === 'route_plugins');
const url = p.url;
- this.props.setTitle(() =>
this.setState({ forceHideTester: va })}
- pathname={location.pathname}
- menu={this.state.menu}
- routeId={p.routeId}
- url={url}
- query={query}
- isCreation={isCreation}
- isOnViewPlugins={isOnViewPlugins}
- entity={entity}
- value={this.state.value}
- viewPlugins={viewPlugins}
- viewRef={this.viewRef}
- location={location}
- history={history}
- saveButton={this.state.saveButton} />);
- }
+ this.props.setTitle(() => (
+ this.setState({ forceHideTester: va })}
+ pathname={location.pathname}
+ menu={this.state.menu}
+ routeId={p.routeId}
+ url={url}
+ query={query}
+ isCreation={isCreation}
+ isOnViewPlugins={isOnViewPlugins}
+ entity={entity}
+ value={this.state.value}
+ viewPlugins={viewPlugins}
+ viewRef={this.viewRef}
+ location={location}
+ history={history}
+ saveButton={this.state.saveButton}
+ />
+ ));
+ };
- loadRoute = from => {
-
+ loadRoute = (from) => {
const { routeId } = this.props.match.params || { routeId: undefined };
if (routeId === 'new') {
- nextClient.template(nextClient.ENTITIES[this.props.entity.fetchName])
- .then(value => {
- this.setState({ value, loading: false }, this.updateSidebar)
- });
+ nextClient.template(nextClient.ENTITIES[this.props.entity.fetchName]).then((value) => {
+ this.setState({ value, loading: false }, this.updateSidebar);
+ });
} else {
if (this.props.location.state && this.props.location.state.routeFromService) {
- this.setState({ value: this.props.location.state.routeFromService, loading: false }, this.updateSidebar)
+ this.setState(
+ { value: this.props.location.state.routeFromService, loading: false },
+ this.updateSidebar
+ );
} else {
- nextClient.fetch(nextClient.ENTITIES[this.props.entity.fetchName], routeId)
- .then(res => {
- if (!res.error) {
- this.setState({ value: res, loading: false }, this.updateSidebar)
- }
- });
+ nextClient.fetch(nextClient.ENTITIES[this.props.entity.fetchName], routeId).then((res) => {
+ if (!res.error) {
+ this.setState({ value: res, loading: false }, this.updateSidebar);
+ }
+ });
}
}
- }
+ };
updateSidebar = () => {
this.props.setSidebarContent(
);
- this.setTitle()
- }
+ this.setTitle();
+ };
render() {
const { entity, history, location, ...props } = this.props;
@@ -418,7 +458,7 @@ class Manager extends React.Component {
query = new URLSearchParams(`?${location.pathname.split('?')[1]}`).get('tab');
}
- const p = this.props.match.params
+ const p = this.props.match.params;
const isCreation = p.routeId === 'new';
const rawViewPlugins = new URLSearchParams(location.search).get('view_plugins');
@@ -431,15 +471,15 @@ class Manager extends React.Component {
render: () => (
this.setState({ forceHideTester: va })}
+ toggleTesterButton={(va) => this.setState({ forceHideTester: va })}
ref={this.viewRef}
tab={query}
history={history}
value={this.state.value}
- setValue={v => this.setState({ value: v }, this.setTitle)}
- setSaveButton={n => this.setState({ saveButton: n, saveTypeButton: 'routes' })}
+ setValue={(v) => this.setState({ value: v }, this.setTitle)}
+ setSaveButton={(n) => this.setState({ saveButton: n, saveTypeButton: 'routes' })}
viewPlugins={viewPlugins}
- setMenu={n => this.setState({ menu: n, menuRefreshed: Date.now() })}
+ setMenu={(n) => this.setState({ menu: n, menuRefreshed: Date.now() })}
/>
),
},
@@ -450,13 +490,20 @@ class Manager extends React.Component {
this.setState({ saveButton: n, saveTypeButton: 'route-compositions' })}
- setRoutes={routes => this.setState({
- value: {
- ...this.state.value,
- routes
- }
- }, this.setTitle)}
+ setSaveButton={(n) =>
+ this.setState({ saveButton: n, saveTypeButton: 'route-compositions' })
+ }
+ setRoutes={(routes) =>
+ this.setState(
+ {
+ value: {
+ ...this.state.value,
+ routes,
+ },
+ },
+ this.setTitle
+ )
+ }
viewPlugins={viewPlugins}
/>
),
@@ -466,52 +513,63 @@ class Manager extends React.Component {
const component = divs.filter((p) => p.predicate);
if (component.length > 0) {
- return
- {component[0].render()}
-
+ return (
+
+ {component[0].render()}
+
+ );
}
- return
-
- this.setState({ value: v })}
- setSaveButton={n => this.setState({ saveButton: n, saveTypeButton: 'informations' }, this.setTitle)}
- />
-
-
+ return (
+
+
+ this.setState({ value: v })}
+ setSaveButton={(n) =>
+ this.setState({ saveButton: n, saveTypeButton: 'informations' }, this.setTitle)
+ }
+ />
+
+
+ );
}
}
const RoutesView = ({ history }) => {
const [creation, setCreation] = useState(false);
const [importServiceDescriptor, setImportServiceDescriptor] = useState(false);
- const { pathname } = useLocation()
+ const { pathname } = useLocation();
return (
<>
{creation && setCreation(false)} history={history} />}
- {importServiceDescriptor && setImportServiceDescriptor(false)} history={history} />}
+ {importServiceDescriptor && (
+ setImportServiceDescriptor(false)} history={history} />
+ )}
- setCreation(true)}
- className="btn btn-primary"
- style={{ _backgroundColor: '#f9b000', _borderColor: '#f9b000', marginLeft: 5 }}>
- Create with wizard
-
- setImportServiceDescriptor(true)}
- className="btn btn-primary"
- style={{ _backgroundColor: '#f9b000', _borderColor: '#f9b000', marginLeft: 5 }}>
- Convert a service descriptor
-
- >}
+ injectTopBar={
+ pathname.includes('route-compositions') ? null : (
+ <>
+ setCreation(true)}
+ className="btn btn-primary"
+ style={{ _backgroundColor: '#f9b000', _borderColor: '#f9b000', marginLeft: 5 }}>
+ Create with wizard
+
+ setImportServiceDescriptor(true)}
+ className="btn btn-primary"
+ style={{ _backgroundColor: '#f9b000', _borderColor: '#f9b000', marginLeft: 5 }}>
+ Convert a service descriptor
+
+ >
+ )
+ }
/>
>
);
@@ -554,11 +612,8 @@ class RouteDesigner extends React.Component {
{ path: `${match.url}/:routeId/events`, component: ServiceEventsPage },
{
path: `${match.url}/:routeId`,
- component: p =>
- }
+ component: (p) => ,
+ },
].map(({ path, component }) => {
const Component = component;
return (
@@ -566,13 +621,15 @@ class RouteDesigner extends React.Component {
exact
key={path}
path={path}
- component={p => {
- return
+ component={(p) => {
+ return (
+
+ );
}}
/>
);
@@ -581,6 +638,6 @@ class RouteDesigner extends React.Component {
);
}
-};
+}
-export default withRouter(RouteDesigner);
\ No newline at end of file
+export default withRouter(RouteDesigner);
diff --git a/otoroshi/javascript/src/pages/ServicePage.js b/otoroshi/javascript/src/pages/ServicePage.js
index d887624625..5e59849ba3 100644
--- a/otoroshi/javascript/src/pages/ServicePage.js
+++ b/otoroshi/javascript/src/pages/ServicePage.js
@@ -1494,22 +1494,26 @@ export class ServicePage extends Component {
{this.state.service.env === 'prod' &&
this.state.service.subdomain.trim().length === 0 && (
)}
{this.state.service.env === 'prod' &&
this.state.service.subdomain.trim().length > 0 && (
)}
{this.state.service.env !== 'prod' && (
)}
>
@@ -3459,10 +3463,11 @@ export class TemplateInput extends Component {
- ${error
- ? `
${title}
`
- : `
${title}
`
- }
+ ${
+ error
+ ? `
${title}
`
+ : `
${title}
`
+ }
${message}
@@ -3565,9 +3570,7 @@ export class TemplateInput extends Component {
-
- {this.message}
-
+
{this.message}
},
}).then((r) => r.json());
-export const getEntityGraph = (entity, id) => fetchWrapper(`/entities/${entity}/${id}`)
+export const getEntityGraph = (entity, id) => fetchWrapper(`/entities/${entity}/${id}`);