Skip to content

Commit

Permalink
feat(entities-shared): JSON/YAML forms [KHCP-9967][KHCP-9968][KHCP-99…
Browse files Browse the repository at this point in the history
…86] (#1006)

* feat(entities-shared): create a KSlideout wrapper around JSON/YAML for forms [KHCP-9892]

* refactor(entities-shared): refactor JsonCodeBlock and YamlCodeBlock for reuse across config tables and forms

* fix(entities-shared): fix props and refs for JSON/YAML

* fix(entities-shared): add styles to slideout

* fix(entities-shared): make jsonContent and yamlContent reactive

* fix(entities-shared): fix style to match figma

* fix(entities-shared): hide behind Milestone2 FF

* test(entities-shared): add component tests

* fix(entities-shared): update sandbox

* fix(entities-shared): hide get api endpoint behind Milestone2 FF

* fix(entities-shared): hide behind Milestone2 FF

* fix(entities-shared): hide created_at and updated_at from json/yaml config

* test(entities-shared): fix component tests

* fix(entities-shared): fix jsonOrYaml record

* fix(entities-shared): fix config in EntityBaseForm and check in ConfigCardDisplay

* fix(entities-shared): strip placeholder id from  post request url

* fix(entities-shared): fix incorrect slot

* test(entities-shared): add new component tests for JsonCodeBlock and YamlCodeBlock

* fix(entities-shared): stop slideout close click from propogating

* test(entities-shared): add new component tests for JsonCodeBlock and YamlCodeBlock

* fix(entities-shared): cleanup

* fix(entities-shared): add code comments and types
  • Loading branch information
mptap authored Jan 3, 2024
1 parent b38f94a commit b95a9eb
Show file tree
Hide file tree
Showing 33 changed files with 583 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:edit-id="certificateId"
:error-message="form.errorMessage"
:fetch-url="fetchUrl"
:form-fields="form.fields"
:is-readonly="form.isReadonly"
@cancel="handleClickCancel"
@fetch:error="(err: any) => $emit('error', err)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:edit-id="certificateId"
:error-message="form.errorMessage"
:fetch-url="fetchUrl"
:form-fields="form.fields"
:is-readonly="form.isReadonly"
@cancel="handleClickCancel"
@fetch:error="(err: any) => $emit('error', err)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:edit-id="consumerGroupId"
:error-message="state.errorMessage || fetchError || preValidateErrorMessage"
:fetch-url="fetchUrl"
:form-fields="state.fields"
:is-readonly="state.readonly"
@cancel="cancelHandler"
@fetch:error="fetchErrorHandler($event)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:edit-id="consumerId"
:error-message="state.errorMessage"
:fetch-url="fetchUrl"
:form-fields="state.fields"
:is-readonly="state.readonly"
@cancel="cancelHandler"
@fetch:error="fetchErrorHandler($event)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:edit-id="gatewayServiceId"
:error-message="form.errorMessage"
:fetch-url="fetchUrl"
:form-fields="form.fields"
:is-readonly="form.isReadonly"
@cancel="handleClickCancel"
@fetch:error="(err: any) => $emit('error', err)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:edit-id="keySetId"
:error-message="form.errorMessage"
:fetch-url="fetchUrl"
:form-fields="form.fields"
:is-readonly="form.isReadonly"
@cancel="handleClickCancel"
@fetch:error="(err: any) => $emit('error', err)"
Expand Down
1 change: 1 addition & 0 deletions packages/entities/entities-keys/src/components/KeyForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:edit-id="keyId"
:error-message="form.errorMessage || fetchKeySetsErrorMessage"
:fetch-url="fetchUrl"
:form-fields="form.fields"
:is-readonly="form.isReadonly"
@cancel="handleClickCancel"
@fetch:error="(err: any) => $emit('error', err)"
Expand Down
2 changes: 1 addition & 1 deletion packages/entities/entities-plugins/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"extends": "../../../package.json"
},
"distSizeChecker": {
"errorLimit": "2.0MB"
"errorLimit": "2.5MB"
},
"dependencies": {
"@kong-ui-public/copy-uuid": "workspace:^",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const konnectConfig = ref<KonnectPluginFormConfig>({
// entityId: '6f1ef200-d3d4-4979-9376-726f2216d90c',
backRoute: { name: 'select-plugin' },
cancelRoute: { name: 'home' },
jsonYamlMilestone2Enabled: true,
})
const kongManagerConfig = ref<KongManagerPluginFormConfig>({
Expand Down
96 changes: 93 additions & 3 deletions packages/entities/entities-plugins/src/components/PluginForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
:edit-id="pluginId"
:error-message="form.errorMessage"
:fetch-url="fetchUrl"
:form-fields="form.fields"
:is-readonly="form.isReadonly"
@cancel="handleClickCancel"
@fetch:error="(err: any) => $emit('error', err)"
Expand Down Expand Up @@ -54,9 +55,22 @@
- if isWizardStep is true we don't want any buttons displayed (default EntityBaseForm buttons included)
-->
<div v-if="isWizardStep" />
<div v-else>
<div
v-else
class="plugin-form-actions"
>
<div v-if="config.jsonYamlMilestone2Enabled">
<KButton
appearance="tertiary"
data-testid="form-view-configuration"
@click="toggle()"
>
{{ t('actions.view_configuration') }}
</KButton>
</div>
<KButton
appearance="secondary"
class="form-action-button"
data-testid="form-cancel"
:disabled="form.isReadonly"
type="reset"
Expand All @@ -67,7 +81,7 @@
<KButton
v-if="formType === EntityBaseFormType.Create && config.backRoute"
appearance="secondary"
class="form-back-button"
class="form-action-button"
data-testid="form-back"
:disabled="form.isReadonly"
@click="handleClickBack"
Expand All @@ -86,6 +100,35 @@
</div>
</template>
</EntityBaseForm>
<KSlideout
close-button-alignment="end"
data-testid="form-view-configuration-slideout"
:has-overlay="false"
:is-visible="isToggled"
prevent-close-on-blur
:title="t('view_configuration.title')"
@close="toggle"
>
<div>
{{ t('view_configuration.message') }}
</div>
<KTabs
data-testid="form-view-configuration-slideout-tabs"
:tabs="tabs"
>
<template #json>
<JsonCodeBlock
:config="config"
:fetcher-url="submitUrl"
:json-record="form.fields"
:request-method="props.pluginId ? 'put' : 'post'"
/>
</template>
<template #yaml>
<YamlCodeBlock :yaml-record="form.fields" />
</template>
</KTabs>
</KSlideout>
</div>
</template>

Expand All @@ -111,6 +154,9 @@ import endpoints from '../plugins-endpoints'
import composables from '../composables'
import { ArrayStringFieldSchema } from '../composables/plugin-schemas/ArrayStringFieldSchema'
import PluginEntityForm from './PluginEntityForm.vue'
import type { Tab } from '@kong/kongponents'
import JsonCodeBlock from '../../../entities-shared/src/components/common/JsonCodeBlock.vue'
import YamlCodeBlock from '../../../entities-shared/src/components/common/YamlCodeBlock.vue'
const emit = defineEmits<{
(e: 'error:fetch-schema', error: AxiosError): void,
Expand Down Expand Up @@ -199,6 +245,7 @@ const { axiosInstance } = useAxios({
headers: props.config.requestHeaders,
})
const isToggled = ref(false)
const formType = computed((): EntityBaseFormType => props.pluginId ? EntityBaseFormType.Edit : EntityBaseFormType.Create)
const schema = ref<Record<string, any> | null>(null)
const treatAsCredential = computed((): boolean => !!(props.credential && props.config.entityId))
Expand All @@ -221,6 +268,17 @@ const form = reactive<PluginFormState>({
errorMessage: '',
})
const tabs = ref<Tab[]>([
{
title: t('view_configuration.yaml'),
hash: '#yaml',
},
{
title: t('view_configuration.json'),
hash: '#json',
},
])
const fetchUrl = computed((): string => {
if (treatAsCredential.value) { // credential
let submitEndpoint = endpoints.form[props.config.app].credential[formType.value]
Expand All @@ -241,6 +299,10 @@ const fetchUrl = computed((): string => {
}
})
const toggle = (): void => {
isToggled.value = !isToggled.value
}
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 Expand Up @@ -1035,8 +1097,36 @@ onBeforeMount(async () => {
.kong-ui-entities-plugin-form-container {
width: 100%;
.form-back-button {
.form-action-button {
margin-left: $kui-space-60;
}
.plugin-form-actions {
display: flex;
}
& :deep(.k-slideout-title) {
color: $kui-color-text !important;
font-size: $kui-font-size-70 !important;
font-weight: $kui-font-weight-bold !important;
line-height: $kui-line-height-60 !important;
margin-bottom: $kui-space-60 !important;
}
& :deep(.k-card.content-card) {
padding: $kui-space-0 $kui-space-60 !important;
}
& :deep(.tab-item > div.tab-link.has-panels) {
color: $kui-color-text-neutral !important;
font-size: $kui-font-size-30 !important;
font-weight: $kui-font-weight-bold !important;
line-height: $kui-line-height-40 !important;
}
& :deep(.tab-item.active > div.tab-link.has-panels) {
color: $kui-color-text !important;
font-weight: $kui-font-weight-semibold !important;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<template #action-buttons>
<div>
<KButton
appearance="outline"
appearance="tertiary"
class="cancel-button"
data-testid="delete-custom-plugin-form-cancel"
@click="$emit('closed')"
Expand Down
7 changes: 7 additions & 0 deletions packages/entities/entities-plugins/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"actions": {
"back": "Back",
"cancel": "Cancel",
"view_configuration": "View Configuration",
"create": "New Plugin",
"create_custom": "Create",
"copy_id": "Copy ID",
Expand All @@ -16,6 +17,12 @@
"go_to_plugins": "Go to Plugins",
"save": "Save"
},
"view_configuration": {
"title": "Configuration",
"message": "Configuring your API has never been easier. Use YAML for human-friendly simplicity or JSON for machine-readability. Streamline your settings effortlessly.",
"yaml": "YAML",
"json": "JSON"
},
"delete": {
"title": "Delete a Plugin",
"custom_title": "Delete {name}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
:edit-id="routeId"
:error-message="form.errorMessage || fetchServicesErrorMessage"
:fetch-url="fetchUrl"
:form-fields="form.fields"
:is-readonly="form.isReadonly"
@cancel="cancelHandler"
@fetch:error="fetchErrorHandler"
Expand Down
10 changes: 10 additions & 0 deletions packages/entities/entities-shared/docs/config-card-display.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ List types of element in the item object.

The base record configuration when format is either JSON or YAML.

#### `fetcherUrl`

- type: `String`
- required: `false`
- default: `''`

Fetcher url for the entity with the filled-in controlPlaneId, workspace, and entity id.

ex. `https://cloud.konghq.com/us/gateway-manager/91e192e0-5981-4662-a37d-7b24272c9da3/routes/0af86198-9822-46e0-9028-47b173caf4aa`

### Usage example

Please refer to the [sandbox](../sandbox/pages/ConfigCardDisplayPage.vue).
Expand Down
7 changes: 7 additions & 0 deletions packages/entities/entities-shared/docs/entity-base-form.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ A Boolean to indicate if the form can be submitted. Used to track form validatio

If form submission fails, this is the error message to display.

#### `formFields`

- type: `Object as PropType<Record<string, any>>`
- required: `true`

A record to indicate the form fields present in a form. Used to populate the Configuration JSON/YAML code blocks.

### Events

#### loading
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

<h2>Format: JSON</h2>
<ConfigCardDisplay
fetcher-url="https://cloud.konghq.com/us/gateway-manager/91e192e0-5981-4662-a37d-7b24272c9da3/routes/0af86198-9822-46e0-9028-47b173caf4aa"
:config="konnectConfig"
:fetcher-url="`${konnectConfig?.apiBaseUrl}${konnectFetchUrl}`"
format="json"
:record="record"
/>
Expand All @@ -23,8 +24,24 @@
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { ConfigCardDisplay } from '../../src'
import type { KonnectBaseEntityConfig } from '../../src'
const controlPlaneId = import.meta.env.VITE_KONNECT_CONTROL_PLANE_ID || ''
const entityId = 'ce83dd74-6455-40a9-b944-0f393c7ee22c'
const konnectFetchUrl = ref(`/api/runtime_groups/${controlPlaneId}/services/${entityId}`)
const konnectConfig = ref<KonnectBaseEntityConfig>({
app: 'konnect',
apiBaseUrl: '/us/kong-api/konnect-api', // `/{geo}/kong-api`, with leading slash and no trailing slash; Consuming app would pass in something like `https://us.api.konghq.com`
// Set the root `.env.development.local` variable to a control plane your PAT can access
controlPlaneId,
entityId,
jsonYamlMilestone2Enabled: true,
})
const item = {
basic:
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
:can-submit="canSubmit"
:config="konnectConfig"
:error-message="form.errorMessage"
:fetch-url="konnectFetchUrl"
:form-fields="form.fields"
:is-readonly="form.isReadonly"
@cancel="handleCancel"
@submit="handleSave"
Expand Down Expand Up @@ -46,13 +48,15 @@ import type { KonnectBaseFormConfig } from '../../src'
import { EntityBaseForm, EntityFormSection } from '../../src'
const controlPlaneId = import.meta.env.VITE_KONNECT_CONTROL_PLANE_ID || ''
const konnectFetchUrl = ref(`/api/runtime_groups/${controlPlaneId}/services`)
const konnectConfig = ref<KonnectBaseFormConfig>({
app: 'konnect',
apiBaseUrl: '/us/kong-api/konnect-api', // `/{geo}/kong-api`, with leading slash and no trailing slash; Consuming app would pass in something like `https://us.api.konghq.com`
// Set the root `.env.development.local` variable to a control plane your PAT can access
controlPlaneId,
cancelRoute: { name: '/' },
jsonYamlMilestone2Enabled: true,
})
const canSubmit = computed((): boolean => !!form.fields.name)
Expand Down
Loading

0 comments on commit b95a9eb

Please sign in to comment.