Skip to content

Commit

Permalink
feat(entities-plugin): add streaming custom plugin support
Browse files Browse the repository at this point in the history
Changes include:
1. Remove `disableCustomPlugins` and use `customPlugins` instead
2. The `customPlugins` indicates custom plugin support and which
   type of custom plugins should be created for the control plane
3. `getCustomEditRoute` now provides `type: 'streaming' | 'non-streaming'`
   for custom plugin type indication
4. Text and sandbox change

JIRA: KM-895
  • Loading branch information
nekolab committed Jan 16, 2025
1 parent 73e2f5a commit cfd823b
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 28 deletions.
11 changes: 7 additions & 4 deletions packages/entities/entities-plugins/docs/plugin-select.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ A grid component for selecting Plugins.
- The route for creating a custom plugin.

- `getCustomEditRoute`:
- type: `(plugin: string) => RouteLocationRaw`
- type: `(plugin: string, type: 'streaming' | 'non-streaming') => RouteLocationRaw`
- required: `false`
- default: `undefined`
- A function that returns the route for editing a custom plugin.
Expand Down Expand Up @@ -92,13 +92,16 @@ A grid component for selecting Plugins.

The base konnect or kongManger config.

#### `disableCustomPlugins`
#### `customPlugins`

- type: `boolean`
- type: `false | 'streaming' | 'non-streaming'`
- required: `false`
- default: `false`

Show the custom plugins tab, but disable it.
Control plane custom plugins support level.
When set to false, custom plugins are not supported, the custom plugins tab is grayed out and disabled.
For 'non-streaming' and 'streaming', all existing custom plugins will be shown in the custom plugins tab and can be modified or deleted.
Users can create new non-streaming custom plugins ONLY if 'non-streaming' is set, and new streaming custom plugins ONLY if 'streaming' is set.

#### `hideCustomPlugins`

Expand Down
7 changes: 7 additions & 0 deletions packages/entities/entities-plugins/fixtures/mockData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,13 @@ export const konnectAvailablePlugins = {
],
}

export const konnectCustomPlugins = {
data: [
{ id: '3e26ba5a-9c6b-4e79-9501-0e0bd9ade0ad', name: 'plugin-1', schema: 'schema text', handler: 'handler text' },
{ id: '3e26ba5a-9c6b-4e79-9501-0e0bd9ade0ae', name: 'plugin-2', schema: 'schema text', handler: 'handler text' },
],
}

