From 7329967d7fb28ac64b2ed33965f02b33507007d0 Mon Sep 17 00:00:00 2001 From: Leopoldthecoder Date: Mon, 25 Dec 2023 14:55:54 +0800 Subject: [PATCH 1/5] feat(*): unified plugin forms --- package.json | 4 +- .../EntityForm/ConfirmModalDialog.vue | 162 ---- src/components/EntityForm/EntityForm.vue | 775 ---------------- .../EntityForm/NativeEntityForm.vue | 697 -------------- src/components/EntityForm/fields.js | 15 - src/components/EntityForm/helpers/index.js | 150 ---- .../EntityForm/mixins/EntityMixin.js | 357 -------- .../EntityForm/mixins/FormActionsMixin.js | 30 - src/components/EntityForm/mixins/FormPage.js | 137 --- .../EntityForm/mixins/RedirectMixin.js | 58 -- src/pages/consumers/CredentialForm.vue | 80 +- src/pages/consumers/CredentialPlugins.ts | 45 - src/pages/plugins/Detail.vue | 42 +- src/pages/plugins/Form.vue | 849 ++---------------- src/pages/plugins/List.vue | 6 +- src/pages/plugins/Select.vue | 38 +- src/schemas/ACL.ts | 9 - src/schemas/ApplicationRegistration.ts | 36 - src/schemas/ArrayCardContainerFields.ts | 7 - src/schemas/BasicAuth.ts | 13 - src/schemas/CustomSchemas.ts | 83 -- src/schemas/Datadog.ts | 59 -- src/schemas/HMAC.ts | 18 - src/schemas/JWT.ts | 36 - src/schemas/Kafka.ts | 27 - src/schemas/KeyAuth.ts | 11 - src/schemas/KeyAuthEnc.ts | 13 - src/schemas/MetricFields.ts | 7 - src/schemas/Mocking.ts | 8 - src/schemas/OAuth2.ts | 36 - src/schemas/RateLimiting.ts | 14 - src/schemas/RequestValidator.ts | 64 -- src/schemas/StatsD.ts | 78 -- src/schemas/StatsDAdvanced.ts | 88 -- src/schemas/Zipkin.ts | 29 - src/schemas/typedefs.ts | 76 -- src/styles/inputs.scss | 9 - yarn.lock | 86 +- 38 files changed, 241 insertions(+), 4011 deletions(-) delete mode 100644 src/components/EntityForm/ConfirmModalDialog.vue delete mode 100644 src/components/EntityForm/EntityForm.vue delete mode 100644 src/components/EntityForm/NativeEntityForm.vue delete mode 100644 src/components/EntityForm/fields.js delete mode 100644 src/components/EntityForm/helpers/index.js delete mode 100644 src/components/EntityForm/mixins/EntityMixin.js delete mode 100644 src/components/EntityForm/mixins/FormActionsMixin.js delete mode 100644 src/components/EntityForm/mixins/FormPage.js delete mode 100644 src/components/EntityForm/mixins/RedirectMixin.js delete mode 100644 src/pages/consumers/CredentialPlugins.ts delete mode 100644 src/schemas/ACL.ts delete mode 100644 src/schemas/ApplicationRegistration.ts delete mode 100644 src/schemas/ArrayCardContainerFields.ts delete mode 100644 src/schemas/BasicAuth.ts delete mode 100644 src/schemas/CustomSchemas.ts delete mode 100644 src/schemas/Datadog.ts delete mode 100644 src/schemas/HMAC.ts delete mode 100644 src/schemas/JWT.ts delete mode 100644 src/schemas/Kafka.ts delete mode 100644 src/schemas/KeyAuth.ts delete mode 100644 src/schemas/KeyAuthEnc.ts delete mode 100644 src/schemas/MetricFields.ts delete mode 100644 src/schemas/Mocking.ts delete mode 100644 src/schemas/OAuth2.ts delete mode 100644 src/schemas/RateLimiting.ts delete mode 100644 src/schemas/RequestValidator.ts delete mode 100644 src/schemas/StatsD.ts delete mode 100644 src/schemas/StatsDAdvanced.ts delete mode 100644 src/schemas/Zipkin.ts delete mode 100644 src/schemas/typedefs.ts diff --git a/package.json b/package.json index ccc2fc3..051cd2e 100644 --- a/package.json +++ b/package.json @@ -31,13 +31,13 @@ "@kong-ui-public/entities-gateway-services": "^2.2.12", "@kong-ui-public/entities-key-sets": "^2.1.16", "@kong-ui-public/entities-keys": "^2.1.16", - "@kong-ui-public/entities-plugins": "^2.5.4", + "@kong-ui-public/entities-plugins": "^2.5.8", "@kong-ui-public/entities-routes": "^2.2.9", "@kong-ui-public/entities-shared": "^2.2.0", "@kong-ui-public/entities-snis": "^2.1.16", "@kong-ui-public/entities-upstreams-targets": "^2.1.16", "@kong-ui-public/entities-vaults": "^2.1.16", - "@kong-ui-public/forms": "^2.1.10", + "@kong-ui-public/forms": "^2.1.16", "@kong-ui-public/i18n": "^2.0.3", "@kong-ui-public/misc-widgets": "^2.0.7", "@kong/icons": "^1.8.8", diff --git a/src/components/EntityForm/ConfirmModalDialog.vue b/src/components/EntityForm/ConfirmModalDialog.vue deleted file mode 100644 index 222cf9b..0000000 --- a/src/components/EntityForm/ConfirmModalDialog.vue +++ /dev/null @@ -1,162 +0,0 @@ - - - - - diff --git a/src/components/EntityForm/EntityForm.vue b/src/components/EntityForm/EntityForm.vue deleted file mode 100644 index c46cf59..0000000 --- a/src/components/EntityForm/EntityForm.vue +++ /dev/null @@ -1,775 +0,0 @@ - - - - - diff --git a/src/components/EntityForm/NativeEntityForm.vue b/src/components/EntityForm/NativeEntityForm.vue deleted file mode 100644 index a668dfb..0000000 --- a/src/components/EntityForm/NativeEntityForm.vue +++ /dev/null @@ -1,697 +0,0 @@ - - - - - diff --git a/src/components/EntityForm/fields.js b/src/components/EntityForm/fields.js deleted file mode 100644 index c23bd74..0000000 --- a/src/components/EntityForm/fields.js +++ /dev/null @@ -1,15 +0,0 @@ -const ArrayStringFieldSchema = { - type: 'array', - valueType: 'string', - valueArrayType: 'array', - itemContainerComponent: 'FieldArrayItem', - fieldClasses: 'kong-form-array-string-field', - fieldItemsClasses: 'kong-form-array-string-field-item', - inputAttributes: { class: 'form-control', style: { minWidth: '200px' } }, - validator: 'array', - styleClasses: 'kong-form-field-wrapper', - newElementButtonLabel: '+ Add', - newElementButtonLabelClasses: 'kong-form-new-element-button-label', -} - -export { ArrayStringFieldSchema } diff --git a/src/components/EntityForm/helpers/index.js b/src/components/EntityForm/helpers/index.js deleted file mode 100644 index 60f6539..0000000 --- a/src/components/EntityForm/helpers/index.js +++ /dev/null @@ -1,150 +0,0 @@ -const capitalizeRegEx = /(?:^|[\s-:'"])\w/g - -export const capitalize = (str) => { - if (!str) return '' - - return str.replace(capitalizeRegEx, (a) => a.toUpperCase()) -} - -export const convertToDotNotation = (key) => { - return key.replace(/-/g, '.') -} - -const camelCase = (str) => { - return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) { - return index === 0 ? word.toLowerCase() : word.toUpperCase() - }).replace(/\s+/g, '') -} - -export const generateFieldLabel = (fieldKey) => { - return convertToDotNotation(fieldKey) - .split('.') - .map((name) => capitalize(camelCase(name))) - .join('.') -} - -export const getMessageFromError = (error) => { - if (!error) { - return error - } - - if (error && error.response && error.response.data) { - if (error.response.data.message) { - return error.response.data.message - } - - if (typeof error.response.data === 'string') { - return error.response.data - } - - if (typeof error.response.data === 'object') { - return Object.keys(error.response.data) - .map(key => `${key} ${error.response.data[key]}`) - .join(', ') - } - } - - return error.message || 'There was an error' -} - -export const pickReadableField = (item, typeHint) => { - if (!item) return undefined - - let preferred - - switch (typeHint) { - case 'services': - case 'routes': - case 'upstreams': - case 'snis': - case 'keys': - case 'key-sets': - preferred = item.name - break - case 'plugins': - preferred = item.instance_name || item.name - break - case 'targets': - preferred = item.target - break - case 'consumers': - preferred = item.username || item.custom_id - break - case 'certificates': - case 'ca_certificates': - preferred = item.id - break - case 'vaults': - preferred = item.prefix || item.name - break - default: - preferred = item.name || item.username || item.email || item.group || item.key || - item.path || item.target - break - } - - return preferred || item.id -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const unFlattenObject = (obj) => { - const result = {} - - // Loop object and reduce each key to build nested structure - for (const key in obj) { - const keys = key.split('.') - - keys.reduce((acc, cur, curIdx) => { - return acc[cur] || - // If current key in acc is the next - // item in the split array (dot notation) - // set its value - (acc[cur] = isNaN(keys[curIdx + 1]) - ? (keys.length - 1 === curIdx ? obj[key] : {}) - : []) - }, result) - } - - return result -} - -export const uuidRegEx = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' - -export const redirectOnResponseStatus = ($router, status, location, options) => { - const opts = options || {} - const changeRoute = opts.replace ? $router.replace : $router.push - - return function (response) { - // Handle both success and error responses - const resp = response.response ? response.response : response - - if (resp && resp.status === status) { - changeRoute.call($router, location) - } - } -} - -export const compareObjects = (a, b) => { - return JSON.stringify(a) === JSON.stringify(b) -} - -export const isObjectEmpty = (obj) => { - return Object.keys(obj).length === 0 -} - -export const sortAlpha = (property) => { - return (a, b) => { - let propertyA = a[property] === undefined || a[property] === null ? '' : a[property] - let propertyB = b[property] === undefined || b[property] === null ? '' : b[property] - - if (Array.isArray(a[property])) { - propertyA = a[property][0] - } - - if (Array.isArray(b[property])) { - propertyB = b[property][0] - } - - return propertyA.localeCompare(propertyB) - } -} diff --git a/src/components/EntityForm/mixins/EntityMixin.js b/src/components/EntityForm/mixins/EntityMixin.js deleted file mode 100644 index 8c5dd47..0000000 --- a/src/components/EntityForm/mixins/EntityMixin.js +++ /dev/null @@ -1,357 +0,0 @@ -import { customFields } from '@kong-ui-public/forms' -import { capitalize, generateFieldLabel } from '../helpers' -import { ArrayStringFieldSchema } from '../fields' - -function buildCustomFields (schema) { - return schema.fields.reduce((acc, field) => { - if (field.fields) { - field.fields.forEach(subField => { - acc[subField.model] = subField - }) - } - - if (field.model) acc[field.model] = field - - return acc - }, {}) -} - -function setFieldDefaultValue (schema) { - return Array.isArray(schema.default) || (schema.default != null && - typeof schema.default !== 'object' && - schema.default !== 'function') -} - -/** - * Format field label - * @param {Object} schema - vue-form-generator schema - * @param {string} fieldName - form field name - * @returns {string} - */ -function formatFieldLabel (schema, fieldName) { - if (schema.inputType === 'hidden') { - // Remove field label or return dot notion label - return '' - - // When the field is not hidden convert the field name to display the exact same way - // it is documented (dot notation), not the way it is referenced in the DOM or in code. - // This can be overridden in the field schema - } - - return schema.label || generateFieldLabel(fieldName) -} - -export default { - computed: { - entityId () { - return this.$route && this.$route.query && this.$route.query.entity_id - }, - }, - - methods: { - scrollToBottom () { - this.$nextTick(() => { - window.scrollTo({ - top: document.body.clientHeight - window.innerHeight, - left: 0, - behavior: 'smooth', - }) - }) - }, - - /** - * a list of form fields not to render across all entity forms - * @returns {Array} an array of form fields not to render across all entity forms - */ - getBlacklist () { - return ['created_at', 'updated_at', 'id'] - }, - - /** - * this method takes in a combined inputSchema and outputs an object containing a model and a schema for VFG form consumption - * @param {Object} backendSchema the schema obtained via the fetchSchema() method - * @param {Object} frontendSchema the schema defined in the custom js files - * @returns {Object} an object containing a formModel and formSchema, both of which will be consumed by the VFG form generator - */ - parseSchema (backendSchema, frontendSchema) { - let inputSchema = {} - if (backendSchema || this.schema) { - inputSchema = backendSchema || (this.schema.fields ? this.schema.fields : this.schema) - } - - const blacklist = this.getBlacklist().concat(this.schema ? this.schema.blacklist : []) - - const inputSchemaFields = Object.keys(inputSchema).filter(f => !blacklist.includes(f)) - - // Comparator function for comparing schema objects should not be added to fields - const comparatorIdx = inputSchemaFields.indexOf('comparator') - - comparatorIdx > -1 && inputSchemaFields.splice(comparatorIdx, 1) - - const formSchema = { fields: [] } - const formModel = {} - - // Iterate over each schema field to augment with display configuration. - inputSchemaFields.forEach(fieldName => { - this.buildFormSchema(inputSchema[fieldName], fieldName, inputSchema, formModel, formSchema, frontendSchema) - }) - - // Assume the fields are sorted, unless they have an `order` property - formSchema.fields.sort((a, b) => { - a.order = a.order || 0 - b.order = b.order || 0 - - return a.order - b.order - }) - - return { - schema: formSchema, - model: formModel, - options: { - noneSelectedText: 'Nothing Selected...', - helpAsHtml: true, - }, - } - }, - - /** - * This is a helper function for mergeSchema. It takes in a field and depending on the field type, - * sets the appropiate properties for it to be consumed by VFG (vue form generator) - * @param {Object} field the field coming from either the backend schema OR a recursive call to be merged with the frontend schema - * @param {string} key the current backend schema key we are looping over - * @param {Object} inputSchema this is the inputSchema we are building to be consumed later by parseSchema - * @param {Object} formModel VFG form model - * @param {Object} formSchema VFG form schema - * @param {Object} frontendSchema the schema coming from the frontend (if it exists) - * @returns {Object} an object representing the combined inputSchema - which will be used by mergeSchema as well as recursive calls - */ - // eslint-disable-next-line max-params - buildFormSchema (field, key, inputSchema, formModel, formSchema, frontendSchema) { - const fieldHasDefaultValue = setFieldDefaultValue(field, key) - - // Set default value should one exist, or empty string. Existing data - // will replace this later. - formModel[key] = fieldHasDefaultValue ? field.default : null - // Update model to be field name for reference within Vue - field.id = key - field.model = key - - if (field.fields && field.type === 'record') { - this.handleFieldRecord(field, key, inputSchema, formModel, formSchema, frontendSchema) - } else { - inputSchema[key] = field - this.fieldSchemaHandler(field, formModel) - if (frontendSchema && frontendSchema[key]) { - this.mergeFrontendSchema(inputSchema[key], frontendSchema[key]) - } - - // Set VFG form schema - formSchema.fields.push(field) - } - - return inputSchema - }, - - /** - * - * @param {*} backendSchemaVal backend schema key value - * @param {*} frontendSchemaVal frontend schema key value - */ - mergeFrontendSchema (backendSchemaVal, frontendSchemaVal) { - if (frontendSchemaVal) { - Object.assign(backendSchemaVal, frontendSchemaVal) - if (frontendSchemaVal.label) { - backendSchemaVal.label = frontendSchemaVal.label - } - } - - return backendSchemaVal - }, - - /** - * Remove id of dot notated foreign key if null - * @param {string} key - * @param {string} model - * @returns {string} - */ - unsetNullForeignKey (key, model) { - const keys = ['service.id', 'route.id', 'consumer.id'] - - if (keys.indexOf(key) > -1 && model[key] === null) { - delete model[key] - model[key.replace('.id', '')] = null - } - }, - - /** - * Catchall handler for Kong's schema fields coming from the Kong dao schema - * parsing. Handles things like inferring schema types and modifying the - * formModel to account for custom fields e.g. autosuggest, foreign, etc. - * @param {Object} schema vfg schema to potentially modify - * @param {Object} formModel vfg form model to potentially modify - */ - fieldSchemaHandler (schema, formModel) { - this.handleCustomFields(schema, formModel) - - switch (schema.type) { - case 'foreign': - this.handleFieldForeign(schema, formModel) - break - case 'number': - this.handleFieldNumber(schema) - schema.attributes = { step: 'any' } - break - case 'integer': - this.handleFieldNumber(schema) - break - case 'string': - this.handleFieldString(schema) - break - case 'set': - this.handleFieldSet(schema) - break - case 'boolean': - this.handleFieldBoolean(schema) - break - case 'map': - this.handleFieldMap(schema) - break - } - - // Set the field label - schema.label = formatFieldLabel(schema, schema.model) - }, - - /** - * Handles field of Kong's schema type "foreign" so VFG can understand - * @param {Object} schema vfg schema to modify - * @param {*} formModel vfg form model to modify - */ - handleFieldForeign (schema, formModel) { - schema.type = 'input' - schema.inputType = 'hidden' - schema.styleClasses = 'kong-form-hidden-field-wrapper' - const foreignKeyId = (this.entityId && this.entityId.split(',')[0]) || this.$route.params.id - - formModel[schema.model] = foreignKeyId ? { id: foreignKeyId } : null - }, - - handleFieldNumber (schema) { - schema.type = 'input' - schema.inputType = 'number' - - if (schema.between && schema.between.length === 2) { - schema.min = schema.between[0] - schema.max = schema.between[1] - } - }, - - handleFieldString (schema) { - if (Object.prototype.hasOwnProperty.call(schema, 'one_of')) { - schema.type = 'select' - schema.values = schema.one_of - schema.selectOptions = { - hideNoneSelectedText: true, - } - } else { - schema.type = 'input' - schema.inputType = 'text' - } - }, - - handleFieldSet (schema) { - schema.type = 'input' - schema.inputType = 'text' - schema.valueType = 'array' - schema.valueArrayType = 'string' - }, - - handleFieldBoolean (schema) { - schema.type = 'checkbox' - schema.default = true - schema.required = false - }, - - handleFieldMap (schema) { - schema.type = 'object-advanced' - - if (schema.values.type === 'array') { - const { type: elementsType } = schema.values.elements || {} - - schema.schema = { - fields: [{ - schema: { - fields: [{ - ...ArrayStringFieldSchema, - model: schema.model, - valueArrayType: elementsType === 'integer' ? 'number' : elementsType || 'string', - inputAttributes: { - ...ArrayStringFieldSchema.inputAttributes, - type: elementsType === 'integer' ? 'number' : 'text', - inputMode: elementsType === 'integer' ? 'numeric' : 'text', - }, - }], - }, - }], - } - } else if (schema.values.fields) { - schema.schema = { - fields: [ - { - type: 'object', - model: 'object', - schema: { - fields: schema.values.fields.map(f => { - const modelName = Object.keys(f)[0] - - return { - model: modelName, - type: 'input', - label: capitalize(modelName), - placeholder: modelName, - inputType: f[modelName].type, - } - }), - }, - }, - ], - } - } - }, - - // eslint-disable-next-line max-params - handleFieldRecord (field, key, inputSchema, formModel, formSchema, frontendSchema) { - // some fields have subfields inside of it which have their own arrays and keys - which requires a recursive call to setField - // in order to flatten them up to the top level inputSchema array for displaying - these will be unflattened later in the getModel() call when submitting - field.fields.forEach(topLevelSchema => { - Object.keys(topLevelSchema).forEach(propName => { - const subfield = topLevelSchema[propName] - - inputSchema = this.buildFormSchema(subfield, key + '-' + propName, inputSchema, formModel, formSchema, frontendSchema) - }) - }) - }, - - /** - * - * @param {Object} schema hard-coded schema from file - * @param {*} formModel VFG Form model - */ - handleCustomFields (schema, formModel) { - if (!customFields.includes(schema.model)) { - return - } - - const customFieldsSchema = buildCustomFields(schema) - - customFields.forEach(field => { - Object.keys(customFieldsSchema).forEach(field => { - const fieldHasDefaultValue = setFieldDefaultValue(customFieldsSchema[field], field) - - formModel[field] = fieldHasDefaultValue ? customFieldsSchema[field].default : null - }) - delete formModel[field] - }) - }, - }, -} diff --git a/src/components/EntityForm/mixins/FormActionsMixin.js b/src/components/EntityForm/mixins/FormActionsMixin.js deleted file mode 100644 index 6cd75c4..0000000 --- a/src/components/EntityForm/mixins/FormActionsMixin.js +++ /dev/null @@ -1,30 +0,0 @@ -export default { - data () { - return { - isSaveActionDisabled: false, - } - }, - - computed: { - formRef () { - return this.$refs.form - }, - }, - - mounted () { - this.isSaveActionDisabled = this.formRef.isSaveActionDisabled - this.$watch('formRef.isSaveActionDisabled', (disabled) => { - this.isSaveActionDisabled = disabled - }) - }, - - methods: { - handleFormSave () { - return this.formRef.confirm() - }, - - handleFormCancel () { - return this.formRef.cancel() - }, - }, -} diff --git a/src/components/EntityForm/mixins/FormPage.js b/src/components/EntityForm/mixins/FormPage.js deleted file mode 100644 index ca5959c..0000000 --- a/src/components/EntityForm/mixins/FormPage.js +++ /dev/null @@ -1,137 +0,0 @@ -/** - Default form page mixins - - Requires: - - `resourceEndpoint` - resource endpoint - - Optional: - - `id` - resource identifier - - Provides: - - `isEditing` - `true` when `id` exists - - `redirectRoute` - route to redirect to, defaults to `{ name: }`. - - `buttonText` - `Update` or `Create` depending on `isEditing` - - `onFormLoad` - handler for `onLoad` callback of `EntityForm` - - `onFormSubmit` - handler for `onSubmit` callback of `EntityForm` - - `getRecord` - method to retrieve resource record - - `createRecord` - method to create a resource record - - `updateRecord` - method to update a resource record - - `transformRecord` - method to transform a resource record before update and create -*/ -import { redirectOnResponseStatus } from '../helpers' -import { apiService } from '@/services/apiService' - -export default { - computed: { - $_redirectOnSubmit () { - return this.redirectOnSubmit !== undefined ? this.redirectOnSubmit : true - }, - - isEditing () { - return !!this.id - }, - - buttonText () { - return this.isEditing ? 'Save' : 'Create' - }, - - /** - * @returns {RawLocation|-1} returns a vue router location or -1 indicating - * that the router should go back, e.g. $router.go(-1) - */ - redirectRoute () { - if (this.redirectPath) { - return this.redirectPath - } - - return { name: this.resourceEndpoint } - }, - }, - - methods: { - onFormLoad () { - return Promise.resolve(this.id ? this.getRecord() : false) - .catch(redirectOnResponseStatus(this.$router, 404, '/404', { replace: true })) - }, - - async onFormSubmit (model, callback = this.redirectRoute) { - const record = this.transformRecord(model) - - return await this.isEditing - ? this.updateRecord(record) - : this.createRecord(record, callback) - }, - - getRecord () { - return apiService.findRecord(this.resourceEndpoint, this.id) - }, - - /** - * @param {Object} model - form model - * @param {RawLocation|Function} callback - vue router location or function - * to calculate the vue router location from the response - */ - async createRecord (model, callback) { - return apiService.createRecord(this.resourceEndpoint, model) - .then(res => { - if (this.hideSubmit) { - return res.data - } - - this.$emit('submit', res.data) - - // if the parent form passes in redirectOnSubmit = false, then we don't do anything after creation - if (!this.$_redirectOnSubmit) { - return null - } - - // if parent form defines a redirectRouteNames object, we either go back to previous page if -1 is passed - // else we go to the named route - const redirectCreateRoute = this.redirectRouteNames && this.redirectRouteNames.create - if (redirectCreateRoute) { - return redirectCreateRoute === '-1' ? this.$router.go(-1) : this.$router.push({ name: redirectCreateRoute, params: this.$router.params }) - } - - const link = this.redirectPath || this.returnLink - - if (link) { - return this.$router.push(link) - } - - const location = typeof callback === 'function' - ? callback(model, res.data) - : callback - - redirectOnResponseStatus(this.$router, 201, location)(res) - - return res.data - }) - }, - - async updateRecord (model) { - return apiService.updateRecord(this.resourceEndpoint, this.id, model) - .then(res => { - const link = this.redirectPath || this.returnLink - - // if parent form defines a redirectRouteNames object, we either go back to previous page if -1 is passed - // else we go to the named route - const redirectUpdateRoute = this.redirectRouteNames && this.redirectRouteNames.update - if (redirectUpdateRoute) { - return redirectUpdateRoute === '-1' ? this.$router.go(-1) : this.$router.push({ name: redirectUpdateRoute, params: this.$router.params }) - } - - if (link) { - return this.$router.push(link) - } - - redirectOnResponseStatus(this.$router, 200, { name: this.resourceEndpoint })(res) - - return res.data - }) - }, - - transformRecord (model) { - return model - }, - }, -} diff --git a/src/components/EntityForm/mixins/RedirectMixin.js b/src/components/EntityForm/mixins/RedirectMixin.js deleted file mode 100644 index f83db76..0000000 --- a/src/components/EntityForm/mixins/RedirectMixin.js +++ /dev/null @@ -1,58 +0,0 @@ -const extractRedirectPath = ($route, urlKey) => { - const query = $route.query[urlKey] - let url = null - - if (Array.isArray(query)) { - url = query[0] - console.warn(`extractRedirectPath: "${urlKey}" in query should not be an array, using first element this time`) - } else if (typeof query === 'string') { - url = query - } - - return url -} - -export default { - computed: { - redirectPath () { - return extractRedirectPath(this.$route, 'redirect') - }, - redirectRouteQuery () { - return { redirect: this.redirectPath } - }, - postDeletePath () { - return extractRedirectPath(this.$route, 'postDelete') - }, - postDeleteRouteQuery () { - return { postDelete: this.postDeletePath } - }, - }, - methods: { - createRedirectRouteQuery (redirect = this.$route.fullPath) { - return { redirect } - }, - createPostDeleteRouteQuery (postDelete) { - if (typeof postDelete !== 'string') { - postDelete = this.postDeletePath ?? this.$route.fullPath - } - - return { postDelete } - }, - redirect (replace = false, goBack = false) { - const routerFn = replace ? this.$router.replace : this.$router.push - if (this.redirectPath) { - routerFn(this.redirectPath) - - return true - } - - if (goBack) { - this.$router.go(-1) - - return true - } - - return false - }, - }, -} diff --git a/src/pages/consumers/CredentialForm.vue b/src/pages/consumers/CredentialForm.vue index 17c8623..85011f8 100644 --- a/src/pages/consumers/CredentialForm.vue +++ b/src/pages/consumers/CredentialForm.vue @@ -1,47 +1,59 @@ diff --git a/src/pages/consumers/CredentialPlugins.ts b/src/pages/consumers/CredentialPlugins.ts deleted file mode 100644 index 55cf57d..0000000 --- a/src/pages/consumers/CredentialPlugins.ts +++ /dev/null @@ -1,45 +0,0 @@ -import ACLSchema from '@/schemas/ACL' -import BasicAuthSchema from '@/schemas/BasicAuth' -import KeyAuthSchema from '@/schemas/KeyAuth' -import KeyAuthEncSchema from '@/schemas/KeyAuthEnc' -import OAuth2Schema from '@/schemas/OAuth2' -import HMACSchema from '@/schemas/HMAC' -import JWTSchema from '@/schemas/JWT' - -export default { - 'acl': { - schema: ACLSchema, - endpoint: '/acls', - schemaEndpoint: 'acls', - }, - 'basic-auth': { - schema: BasicAuthSchema, - endpoint: '/basic-auth', - schemaEndpoint: 'basicauth_credentials', - }, - 'key-auth': { - schema: KeyAuthSchema, - endpoint: '/key-auth', - schemaEndpoint: 'keyauth_credentials', - }, - 'key-auth-enc': { - schema: KeyAuthEncSchema, - endpoint: '/key-auth-enc', - schemaEndpoint: 'keyauth_enc_credentials', - }, - 'oauth2': { - schema: OAuth2Schema, - endpoint: '/oauth2', - schemaEndpoint: 'oauth2_credentials', - }, - 'hmac-auth': { - schema: HMACSchema, - endpoint: '/hmac-auth', - schemaEndpoint: 'hmacauth_credentials', - }, - 'jwt': { - schema: JWTSchema, - endpoint: '/jwt', - schemaEndpoint: 'jwt_secrets', - }, -} diff --git a/src/pages/plugins/Detail.vue b/src/pages/plugins/Detail.vue index 3d6d9e3..886007d 100644 --- a/src/pages/plugins/Detail.vue +++ b/src/pages/plugins/Detail.vue @@ -14,17 +14,16 @@ class="button-edit" entity="plugin" :route-options="{ - query: { - entity_type: route.query?.entity_type, - entity_id: route.query?.entity_id, - }, + query: entityScope ? { + [entityScope.keyInQuery]: entityScope.id, + } : undefined, }" /> @@ -47,19 +46,28 @@ const { t } = useI18n() const id = computed(() => (route.params.id as string) ?? '') const pluginType = computed(() => (route.params.pluginType ?? '') as string) -const entityType = computed(() => { - if (!route.query?.entity_type) { - return undefined +const entityScope = computed(() => { + if (route.query.serviceId) { + return { + id: route.query.serviceId as string, + typeLiteral: 'services', + keyInQuery: 'serviceId', + } + } else if (route.query.routeId) { + return { + id: route.query.routeId as string, + typeLiteral: 'routes', + keyInQuery: 'routeId', + } + } else if (route.query.consumerId) { + return { + id: route.query.consumerId as string, + typeLiteral: 'consumers', + keyInQuery: 'consumerId', + } } - return `${(route.query.entity_type as string).split('_')[0]}s` -}) -const entityId = computed(() => { - if (!route.query?.entity_id) { - return undefined - } - - return route.query.entity_id as string + return null }) const pluginDetailConfig = reactive({ diff --git a/src/pages/plugins/Form.vue b/src/pages/plugins/Form.vue index 5524acd..4b0623b 100644 --- a/src/pages/plugins/Form.vue +++ b/src/pages/plugins/Form.vue @@ -1,781 +1,116 @@