Skip to content

Commit

Permalink
feat(entities-plugins): support route-by-header (#952)
Browse files Browse the repository at this point in the history
  • Loading branch information
Leopoldthecoder authored Nov 29, 2023
1 parent d494c15 commit 2b8578f
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 21 deletions.
5 changes: 5 additions & 0 deletions packages/core/forms/src/generator/FormGenerator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,11 @@ export default {
}
}
}
.kong-form-new-element-button-label {
margin-bottom: $kui-space-80!important;
margin-top: $kui-space-80!important;
}
} // fieldset
// stylelint-disable no-duplicate-selectors
Expand Down
4 changes: 4 additions & 0 deletions packages/core/forms/src/generator/FormGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,10 @@ $errorColor: #f00;
.form-group-label {
display: flex;
justify-content: space-between;

:deep(.k-tooltip p) {
margin: 0;
}
}

.icon-wrapper {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<template>
<div class="key-value-pairs-editor">
<div
v-for="(pair, index) in pairs"
:key="index"
class="pair-item"
>
<input
class="form-control"
:data-testid="`${getFieldID(schema)}-pair-key-${index}`"
:placeholder="schema.keyInputPlaceholder ?? 'Key'"
type="text"
:value="pair.key"
@input="(e) => { onInput(e, index, 'key') }"
>
<input
class="form-control"
:data-testid="`${getFieldID(schema)}-pair-value-${index}`"
:placeholder="schema.valueInputPlaceholder ?? 'Value'"
type="text"
:value="pair.value"
@input="(e) => { onInput(e, index, 'value') }"
>
<KButton
appearance="tertiary"
:data-testid="`${getFieldID(schema)}-remove-pair-${index}`"
@click="() => { removePair(index) }"
>
<TrashIcon />
</KButton>
</div>
<KButton
appearance="tertiary"
:class="schema.newElementButtonLabelClasses"
:data-testid="`${getFieldID(schema)}-add-pair`"
type="button"
@click="addPair"
>
{{ schema.newElementButtonLabel ?? '+ Add Pair' }}
</KButton>
</div>
</template>

<script>
import abstractField from '../abstractField'
import { TrashIcon } from '@kong/icons'
export default {
name: 'FieldKeyValuePairs',
components: { TrashIcon },
mixins: [abstractField],
data() {
return {
pairs: [],
}
},
watch: {
pairs: {
handler() {
this.updateValue()
},
deep: true,
},
},
created() {
if (!this.value) {
this.value = {}
}
const modelPairs = this.model?.[this.schema?.model] ?? {}
Object.keys(modelPairs).forEach((key) => {
this.pairs.push({
key,
value: modelPairs[key],
})
})
},
methods: {
onInput(e, index, type) {
this.pairs[index][type] = e.target.value
},
updateValue() {
this.value = this.pairs.reduce((acc, { key, value }) => ({
...acc,
...(key && value ? { [key]: value } : null),
}), {})
},
addPair() {
this.pairs.push({
key: '',
value: '',
})
},
removePair(index) {
this.pairs.splice(index, 1)
},
},
}
</script>
<style lang="scss" scoped>
.key-value-pairs-editor {
width: 100%;
.pair-item {
display: flex;
&:not(:first-child) {
margin-top: 12px;
}
input {
margin-right: 12px;
}
}
}
</style>
1 change: 1 addition & 0 deletions packages/core/forms/src/generator/utils/fieldsLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ export { default as FieldSelectionGroup } from '../fields/advanced/FieldSelectio
export { default as FieldRadio } from '../fields/advanced/FieldRadio.vue'
export { default as FieldArrayCardContainer } from '../fields/advanced/FieldArrayCardContainer.vue'
export { default as FieldMultiselect } from '../fields/advanced/FieldMultiselect.vue'
export { default as FieldKeyValuePairs } from '../fields/advanced/FieldKeyValuePairs.vue'
18 changes: 0 additions & 18 deletions packages/entities/entities-plugins/src/components/PluginForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,6 @@
</template>
</KEmptyState>

<KEmptyState
v-else-if="isDisabled"
cta-is-hidden
is-error
>
<template #title>
{{ t('plugins.form.disabled_warning') }}
</template>
</KEmptyState>

<EntityBaseForm
v-else
:can-submit="canSubmit"
Expand Down Expand Up @@ -240,14 +230,6 @@ const fetchUrl = computed((): string => {
return endpoints.form[props.config.app].edit
})
// non-editable plugin type. They shouldn't be able to get to this unless they manually
// type in the URL
const isDisabled = computed((): boolean => {
const currentPlugin = Object.keys(customSchemas).find((key: string) => key === props.pluginType)
return currentPlugin ? (customSchemas[currentPlugin as keyof typeof customSchemas] as Record<string, any>)?.configurationDisabled : false
})
const entityMap = computed((): Record<string, PluginEntityInfo> => {
const consumerId = (props.config.entityType === 'consumers' && props.config.entityId) || record.value?.consumer?.id
const consumerGroupId = (props.config.entityType === 'consumer_groups' && props.config.entityId) || record.value?.consumer_group?.id
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { RouteByHeaderSchema } from '../../types/plugins/route-by-header'
import { arrayCardContainerFieldSchema } from './ArrayCardContainerFields'

export const routeByHeaderSchema: RouteByHeaderSchema = {
'config-rules': {
...arrayCardContainerFieldSchema,
newElementButtonLabel: '+ Add Rule',
items: {
type: 'object',
schema: {
fields: [{
label: 'Upstream Name',
model: 'upstream_name',
type: 'input',
help: 'Target hostname where traffic will be routed in case of condition match',
placeholder: 'Hostname',
inputType: 'text',
}, {
label: 'Condition',
model: 'condition',
type: 'keyValuePairs',
help: 'List of headers name and value pairs',
newElementButtonLabelClasses: 'kong-form-new-element-button-label',
newElementButtonLabel: '+ Add Condition',
keyInputPlaceholder: 'Header name',
valueInputPlaceholder: 'Header value',
}],
},
},
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { mockingSchema } from './plugin-schemas/Mocking'
import { preFunctionSchema } from './plugin-schemas/PreFunction'
import { rateLimitingSchema } from './plugin-schemas/RateLimiting'
import { requestTransformerAdvancedSchema } from './plugin-schemas/RequestTransformerAdvanced'
import { routeByHeaderSchema } from './plugin-schemas/RouteByHeader'
import { graphqlRateLimitingAdvancedSchema } from './plugin-schemas/GraphQLRateLimitingAdvanced'
import { statsDSchema } from './plugin-schemas/StatsD'
import { ArrayStringFieldSchema } from './plugin-schemas/ArrayStringFieldSchema'
Expand Down Expand Up @@ -63,7 +64,7 @@ export const useSchemas = (entityId?: string) => {
},

'route-by-header': {
configurationDisabled: true,
...routeByHeaderSchema,
},

mocking: {
Expand Down
1 change: 0 additions & 1 deletion packages/entities/entities-plugins/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,6 @@
}
},
"form": {
"disabled_warning": "This plugin must be configured using the Kong Admin API. Please see the documentation.",
"no_selection": "No selection...",
"fields": {
"enabled": {
Expand Down
3 changes: 2 additions & 1 deletion packages/entities/entities-plugins/src/types/plugin-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { StatsDAdvancedSchema } from './plugins/stats-d-advanced'
import type { KafkaSchema } from './plugins/kafka-schema'
import type { UpstreamTlsSchema } from './plugins/upstream-tls'
import type { RateLimitingSchema } from './plugins/rate-limiting'
import type { RouteByHeaderSchema } from './plugins/route-by-header'
import type { GraphQLRateLimitingAdvancedSchema } from './plugins/graphql-rate-limiting-advanced'

export interface BasePluginSelectConfig {
Expand Down Expand Up @@ -188,7 +189,7 @@ export interface CustomSchemas {
mocking: MockingSchema
'rate-limiting': RateLimitingSchema
'rate-limiting-advanced': RateLimitingSchema
'route-by-header': { configurationDisabled: boolean } & CommonSchemaFields
'route-by-header': RouteByHeaderSchema
'graphql-rate-limiting-advanced': GraphQLRateLimitingAdvancedSchema
'response-ratelimiting': RateLimitingSchema
'pre-function': CommonSchemaFields & Record<string, any>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Field, ItemsSchema, CommonSchemaFields } from '../../types/plugins/shared'

type FieldForKeyValuePairs = Field & {
newElementButtonLabelClasses?: string
newElementButtonLabel?: string
keyInputPlaceholder?: string
valueInputPlaceholder?: string
}

type ItemsSchemaForKeyValuePairs = Omit<ItemsSchema, 'schema'> & {
schema: {
fields: FieldForKeyValuePairs[]
}
}

export interface RouteByHeaderSchema extends CommonSchemaFields {
'config-rules': {
type: string
showRemoveButton: boolean
newElementButtonLabelClasses: string
itemContainerComponent: string
fieldClasses: string

newElementButtonLabel: string
items: ItemsSchemaForKeyValuePairs
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface Field {
default?: string,
placeholder?: string,
hint?: string,
help?: string,
inputType?: 'text' | 'number'
}

Expand Down

0 comments on commit 2b8578f

Please sign in to comment.