/**
* Form page data
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<script setup lang="ts">
import { ref } from 'vue'
import type { KonnectPluginSelectConfig, KongManagerPluginSelectConfig } from '../../src'
import type { KonnectPluginSelectConfig, KongManagerPluginSelectConfig, CustomPluginType } from '../../src'
import { PluginSelect } from '../../src'
const controlPlaneId = import.meta.env.VITE_KONNECT_CONTROL_PLANE_ID || ''
Expand All @@ -40,11 +40,12 @@ const konnectConfig = ref<KonnectPluginSelectConfig>({
}),
// custom plugins
createCustomRoute: { name: 'create-custom-plugin' },
getCustomEditRoute: (plugin: string) => ({
getCustomEditRoute: (plugin: string, type: CustomPluginType) => ({
name: 'edit-custom-plugin',
params: {
control_plane_id: controlPlaneId.value,
plugin,
customPluginType: type,
},
}),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
firstShownCustomPlugin,
kongPluginNames,
customPluginNames,
konnectCustomPlugins,
} from '../../fixtures/mockData'
import type { Router } from 'vue-router'
import { createMemoryHistory, createRouter } from 'vue-router'
Expand All @@ -27,11 +28,12 @@ const baseConfigKonnect: KonnectPluginSelectConfig = {
}),
// custom plugins
createCustomRoute: { name: 'create-custom-plugin' },
getCustomEditRoute: (plugin: string) => ({
getCustomEditRoute: (plugin: string, type: 'streaming' | 'non-streaming') => ({
name: 'edit-custom-plugin',
params: {
control_plane_id: 'abc-123-i-love-cats',
plugin,
customPluginType: type,
},
}),
}
Expand Down Expand Up @@ -372,6 +374,17 @@ describe('<PluginSelect />', {
body: params?.mockData ?? konnectAvailablePlugins,
},
).as(params?.alias ?? 'getAvailablePlugins')

cy.intercept(
{
method: 'GET',
url: `${baseConfigKonnect.apiBaseUrl}/v2/control-planes/${baseConfigKonnect.controlPlaneId}/core-entities/custom-plugins`,
},
{
statusCode: 200,
body: konnectCustomPlugins,
},
).as('getStreamingCustomPlugins')
}

beforeEach(() => {
Expand All @@ -390,6 +403,7 @@ describe('<PluginSelect />', {
cy.mount(PluginSelect, {
props: {
config: baseConfigKonnect,
customPlugins: 'non-streaming',
},
router,
})
Expand Down Expand Up @@ -661,6 +675,7 @@ describe('<PluginSelect />', {
cy.mount(PluginSelect, {
props: {
config: baseConfigKonnect,
customPlugins: 'non-streaming',
canCreateCustomPlugin: () => false,
canEditCustomPlugin: () => true,
canDeleteCustomPlugin: () => true,
Expand Down Expand Up @@ -688,6 +703,7 @@ describe('<PluginSelect />', {
cy.mount(PluginSelect, {
props: {
config: baseConfigKonnect,
customPlugins: 'streaming',
canCreateCustomPlugin: () => true,
canEditCustomPlugin: () => false,
canDeleteCustomPlugin: () => false,
Expand Down
47 changes: 36 additions & 11 deletions packages/entities/entities-plugins/src/components/PluginSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
@change="onTabsChange"
>
<template
v-if="disableCustomPlugins"
v-if="customPlugins === false"
#custom-anchor
>
<KTooltip
Expand Down Expand Up @@ -134,6 +134,8 @@ import {
type PluginType,
type DisabledPlugin,
type PluginCardList,
type StreamingCustomPluginSchema,
type CustomPluginSupportLevel,
} from '../types'
import { useAxios, useHelpers, useErrors } from '@kong-ui-public/entities-shared'
import composables from '../composables'
Expand All @@ -152,9 +154,9 @@ const props = defineProps({
return true
},
},
/** If true disable UIs related to custom plugins */
disableCustomPlugins: {
type: Boolean,
/** customPlugins support level */
customPlugins: {
type: [Boolean, String] as PropType<CustomPluginSupportLevel>,
default: false,
},
/** If true don't display UIs related to custom plugins */
Expand Down Expand Up @@ -247,7 +249,8 @@ const filter = ref('')
const isLoading = ref(true)
const hasError = ref(false)
const fetchErrorMessage = ref('')
const availablePlugins = ref<string[]>([])
const availablePlugins = ref<string[]>([]) // all available plugins
const streamingCustomPlugins = ref<StreamingCustomPluginSchema[]>([])
const pluginsList = ref<PluginCardList>({})
const existingEntityPlugins = ref<string[]>([])
Expand Down Expand Up @@ -318,14 +321,14 @@ const tabs = computed(() => {
{
hash: '#custom',
title: t('plugins.select.tabs.custom.title'),
disabled: props.disableCustomPlugins,
disabled: props.customPlugins === false,
}]
: []
})
const activeTab = computed(() => {
let hash = tabs.value.length ? route?.hash || tabs.value[0]?.hash || '' : ''
// If custom plugins are disabled, default to kong tab
if (hash === '#custom' && props.disableCustomPlugins) {
if (hash === '#custom' && props.customPlugins === false) {
hash = '#kong'
}
return hash
Expand Down Expand Up @@ -383,14 +386,20 @@ const buildPluginList = (): PluginCardList => {
// build the actual card list
.reduce((list: PluginCardList, pluginId: string) => {
const pluginName = (pluginMetaData[pluginId] && pluginMetaData[pluginId].name) || pluginId
const plugin = {
const plugin: PluginType = {
...pluginMetaData[pluginId],
id: pluginId,
name: pluginName,
available: availablePlugins.value.includes(pluginId),
disabledMessage: '',
group: pluginMetaData[pluginId]?.group || PluginGroup.CUSTOM_PLUGINS,
} as PluginType
}
if (plugin.group === PluginGroup.CUSTOM_PLUGINS) {
plugin.customPluginType = streamingCustomPlugins.value.find(sp => sp.name === pluginId)
? 'streaming'
: 'non-streaming'
}
if (props.disabledPlugins) {
plugin.disabledMessage = props.disabledPlugins[pluginId]
Expand Down Expand Up @@ -426,6 +435,16 @@ const availablePluginsUrl = computed((): string => {
return url
})
const streamingPluginsUrl = computed<string | null>(() => {
if (props.config.app === 'konnect') {
let url = `${props.config.apiBaseUrl}${endpoints.select[props.config.app].streamingCustomPlugins}`
url = url.replace(/{controlPlaneId}/gi, props.config.controlPlaneId || '')
return url
}
// Kong Manager does not have streaming plugins now
return null
})
const fetchEntityPluginsUrl = computed((): string => {
if (props.config.entityType && props.config.entityId) {
let url = `${props.config.apiBaseUrl}${endpoints.list[props.config.app].forEntity}`
Expand Down Expand Up @@ -487,8 +506,14 @@ onMounted(async () => {
// TODO: endpoints temporarily return different formats
if (props.config.app === 'konnect') {
const { names: available } = data
availablePlugins.value = available || []
const { names: allAvailablePlugins } = data
availablePlugins.value = allAvailablePlugins || []
if (streamingPluginsUrl.value) {
// fetch streaming custom plugins for plugin type partition
const { data: streamingCustomPluginsData } = await axiosInstance.get<{ data: StreamingCustomPluginSchema[] }>(streamingPluginsUrl.value)
// split custom plugins into streaming and non-streaming
streamingCustomPlugins.value = streamingCustomPluginsData.data || []
}
} else if (props.config.app === 'kongManager') {
const { plugins: { available_on_server: aPlugins } } = data
availablePlugins.value = aPlugins ? Object.keys(aPlugins) : []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@
<script setup lang="ts">
import { ref, computed, type PropType } from 'vue'
import {
type CustomPluginType,
type KongManagerPluginSelectConfig,
type KonnectPluginSelectConfig,
} from '../../types'
import composables from '../../composables'
import endpoints from '../../plugins-endpoints'
import { useAxios, useErrors, EntityTypes, EntityDeleteModal } from '@kong-ui-public/entities-shared'
const props = defineProps({
Expand All @@ -71,7 +73,7 @@ const props = defineProps({
},
},
plugin: {
type: Object as PropType<{ name: string, id: string }>,
type: Object as PropType<{ name: string, id: string, customPluginType?: CustomPluginType }>,
required: true,
},
})
Expand All @@ -93,6 +95,20 @@ const isLoading = ref(false)
const errorMessage = ref('')
const isPluginSchemaInUse = ref(false)
const requestUrl = computed(() => {
if (props.config.app === 'konnect') {
const urlPluginPart = props.plugin.customPluginType === 'streaming'
? endpoints.select[props.config.app].streamingCustomPluginItem
: endpoints.select[props.config.app].nonStreamingCustomPluginItem
let url = `${props.config.apiBaseUrl}${urlPluginPart}`
url = url.replace(/{controlPlaneId}/gi, props.config.controlPlaneId || '')
url = url.replace(/{pluginId}/gi, props.plugin.id)
return url
}
// Kong Manager does not have this feature
return null
})
const handleSubmit = async (): Promise<void> => {
isLoading.value = true
errorMessage.value = ''
Expand All @@ -102,8 +118,9 @@ const handleSubmit = async (): Promise<void> => {
}
try {
const url = `${props.config.apiBaseUrl}/v2/control-planes/${props.config.controlPlaneId}/core-entities/plugin-schemas/${props.plugin?.name}`
await axiosInstance.delete(url)
if (requestUrl.value) {
await axiosInstance.delete(requestUrl.value)
}
emit('proceed')
} catch (err: any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import {
type KonnectPluginSelectConfig,
type PluginType,
type PluginCardList,
type CustomPluginType,
} from '../../types'
import composables from '../../composables'
import PluginSelectCard from '../select/PluginSelectCard.vue'
Expand Down Expand Up @@ -165,13 +166,14 @@ const modifiedCustomPlugins = computed((): PluginType[] => {
})
const openDeleteModal = ref(false)
const selectedPlugin = ref<{ name: string, id: string } | null>(null)
const selectedPlugin = ref<{ name: string, id: string, customPluginType?: CustomPluginType } | null>(null)
const handleCustomPluginDelete = (plugin: PluginType): void => {
openDeleteModal.value = true
selectedPlugin.value = {
id: plugin.id,
name: plugin.name,
customPluginType: plugin.customPluginType,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<KDropdownItem
v-if="canDeleteCustomPlugin"
data-testid="edit-plugin-schema"
@click.stop="handleCustomEdit(plugin.name)"
@click.stop="handleCustomEdit(plugin.name, plugin.customPluginType!)"
>
{{ t('actions.edit') }}
</KDropdownItem>
Expand Down Expand Up @@ -104,6 +104,7 @@ import { computed, type PropType } from 'vue'
import { useRouter } from 'vue-router'
import {
PluginGroup,
type CustomPluginType,
type KongManagerPluginSelectConfig,
type KonnectPluginSelectConfig,
type PluginType,
Expand Down Expand Up @@ -187,10 +188,10 @@ const handleCustomDelete = (): void => {
}
}
const handleCustomEdit = (pluginName: string): void => {
const handleCustomEdit = (pluginName: string, type: CustomPluginType): void => {
const konnectConfig = props.config as KonnectPluginSelectConfig
if (props.config.app === 'konnect' && typeof konnectConfig.getCustomEditRoute === 'function' && konnectConfig.getCustomEditRoute) {
router.push(konnectConfig.getCustomEditRoute(pluginName))
router.push(konnectConfig.getCustomEditRoute(pluginName, type))
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/entities/entities-plugins/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@
"custom": {
"title": "Custom Plugins",
"description": "Custom plugins will be available in this control plane only.",
"disabled_tooltip": "Custom Plugins are not available with this Gateway. Create a Hybrid Gateway to leverage Custom Plugins.",
"disabled_tooltip": "Custom Plugins are not available with this Gateway. Create a Hybrid or Dedicated Cloud Gateway to leverage Custom Plugins.",
"empty_title": "No Custom Plugins",
"empty_description": "No custom plugins have been added to this Control Plane.",
"create": {
Expand Down
3 changes: 3 additions & 0 deletions packages/entities/entities-plugins/src/plugins-endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export default {
select: {
konnect: {
availablePlugins: `${konnectBaseApiUrl}/v1/available-plugins`,
streamingCustomPlugins: `${konnectBaseApiUrl}/custom-plugins`,
nonStreamingCustomPluginItem: `${konnectBaseApiUrl}/plugin-schemas/{pluginId}`,
streamingCustomPluginItem: `${konnectBaseApiUrl}/custom-plugins/{pluginId}`,
},
kongManager: {
availablePlugins: `${KMBaseApiUrl}/kong`,
Expand Down
4 changes: 2 additions & 2 deletions packages/entities/entities-plugins/src/types/plugin-form.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { RouteLocationRaw } from 'vue-router'
import type { KonnectBaseFormConfig, KongManagerBaseFormConfig } from '@kong-ui-public/entities-shared'
import type { EntityType } from './plugin'
import type { CustomPluginType, EntityType } from './plugin'
import type { CommonSchemaFields } from './plugins/shared'
import type { ApplicationRegistrationSchema } from './plugins/application-registration-schema'
import type { StatsDSchema } from './plugins/stats-d'
Expand Down Expand Up @@ -45,7 +45,7 @@ export interface KonnectPluginSelectConfig extends BasePluginSelectConfig, Konne
/** Route for creating a custom plugin */
createCustomRoute?: RouteLocationRaw
/** A function that returns the route for editing a custom plugin */
getCustomEditRoute?: (id: string) => RouteLocationRaw
getCustomEditRoute?: (id: string, type: CustomPluginType) => RouteLocationRaw
}

export interface KonnectPluginFormConfig extends BasePluginFormConfig, KonnectBaseFormConfig {}
Expand Down
Loading

0 comments on commit cfd823b

Please sign in to comment.