Admin integration gateway UX improvements
- add admin integration gateway UX improvements - add purge requests button to admin profiler - added purge profiler hits
This commit is contained in:
committed by
Peter Grlica
parent
921d4988c7
commit
b250b9329f
@@ -11,17 +11,15 @@
|
||||
@hidden="onHidden"
|
||||
>
|
||||
<div
|
||||
v-if="filter"
|
||||
v-if="internalFilter"
|
||||
class="card-body"
|
||||
>
|
||||
<c-filter-params
|
||||
:filter="filter"
|
||||
@update="onUpdate"
|
||||
:filter="internalFilter"
|
||||
/>
|
||||
<b-form-checkbox
|
||||
v-model="filter.enabled"
|
||||
v-model="internalFilter.enabled"
|
||||
data-test-id="checkbox-filter-enable"
|
||||
@change="onUpdate"
|
||||
>
|
||||
{{ $t('filters.enabled') }}
|
||||
</b-form-checkbox>
|
||||
@@ -53,25 +51,65 @@ export default {
|
||||
|
||||
data () {
|
||||
return {
|
||||
updated: false,
|
||||
|
||||
filteredFields: [],
|
||||
internalFilter: undefined,
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
visible: {
|
||||
handler (visible) {
|
||||
if (visible) {
|
||||
// Convert to FE structure
|
||||
this.internalFilter = {
|
||||
...this.filter,
|
||||
params: this.filter.params.map(p => {
|
||||
if (this.filter.ref === 'response') {
|
||||
let value = p.value || {}
|
||||
|
||||
if (p.type === 'header') {
|
||||
value = Object.entries(value).map(([name, v = []]) => {
|
||||
return { name, expr: v.join('') }
|
||||
})
|
||||
} else if (p.type === 'input') {
|
||||
value = { type: 'Any', expr: '', ...value }
|
||||
}
|
||||
|
||||
this.$set(p, 'value', value)
|
||||
}
|
||||
|
||||
return p
|
||||
}),
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSave () {
|
||||
this.$emit('submit', { ...this.filter, updated: this.updated })
|
||||
this.updated = false
|
||||
// Convert to BE structure
|
||||
const filter = {
|
||||
...this.internalFilter,
|
||||
params: this.internalFilter.params.map(p => {
|
||||
if (this.filter.ref === 'response') {
|
||||
if (p.type === 'header') {
|
||||
p.value = p.value.reduce((obj, { name, expr = '' }) => {
|
||||
return { ...obj, [name]: [expr] }
|
||||
}, {})
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}),
|
||||
}
|
||||
|
||||
this.$emit('submit', { ...filter, updated: true })
|
||||
this.internalFilter = undefined
|
||||
},
|
||||
|
||||
onHidden () {
|
||||
this.$emit('reset')
|
||||
},
|
||||
|
||||
onUpdate () {
|
||||
this.updated = true
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
>
|
||||
<template slot="label">
|
||||
{{ $t(`filters.labels.${param.label}`) }}
|
||||
|
||||
<template v-if="param.label === 'expr'">
|
||||
<a
|
||||
v-if="param.label === 'expr'"
|
||||
@@ -24,12 +25,13 @@
|
||||
</a>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- TODO create multi field component-->
|
||||
<b-form-checkbox
|
||||
v-if="param.type === 'bool'"
|
||||
v-model="param.value"
|
||||
@change="onUpdate"
|
||||
/>
|
||||
|
||||
<vue-select
|
||||
v-else-if="param.label === 'workflow'"
|
||||
v-model="param.value"
|
||||
@@ -37,13 +39,12 @@
|
||||
:reduce="wf => wf.workflowID"
|
||||
:placeholder="$t('filters.placeholders.workflow')"
|
||||
class="bg-white"
|
||||
@input="onUpdate"
|
||||
/>
|
||||
|
||||
<b-form-select
|
||||
v-else-if="param.label === 'status'"
|
||||
v-model="param.value"
|
||||
:options="httpStatusOptions"
|
||||
@change="onUpdate"
|
||||
>
|
||||
<template #first>
|
||||
<b-form-select-option
|
||||
@@ -53,12 +54,70 @@
|
||||
</b-form-select-option>
|
||||
</template>
|
||||
</b-form-select>
|
||||
|
||||
<template v-else-if="filter.ref === 'response'">
|
||||
<template v-if="param.type === 'input'">
|
||||
<b-form-select
|
||||
v-model="param.value.type"
|
||||
:options="inputTypeOptions"
|
||||
class="mb-2"
|
||||
/>
|
||||
|
||||
<b-input-group>
|
||||
<b-input-group-prepend>
|
||||
<b-button variant="dark">
|
||||
ƒ
|
||||
</b-button>
|
||||
</b-input-group-prepend>
|
||||
<b-form-input
|
||||
v-model="param.value.expr"
|
||||
:placeholder="$t('filters.help.expression.example')"
|
||||
/>
|
||||
</b-input-group>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<b-input-group
|
||||
v-for="(header, hIndex) in param.value"
|
||||
:key="`header-${hIndex}`"
|
||||
class="mb-2"
|
||||
>
|
||||
<b-form-input
|
||||
v-model="header.name"
|
||||
:placeholder="$t('filters.labels.name')"
|
||||
/>
|
||||
<b-form-input
|
||||
v-model="header.expr"
|
||||
:placeholder="$t('filters.labels.value')"
|
||||
/>
|
||||
|
||||
<b-input-group-append>
|
||||
<b-button
|
||||
variant="danger"
|
||||
@click="param.value.splice(hIndex, 1)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['far', 'trash-alt']"
|
||||
/>
|
||||
</b-button>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
|
||||
<b-button
|
||||
variant="link"
|
||||
class="text-decoration-none px-0"
|
||||
@click="param.value.push({ name: '', expr: '' })"
|
||||
>
|
||||
+ {{ $t('filters.addHeader') }}
|
||||
</b-button>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<b-form-textarea
|
||||
v-if="param.label === 'jsfunc'"
|
||||
v-model="param.value"
|
||||
max-rows="6"
|
||||
@change="onUpdate"
|
||||
/>
|
||||
<b-input-group v-else>
|
||||
<b-input-group-prepend
|
||||
@@ -72,12 +131,10 @@
|
||||
v-if="param.label === 'expr'"
|
||||
v-model="param.value"
|
||||
:placeholder="$t('filters.help.expression.example')"
|
||||
@change="onUpdate"
|
||||
/>
|
||||
<b-form-input
|
||||
v-else
|
||||
v-model="param.value"
|
||||
@change="onUpdate"
|
||||
/>
|
||||
</b-input-group>
|
||||
</template>
|
||||
@@ -115,6 +172,18 @@ export default {
|
||||
{ value: 307, text: this.$t('filters.httpStatus.307') },
|
||||
{ value: 308, text: this.$t('filters.httpStatus.308') },
|
||||
],
|
||||
|
||||
inputTypeOptions: [
|
||||
'String',
|
||||
'Any',
|
||||
'Array',
|
||||
'KV',
|
||||
'DateTime',
|
||||
'Float',
|
||||
'Integer',
|
||||
'Reader',
|
||||
'Vars',
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
@@ -136,11 +205,5 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onUpdate () {
|
||||
this.$emit('update')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<b-card
|
||||
data-test-id="card-filter-list"
|
||||
class="apigw shadow-sm mt-3"
|
||||
header-bg-variant="white"
|
||||
footer-bg-variant="white"
|
||||
body-class="p-0"
|
||||
class="apigw shadow-sm mt-3"
|
||||
>
|
||||
<c-filter-modal
|
||||
:visible="!!selectedFilter"
|
||||
@@ -12,55 +13,53 @@
|
||||
@reset="onReset"
|
||||
/>
|
||||
|
||||
<b-form
|
||||
@submit.prevent="$emit('submit', route)"
|
||||
<b-tabs
|
||||
data-test-id="filter-steps"
|
||||
active-nav-item-class="active-tab bg-white"
|
||||
class="border-0"
|
||||
content-class="border-bottom"
|
||||
>
|
||||
<b-tabs
|
||||
data-test-id="filter-steps"
|
||||
active-nav-item-class="active-tab bg-white"
|
||||
class="border-0 font-weight-bold"
|
||||
content-class="border-bottom"
|
||||
<b-tab
|
||||
v-for="(step, index) in steps"
|
||||
:key="index"
|
||||
class="border-0"
|
||||
:title="$t(`filters.step_title.${step}`)"
|
||||
@click="onActivateTab(index)"
|
||||
>
|
||||
<b-tab
|
||||
v-for="(step, index) in steps"
|
||||
:key="index"
|
||||
class="border-0"
|
||||
:title="$t(`filters.step_title.${step}`)"
|
||||
@click="onActivateTab(index)"
|
||||
>
|
||||
<b-row class="d-flex flex-column w-100 m-0">
|
||||
<c-filters-dropdown
|
||||
class="px-1 py-2"
|
||||
:available-filters="getAvailableFiltersByStep"
|
||||
:filters="getSelectedFiltersByStep"
|
||||
@addFilter="onAddFilter"
|
||||
/>
|
||||
<c-filters-table
|
||||
:filters="getSelectedFiltersByStep"
|
||||
:step="index"
|
||||
:fetching="fetching"
|
||||
@filterSelect="onFilterSelect"
|
||||
@removeFilter="onRemoveFilter"
|
||||
@sortFilters="onSortFilters"
|
||||
/>
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
|
||||
<c-filters-table
|
||||
ref="filterTable"
|
||||
:filters="getSelectedFiltersByStep"
|
||||
:selected-row="step.selectedRow"
|
||||
:step="index"
|
||||
@filterSelect="onFilterSelect"
|
||||
@removeFilter="onRemoveFilter"
|
||||
@sortFilters="onSortFilters"
|
||||
/>
|
||||
</b-row>
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
</b-form>
|
||||
<template #header>
|
||||
<h3 class="m-0">
|
||||
{{ $t('filters.title') }}
|
||||
</h3>
|
||||
</template>
|
||||
<c-submit-button
|
||||
class="float-right mt-3"
|
||||
:processing="processing"
|
||||
:success="success"
|
||||
:disabled="disabled"
|
||||
@submit="$emit('submit')"
|
||||
/>
|
||||
|
||||
<template #footer>
|
||||
<div
|
||||
class="d-flex justify-content-between"
|
||||
>
|
||||
<c-filters-dropdown
|
||||
:available-filters="getAvailableFiltersByStep"
|
||||
:filters="getSelectedFiltersByStep"
|
||||
@addFilter="onAddFilter"
|
||||
/>
|
||||
<c-submit-button
|
||||
:processing="processing"
|
||||
:success="success"
|
||||
:disabled="disabled"
|
||||
@submit="$emit('submit')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</b-card>
|
||||
</template>
|
||||
<script>
|
||||
@@ -83,6 +82,10 @@ export default {
|
||||
CFiltersDropdown,
|
||||
},
|
||||
props: {
|
||||
fetching: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
processing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-table-simple
|
||||
class="filter-table"
|
||||
hover
|
||||
class="mb-0"
|
||||
>
|
||||
<b-thead>
|
||||
<b-thead head-variant="light">
|
||||
<b-tr>
|
||||
<b-th />
|
||||
<b-th>{{ $t('filters.list.filters') }}</b-th>
|
||||
<b-th>{{ $t('filters.list.status') }}</b-th>
|
||||
<b-th />
|
||||
@@ -13,51 +14,77 @@
|
||||
</b-thead>
|
||||
|
||||
<draggable
|
||||
v-if="!fetching"
|
||||
v-model="sortableFilters"
|
||||
:options="{ handle: '.handle' }"
|
||||
tag="b-tbody"
|
||||
>
|
||||
<b-tr
|
||||
v-for="(filter, index) in sortableFilters"
|
||||
:key="index"
|
||||
class="pointer"
|
||||
:class="[selectedRow===index ? 'row-selected' : 'row-not-selected']"
|
||||
@click.stop="onRowClick(filter,index)"
|
||||
>
|
||||
<b-td class="align-baseline">
|
||||
<td
|
||||
class="handle align-middle grab"
|
||||
style="width: 1%"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'bars']"
|
||||
class="text-light"
|
||||
/>
|
||||
</td>
|
||||
<b-td class="align-middle">
|
||||
{{ filter.label }}
|
||||
</b-td>
|
||||
<b-td class="align-baseline">
|
||||
<b-td class="align-middle">
|
||||
{{ $t(`filters.${filter.enabled ? 'enabled' : 'disabled'}`) }}
|
||||
</b-td>
|
||||
<b-td class="text-right align-baseline">
|
||||
<b-td class="text-right align-middle">
|
||||
<b-button
|
||||
variant="danger"
|
||||
class="my-1"
|
||||
size="sm"
|
||||
@click.stop="onRemoveFilter(filter)"
|
||||
variant="link"
|
||||
@click.stop="onRowClick(filter, index)"
|
||||
>
|
||||
{{ $t('filters.list.remove') }}
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'pen']"
|
||||
/>
|
||||
</b-button>
|
||||
<c-input-confirm
|
||||
class="ml-1"
|
||||
@confirmed="onRemoveFilter(filter)"
|
||||
@click.stop
|
||||
/>
|
||||
</b-td>
|
||||
</b-tr>
|
||||
</draggable>
|
||||
</b-table-simple>
|
||||
<h6
|
||||
v-if="!sortableFilters.length"
|
||||
data-test-id="no-filters"
|
||||
class="d-flex justify-content-center align-items-center mb-3"
|
||||
|
||||
<div
|
||||
class="d-flex flex-column align-items-center justify-content-center h-100 overflow-hidden"
|
||||
>
|
||||
{{ $t('filters.list.noFilters') }}
|
||||
</h6>
|
||||
<b-spinner
|
||||
v-if="fetching"
|
||||
class="my-4"
|
||||
/>
|
||||
|
||||
<p
|
||||
v-else-if="!sortableFilters.length"
|
||||
data-test-id="no-filters"
|
||||
class="my-4"
|
||||
>
|
||||
{{ $t('filters.list.noFilters') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
draggable,
|
||||
},
|
||||
|
||||
props: {
|
||||
filters: {
|
||||
type: Array,
|
||||
@@ -67,6 +94,10 @@ export default {
|
||||
type: Number,
|
||||
default: () => 0,
|
||||
},
|
||||
fetching: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
|
||||
data () {
|
||||
@@ -75,6 +106,7 @@ export default {
|
||||
selectedFilter: {},
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
sortableFilters: {
|
||||
get () {
|
||||
@@ -86,6 +118,7 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onAddFilter (filter) {
|
||||
if (!this.filters.find(f => f.ref === filter.ref)) {
|
||||
@@ -109,12 +142,3 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.filter-table .row-selected{
|
||||
background: #F3F3F5;
|
||||
}
|
||||
.cursor-default{
|
||||
cursor: default;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
>
|
||||
<label
|
||||
label-for="endpoint"
|
||||
class="mb-0"
|
||||
>
|
||||
{{ $t('endpoint') }}
|
||||
</label>
|
||||
@@ -68,6 +69,16 @@
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group
|
||||
v-if="route.meta"
|
||||
:label="$t('description')"
|
||||
label-cols="2"
|
||||
>
|
||||
<b-form-textarea
|
||||
v-model="route.meta.description"
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group
|
||||
label-cols="2"
|
||||
:class="{ 'mb-0': !route.routeID }"
|
||||
|
||||
@@ -1,53 +1,18 @@
|
||||
<template>
|
||||
<b-container
|
||||
class="py-3"
|
||||
<b-card
|
||||
class="shadow-sm"
|
||||
body-class="p-0"
|
||||
header-bg-variant="white"
|
||||
footer-bg-variant="white"
|
||||
>
|
||||
<c-content-header
|
||||
:title="$t('title')"
|
||||
<template
|
||||
#header
|
||||
>
|
||||
<span
|
||||
class="text-nowrap"
|
||||
>
|
||||
<b-button
|
||||
v-if="canCreate"
|
||||
data-test-id="button-add"
|
||||
variant="primary"
|
||||
:to="{ name: 'system.apigw.new' }"
|
||||
>
|
||||
{{ $t('new') }}
|
||||
</b-button>
|
||||
<b-button
|
||||
v-if="$Settings.get('apigw.profilerEnabled', false)"
|
||||
data-test-id="button-profiler"
|
||||
class="ml-2"
|
||||
variant="info"
|
||||
:to="{ name: 'system.apigw.profiler' }"
|
||||
>
|
||||
{{ $t('profiler') }}
|
||||
</b-button>
|
||||
<c-permissions-button
|
||||
v-if="canGrant"
|
||||
data-test-id="button-permissions"
|
||||
resource="corteza::system:apigw-route/*"
|
||||
button-variant="light"
|
||||
class="ml-2"
|
||||
>
|
||||
<font-awesome-icon :icon="['fas', 'lock']" />
|
||||
{{ $t('permissions') }}
|
||||
</c-permissions-button>
|
||||
</span>
|
||||
<b-dropdown
|
||||
v-if="false"
|
||||
variant="link"
|
||||
right
|
||||
menu-class="shadow-sm"
|
||||
:text="$t('export')"
|
||||
>
|
||||
<b-dropdown-item-button variant="link">
|
||||
{{ $t('yaml') }}
|
||||
</b-dropdown-item-button>
|
||||
</b-dropdown>
|
||||
</c-content-header>
|
||||
<h3 class="m-0">
|
||||
{{ $t('title') }}
|
||||
</h3>
|
||||
</template>
|
||||
|
||||
<c-resource-list
|
||||
:primary-key="primaryKey"
|
||||
:filter="filter"
|
||||
@@ -66,9 +31,52 @@
|
||||
prevPagination: $t('admin:general.pagination.prev'),
|
||||
nextPagination: $t('admin:general.pagination.next'),
|
||||
}"
|
||||
class="h-100"
|
||||
@search="filterList"
|
||||
>
|
||||
<template #header>
|
||||
<b-button
|
||||
v-if="canCreate"
|
||||
data-test-id="button-add"
|
||||
variant="primary"
|
||||
:to="{ name: 'system.apigw.new' }"
|
||||
>
|
||||
{{ $t('new') }}
|
||||
</b-button>
|
||||
|
||||
<b-button
|
||||
v-if="$Settings.get('apigw.profiler.enabled', false)"
|
||||
data-test-id="button-profiler"
|
||||
class="ml-1"
|
||||
variant="info"
|
||||
:to="{ name: 'system.apigw.profiler' }"
|
||||
>
|
||||
{{ $t('profiler') }}
|
||||
</b-button>
|
||||
|
||||
<c-permissions-button
|
||||
v-if="canGrant"
|
||||
data-test-id="button-permissions"
|
||||
resource="corteza::system:apigw-route/*"
|
||||
button-variant="light"
|
||||
class="ml-1"
|
||||
>
|
||||
<font-awesome-icon :icon="['fas', 'lock']" />
|
||||
{{ $t('permissions') }}
|
||||
</c-permissions-button>
|
||||
|
||||
<b-dropdown
|
||||
v-if="false"
|
||||
variant="link"
|
||||
right
|
||||
menu-class="shadow-sm"
|
||||
:text="$t('export')"
|
||||
>
|
||||
<b-dropdown-item-button variant="link">
|
||||
{{ $t('yaml') }}
|
||||
</b-dropdown-item-button>
|
||||
</b-dropdown>
|
||||
|
||||
<c-resource-list-status-filter
|
||||
v-model="filter.deleted"
|
||||
data-test-id="filter-deleted-routes"
|
||||
@@ -76,6 +84,7 @@
|
||||
:excluded-label="$t('filterForm.excluded.label')"
|
||||
:inclusive-label="$t('filterForm.inclusive.label')"
|
||||
:exclusive-label="$t('filterForm.exclusive.label')"
|
||||
class="mt-3"
|
||||
@change="filterList"
|
||||
/>
|
||||
</template>
|
||||
@@ -92,13 +101,13 @@
|
||||
</b-button>
|
||||
</template>
|
||||
</c-resource-list>
|
||||
</b-container>
|
||||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as moment from 'moment'
|
||||
import listHelpers from 'corteza-webapp-admin/src/mixins/listHelpers'
|
||||
import { mapGetters } from 'vuex'
|
||||
import listHelpers from 'corteza-webapp-admin/src/mixins/listHelpers'
|
||||
import moment from 'moment'
|
||||
import { components } from '@cortezaproject/corteza-vue'
|
||||
const { CResourceList } = components
|
||||
|
||||
@@ -112,14 +121,12 @@ export default {
|
||||
],
|
||||
|
||||
i18nOptions: {
|
||||
namespaces: [ 'system.apigw' ],
|
||||
namespaces: 'system.apigw',
|
||||
keyPrefix: 'list',
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
id: 'routes',
|
||||
|
||||
primaryKey: 'routeID',
|
||||
editRoute: 'system.apigw.edit',
|
||||
|
||||
124
client/web/admin/src/components/Apigw/CSettingsEditor.vue
Normal file
124
client/web/admin/src/components/Apigw/CSettingsEditor.vue
Normal file
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<b-card
|
||||
class="shadow-sm"
|
||||
header-bg-variant="white"
|
||||
footer-bg-variant="white"
|
||||
>
|
||||
<template #header>
|
||||
<h3 class="m-0">
|
||||
{{ $t('title') }}
|
||||
</h3>
|
||||
</template>
|
||||
|
||||
<b-form-row
|
||||
@submit.prevent="$emit('submit', settings)"
|
||||
>
|
||||
<b-col
|
||||
cols="12"
|
||||
md="6"
|
||||
class="mb-3 mb-md-0"
|
||||
>
|
||||
<b-form-group
|
||||
:label="$t('profiler.label')"
|
||||
label-class="text-primary"
|
||||
class="mb-0"
|
||||
>
|
||||
<b-form-radio-group
|
||||
v-model="profilerSetting"
|
||||
:options="profilerOptions"
|
||||
button-variant="outline-primary"
|
||||
size="sm"
|
||||
buttons
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
|
||||
<b-col
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<b-form-group
|
||||
:label="$t('proxy.label')"
|
||||
label-class="text-primary"
|
||||
class="mb-0"
|
||||
>
|
||||
<b-form-checkbox
|
||||
v-model="settings['apigw.proxy.follow-redirects']"
|
||||
>
|
||||
{{ $t('proxy.follow') }}
|
||||
</b-form-checkbox>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
</b-form-row>
|
||||
|
||||
<template #footer>
|
||||
<c-submit-button
|
||||
class="float-right"
|
||||
:processing="processing"
|
||||
:success="success"
|
||||
@submit="$emit('submit', settings)"
|
||||
/>
|
||||
</template>
|
||||
</b-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CSubmitButton from 'corteza-webapp-admin/src/components/CSubmitButton'
|
||||
|
||||
export default {
|
||||
name: 'CSettingsEditor',
|
||||
|
||||
i18nOptions: {
|
||||
namespaces: 'system.apigw',
|
||||
keyPrefix: 'settings',
|
||||
},
|
||||
|
||||
components: {
|
||||
CSubmitButton,
|
||||
},
|
||||
|
||||
props: {
|
||||
settings: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
|
||||
processing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
|
||||
success: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
profilerOptions: [
|
||||
{ value: 'disabled', text: 'Disabled' },
|
||||
{ value: 'filter', text: 'Enabled as filter' },
|
||||
{ value: 'global', text: 'Enabled for all routes' },
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
profilerSetting: {
|
||||
get () {
|
||||
if (this.settings['apigw.profiler.enabled']) {
|
||||
return this.settings['apigw.profiler.global'] ? 'global' : 'filter'
|
||||
}
|
||||
|
||||
return 'disabled'
|
||||
},
|
||||
|
||||
set (setting) {
|
||||
this.settings['apigw.profiler.enabled'] = ['filter', 'global'].includes(setting)
|
||||
this.settings['apigw.profiler.global'] = setting === 'global'
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -2,7 +2,7 @@
|
||||
<b-card
|
||||
data-test-id="card-requests"
|
||||
no-body
|
||||
class="shadow-sm mb-3"
|
||||
class="shadow-sm"
|
||||
footer-class="d-flex align-items-center justify-content-center"
|
||||
footer-bg-variant="white"
|
||||
header-bg-variant="white"
|
||||
@@ -13,22 +13,33 @@
|
||||
</h3>
|
||||
|
||||
<div
|
||||
class="d-flex align-items-center justify-content-end"
|
||||
class="d-flex align-items-center justify-content-between"
|
||||
>
|
||||
<span
|
||||
:class="{ 'loading': loading }"
|
||||
<div>
|
||||
<b-button
|
||||
data-test-id="button-refresh"
|
||||
variant="primary"
|
||||
:disabled="loading"
|
||||
@click="loadItems()"
|
||||
>
|
||||
{{ $t('general:label.refresh') }}
|
||||
</b-button>
|
||||
<span
|
||||
class="ml-1"
|
||||
:class="{ 'loading': loading }"
|
||||
>
|
||||
{{ autoRefreshLabel }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<c-input-confirm
|
||||
:disabled="!items.length"
|
||||
:borderless="false"
|
||||
variant="danger"
|
||||
@confirmed="purgeRequests"
|
||||
>
|
||||
{{ autoRefreshLabel }}
|
||||
</span>
|
||||
<b-button
|
||||
data-test-id="button-refresh"
|
||||
variant="primary"
|
||||
:disabled="loading"
|
||||
class="ml-2"
|
||||
@click="loadItems()"
|
||||
>
|
||||
{{ $t('general:label.refresh') }}
|
||||
</b-button>
|
||||
{{ $t('purge.this') }}
|
||||
</c-input-confirm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -66,13 +77,13 @@
|
||||
<template #cell(actions)="row">
|
||||
<b-button
|
||||
data-test-id="button-edit-route"
|
||||
size="sm"
|
||||
variant="link"
|
||||
class="p-0"
|
||||
:to="{ name: 'system.apigw.profiler.hit.list', params: { hitID: row.item.hitID } }"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'pen']"
|
||||
:icon="['fas', 'info-circle']"
|
||||
class="text-primary"
|
||||
/>
|
||||
</b-button>
|
||||
</template>
|
||||
@@ -141,12 +152,12 @@ export default {
|
||||
{
|
||||
key: 'time_start',
|
||||
sortable: true,
|
||||
formatter: v => fmt.fullDateTime(v),
|
||||
formatter: v => v ? fmt.fullDateTime(v) : '',
|
||||
},
|
||||
{
|
||||
key: 'time_finish',
|
||||
sortable: true,
|
||||
formatter: v => fmt.fullDateTime(v),
|
||||
formatter: v => v ? fmt.fullDateTime(v) : '',
|
||||
},
|
||||
{
|
||||
key: 'http_method',
|
||||
@@ -161,12 +172,13 @@ export default {
|
||||
{
|
||||
key: 'content_length',
|
||||
sortable: true,
|
||||
formatter: v => `${v || 0} bytes`,
|
||||
class: 'text-right',
|
||||
},
|
||||
{
|
||||
key: 'time_duration',
|
||||
sortable: true,
|
||||
formatter: v => `${v.toFixed(2)} ms`,
|
||||
formatter: v => v ? `${v.toFixed(2)} ms` : '',
|
||||
class: 'text-right',
|
||||
},
|
||||
{
|
||||
@@ -231,7 +243,9 @@ export default {
|
||||
this.totalItems = append ? this.totalItems + set.length : this.totalItems
|
||||
|
||||
return { filter, set }
|
||||
}).finally(() => {
|
||||
})
|
||||
.catch(this.toastErrorHandler(this.$t('notification:gateway.profiler.purge.fetch')))
|
||||
.finally(() => {
|
||||
if (!append) {
|
||||
this.filter.before = oldBeforeID
|
||||
}
|
||||
@@ -239,6 +253,16 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
purgeRequests () {
|
||||
const { routeID } = this.filter
|
||||
this.$SystemAPI.apigwProfilerPurge({ routeID })
|
||||
.then(() => {
|
||||
this.loadItems()
|
||||
this.toastSuccess(this.$t('notification:gateway.profiler.purge.success'))
|
||||
})
|
||||
.catch(this.toastErrorHandler(this.$t('notification:gateway.profiler.purge.error')))
|
||||
},
|
||||
|
||||
resetItems (sorting = this.sorting) {
|
||||
this.sorting = sorting
|
||||
this.filter.before = ''
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<template>
|
||||
<b-card
|
||||
data-test-id="card-edit-authentication"
|
||||
header-bg-variant="white"
|
||||
footer-bg-variant="white"
|
||||
class="shadow-sm"
|
||||
|
||||
@@ -46,6 +46,7 @@ import {
|
||||
faCloud,
|
||||
faQuestion,
|
||||
faStamp,
|
||||
faInfoCircle,
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import {
|
||||
@@ -109,4 +110,5 @@ library.add(
|
||||
faCloud,
|
||||
faQuestion,
|
||||
faStamp,
|
||||
faInfoCircle,
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ import { components } from '@cortezaproject/corteza-vue'
|
||||
import { LMap, LTileLayer, LMarker } from 'vue2-leaflet'
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
import { Icon } from 'leaflet'
|
||||
const { CCorredorManualButtons, CPermissionsButton } = components
|
||||
const { CCorredorManualButtons, CPermissionsButton, CInputConfirm } = components
|
||||
|
||||
Vue.use(PortalVue)
|
||||
Vue.component('c-corredor-manual-buttons', CCorredorManualButtons)
|
||||
@@ -16,6 +16,7 @@ Vue.component('c-permissions-button', CPermissionsButton)
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon)
|
||||
Vue.component('c-content-header', CContentHeader)
|
||||
Vue.component('c-resource-list-status-filter', CResourceListStatusFilter)
|
||||
Vue.component('c-input-confirm', CInputConfirm)
|
||||
|
||||
// Map things
|
||||
Vue.component('l-map', LMap)
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<c-filters-stepper
|
||||
v-if="routeID"
|
||||
ref="stepper"
|
||||
:fetching="stepper.fetching"
|
||||
:processing="stepper.processing"
|
||||
:success="stepper.success"
|
||||
:filters.sync="filters"
|
||||
@@ -91,6 +92,7 @@ export default {
|
||||
success: false,
|
||||
},
|
||||
stepper: {
|
||||
fetching: false,
|
||||
processing: false,
|
||||
success: false,
|
||||
},
|
||||
@@ -115,7 +117,7 @@ export default {
|
||||
},
|
||||
|
||||
showProfiler () {
|
||||
return this.$Settings.get('apigw.profilerEnabled', false) && (this.$Settings.get('apigw.profilerGlobal', false) || this.filters.some(({ ref, enabled = false }) => ref === 'profiler' && enabled))
|
||||
return this.$Settings.get('apigw.profiler.enabled', false) && (this.$Settings.get('apigw.profiler.global', false) || this.filters.some(({ ref, enabled = false }) => ref === 'profiler' && enabled))
|
||||
},
|
||||
},
|
||||
|
||||
@@ -128,7 +130,6 @@ export default {
|
||||
if (this.routeID) {
|
||||
this.fetchSteps()
|
||||
this.fetchRoute()
|
||||
this.fetchAllAvailableFilters()
|
||||
this.fetchFilters()
|
||||
} else {
|
||||
this.route = {
|
||||
@@ -262,24 +263,29 @@ export default {
|
||||
|
||||
fetchFilters () {
|
||||
this.incLoader()
|
||||
this.stepper.fetching = true
|
||||
|
||||
this.$SystemAPI.apigwFilterList({ routeID: this.routeID })
|
||||
.then(({ set = [] }) => {
|
||||
this.setRouteFilters(set)
|
||||
return this.setRouteFilters(set)
|
||||
})
|
||||
.catch(this.toastErrorHandler(this.$t('notification:gateway.filter.fetch.error')))
|
||||
.finally(() => {
|
||||
this.decLoader()
|
||||
this.stepper.fetching = false
|
||||
})
|
||||
},
|
||||
|
||||
setRouteFilters (routeFilters = []) {
|
||||
this.filters = (routeFilters || []).map(filter => {
|
||||
const f = { ...this.availableFilters.find((af) => af.ref === filter.ref) }
|
||||
f.params = this.decodeParams(f, { ...filter.params })
|
||||
f.weight = parseInt(filter.weight)
|
||||
f.filterID = filter.filterID
|
||||
f.enabled = !!filter.enabled
|
||||
return { ...f }
|
||||
return this.fetchAllAvailableFilters().then(() => {
|
||||
this.filters = (routeFilters || []).map(filter => {
|
||||
const f = { ...this.availableFilters.find((af) => af.ref === filter.ref) }
|
||||
f.params = this.decodeParams(f, { ...filter.params })
|
||||
f.weight = parseInt(filter.weight)
|
||||
f.filterID = filter.filterID
|
||||
f.enabled = !!filter.enabled
|
||||
return { ...f }
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
@@ -303,10 +309,11 @@ export default {
|
||||
|
||||
fetchAllAvailableFilters () {
|
||||
this.incLoader()
|
||||
this.$SystemAPI.apigwFilterDefFilter()
|
||||
|
||||
return this.$SystemAPI.apigwFilterDefFilter()
|
||||
.then((api) => {
|
||||
this.availableFilters = api.map((f) => {
|
||||
return { name, ...f, ref: f.name, enabled: true, options: { checked: false } }
|
||||
return { ...f, ref: f.name, enabled: true, options: { checked: false } }
|
||||
})
|
||||
})
|
||||
.catch(this.toastErrorHandler(this.$t('notification:gateway.filter.fetch.error')))
|
||||
|
||||
111
client/web/admin/src/views/System/Apigw/Index.vue
Normal file
111
client/web/admin/src/views/System/Apigw/Index.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<b-container
|
||||
class="py-3"
|
||||
>
|
||||
<c-content-header
|
||||
:title="$t('title')"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="d-flex flex-column h-100"
|
||||
>
|
||||
<c-settings-editor
|
||||
:settings="apigwSettings"
|
||||
class="mb-3"
|
||||
@submit="onSettingsSubmit"
|
||||
/>
|
||||
|
||||
<c-route-list
|
||||
class="mb-4 flex-fill"
|
||||
/>
|
||||
</div>
|
||||
</b-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import editorHelpers from 'corteza-webapp-admin/src/mixins/editorHelpers'
|
||||
import CSettingsEditor from 'corteza-webapp-admin/src/components/Apigw/CSettingsEditor'
|
||||
import CRouteList from 'corteza-webapp-admin/src/components/Apigw/CRouteList'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CRouteList,
|
||||
CSettingsEditor,
|
||||
},
|
||||
|
||||
mixins: [
|
||||
editorHelpers,
|
||||
],
|
||||
|
||||
i18nOptions: {
|
||||
namespaces: [ 'system.apigw' ],
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
settings: {
|
||||
processing: false,
|
||||
success: false,
|
||||
|
||||
items: [],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
apigwSettings () {
|
||||
if (this.settings.items.length > 0) {
|
||||
return this.settings.items.reduce((map, obj) => {
|
||||
const { name, value } = obj
|
||||
const split = name.split('.')
|
||||
|
||||
if (split[0] === 'apigw') {
|
||||
map[name] = value
|
||||
}
|
||||
|
||||
return map
|
||||
}, {})
|
||||
}
|
||||
return {}
|
||||
},
|
||||
},
|
||||
|
||||
created () {
|
||||
this.fetchSettings()
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSettingsSubmit (settings) {
|
||||
this.settings.processing = true
|
||||
|
||||
const values = Object.entries(settings).map(([name, value]) => {
|
||||
return { name, value }
|
||||
})
|
||||
|
||||
this.$SystemAPI.settingsUpdate({ values })
|
||||
.then(() => {
|
||||
this.animateSuccess('settings')
|
||||
this.toastSuccess(this.$t('notification:settings.system.apigw.success'))
|
||||
this.$Settings.fetch()
|
||||
})
|
||||
.catch(this.toastErrorHandler(this.$t('notification:settings.system.apigw.error')))
|
||||
.finally(() => {
|
||||
this.settings.processing = false
|
||||
})
|
||||
},
|
||||
|
||||
fetchSettings () {
|
||||
this.incLoader()
|
||||
|
||||
this.$SystemAPI.settingsList()
|
||||
.then((settings = []) => {
|
||||
this.settings.items = settings
|
||||
})
|
||||
.catch(this.toastErrorHandler(this.$t('notification:settings.system.fetch.error')))
|
||||
.finally(() => {
|
||||
this.decLoader()
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -19,27 +19,36 @@
|
||||
<h3>
|
||||
{{ $t('general:label.routes') }}
|
||||
</h3>
|
||||
<em>{{ description }}</em>
|
||||
|
||||
<div
|
||||
class="d-flex align-items-center justify-content-between"
|
||||
class="d-flex align-items-center justify-content-between mt-2"
|
||||
>
|
||||
<em>{{ description }}</em>
|
||||
<div>
|
||||
<span
|
||||
:class="{ 'loading': loading }"
|
||||
>
|
||||
{{ autoRefreshLabel }}
|
||||
</span>
|
||||
<b-button
|
||||
variant="primary"
|
||||
data-test-id="button-refresh"
|
||||
variant="primary"
|
||||
:disabled="loading"
|
||||
class="ml-2"
|
||||
@click="loadItems()"
|
||||
>
|
||||
{{ $t('general:label.refresh') }}
|
||||
</b-button>
|
||||
<span
|
||||
class="ml-1"
|
||||
:class="{ 'loading': loading }"
|
||||
>
|
||||
{{ autoRefreshLabel }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<c-input-confirm
|
||||
:disabled="!items.length"
|
||||
:borderless="false"
|
||||
variant="danger"
|
||||
@confirmed="purgeRequests"
|
||||
>
|
||||
{{ $t('purge.all') }}
|
||||
</c-input-confirm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -63,13 +72,13 @@
|
||||
>
|
||||
<template #cell(actions)="row">
|
||||
<b-button
|
||||
size="sm"
|
||||
variant="link"
|
||||
class="p-0"
|
||||
:to="{ name: 'system.apigw.profiler.route.list', params: { routeID: row.item.routeID } }"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'pen']"
|
||||
:icon="['fas', 'info-circle']"
|
||||
class="text-primary"
|
||||
/>
|
||||
</b-button>
|
||||
</template>
|
||||
@@ -196,7 +205,7 @@ export default {
|
||||
},
|
||||
|
||||
description () {
|
||||
return this.$Settings.get('apigw.profilerGlobal', false) ? this.$t('description.globalEnabled') : this.$t('description.globalDisabled')
|
||||
return this.$Settings.get('apigw.profiler.global', false) ? this.$t('description.globalEnabled') : this.$t('description.globalDisabled')
|
||||
},
|
||||
|
||||
hasNextPage () {
|
||||
@@ -245,6 +254,15 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
purgeRequests () {
|
||||
this.$SystemAPI.apigwProfilerPurgeAll()
|
||||
.then(() => {
|
||||
this.loadItems()
|
||||
this.toastSuccess(this.$t('notification:gateway.profiler.purge.success'))
|
||||
})
|
||||
.catch(this.toastErrorHandler(this.$t('notification:gateway.profiler.purge.error')))
|
||||
},
|
||||
|
||||
resetItems (sorting = this.sorting) {
|
||||
this.sorting = sorting
|
||||
this.filter.before = ''
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
class="text-nowrap"
|
||||
>
|
||||
<b-button
|
||||
v-if="$Settings.get('apigw.profilerEnabled', false)"
|
||||
v-if="$Settings.get('apigw.profiler.enabled', false)"
|
||||
class="ml-2"
|
||||
variant="info"
|
||||
:to="{ name: 'system.apigw.profiler' }"
|
||||
|
||||
@@ -96,8 +96,9 @@ export default [
|
||||
|
||||
combo('system', 'authClient', { pkey: 'authClientID' }),
|
||||
|
||||
combo('system', 'apigw', { pkey: 'routeID', plural: 'routes' }),
|
||||
|
||||
r('system.apigw', 'apigw', 'System/Apigw/Index'),
|
||||
r('system.apigw.new', 'apigw/new', 'System/Apigw/Editor'),
|
||||
r('system.apigw.edit', 'apigw/edit/:routeID', 'System/Apigw/Editor'),
|
||||
r('system.apigw.profiler', 'apigw/profiler', 'System/Apigw/Profiler/Index'),
|
||||
r('system.apigw.profiler.route.list', 'apigw/profiler/route/:routeID', 'System/Apigw/Profiler/Route'),
|
||||
r('system.apigw.profiler.hit.list', 'apigw/profiler/hit/:hitID', 'System/Apigw/Profiler/Hit'),
|
||||
|
||||
@@ -4070,6 +4070,48 @@ export default class System {
|
||||
return `/apigw/profiler/hit/${hitID}`
|
||||
}
|
||||
|
||||
// Purge all profiler hits
|
||||
async apigwProfilerPurgeAll (extra: AxiosRequestConfig = {}): Promise<KV> {
|
||||
|
||||
const cfg: AxiosRequestConfig = {
|
||||
...extra,
|
||||
method: 'post',
|
||||
url: this.apigwProfilerPurgeAllEndpoint(),
|
||||
}
|
||||
|
||||
return this.api().request(cfg).then(result => stdResolve(result))
|
||||
}
|
||||
|
||||
apigwProfilerPurgeAllEndpoint (): string {
|
||||
return '/apigw/profiler/purge'
|
||||
}
|
||||
|
||||
// Purge route profiler hits
|
||||
async apigwProfilerPurge (a: KV, extra: AxiosRequestConfig = {}): Promise<KV> {
|
||||
const {
|
||||
routeID,
|
||||
} = (a as KV) || {}
|
||||
if (!routeID) {
|
||||
throw Error('field routeID is empty')
|
||||
}
|
||||
const cfg: AxiosRequestConfig = {
|
||||
...extra,
|
||||
method: 'post',
|
||||
url: this.apigwProfilerPurgeEndpoint({
|
||||
routeID,
|
||||
}),
|
||||
}
|
||||
|
||||
return this.api().request(cfg).then(result => stdResolve(result))
|
||||
}
|
||||
|
||||
apigwProfilerPurgeEndpoint (a: KV): string {
|
||||
const {
|
||||
routeID,
|
||||
} = a || {}
|
||||
return `/apigw/profiler/purge/${routeID}`
|
||||
}
|
||||
|
||||
// List resources translations
|
||||
async localeListResource (a: KV, extra: AxiosRequestConfig = {}): Promise<KV> {
|
||||
const {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
:size="size"
|
||||
:disabled="disabled"
|
||||
:class="`${buttonClass} ${borderless ? 'border-0' : ''}`"
|
||||
@click.prevent="onPrompt"
|
||||
@click.stop.prevent="onPrompt"
|
||||
>
|
||||
<slot>
|
||||
<font-awesome-icon
|
||||
@@ -26,7 +26,7 @@
|
||||
class="mr-1"
|
||||
:class="[ borderless && 'border-0' ]"
|
||||
@blur.prevent="onCancel()"
|
||||
@click.prevent="onConfirmation()"
|
||||
@click.prevent.stop="onConfirmation()"
|
||||
>
|
||||
<slot name="yes">
|
||||
<font-awesome-icon
|
||||
@@ -40,7 +40,7 @@
|
||||
:size="sizeConfirm"
|
||||
:disabled="cancelDisabled"
|
||||
:class="[ borderless && 'border-0' ]"
|
||||
@click.prevent="onCancel()"
|
||||
@click.prevent.stop="onCancel()"
|
||||
>
|
||||
<slot name="no">
|
||||
<font-awesome-icon
|
||||
|
||||
@@ -156,6 +156,12 @@ gateway:
|
||||
undelete:
|
||||
success: Route restored
|
||||
error: Route restore failed
|
||||
profiler:
|
||||
fetch:
|
||||
error: Requests fetch failed
|
||||
purge:
|
||||
success: Requests purged
|
||||
error: Requests purge failed
|
||||
workflow:
|
||||
fetch:
|
||||
error: Workflow fetch failed
|
||||
@@ -238,6 +244,9 @@ settings:
|
||||
smtpCheck:
|
||||
success: SMTP configuration check passed
|
||||
error: SMTP configuration check failed
|
||||
apigw:
|
||||
success: Integration gateway settings saved
|
||||
error: Integration gateway settings update failed
|
||||
compose:
|
||||
fetch:
|
||||
error: Compose settings fetch failed
|
||||
|
||||
@@ -1,172 +1,177 @@
|
||||
title: Integration Gateway
|
||||
list:
|
||||
export: Export
|
||||
title: 'Integration Gateway'
|
||||
new: 'New'
|
||||
permissions: 'Permissions'
|
||||
profiler: 'Profiler'
|
||||
yaml: 'YAML'
|
||||
loading: 'Loading routes'
|
||||
title: Routes
|
||||
new: New
|
||||
permissions: Permissions
|
||||
profiler: Profiler
|
||||
yaml: YAML
|
||||
loading: Loading routes
|
||||
numFound: '{{count}} route found'
|
||||
numFound_plural: '{{count}} routes found'
|
||||
filterForm:
|
||||
query:
|
||||
label: 'Filter route list'
|
||||
placeholder: 'Filter routes by name'
|
||||
label: Filter route list
|
||||
placeholder: Filter routes by name
|
||||
excluded:
|
||||
label: 'Without'
|
||||
label: Without
|
||||
inclusive:
|
||||
label: 'Including'
|
||||
label: Including
|
||||
exclusive:
|
||||
label: 'Only'
|
||||
label: Only
|
||||
deleted:
|
||||
label: 'Deleted routes'
|
||||
label: deleted routes
|
||||
handle:
|
||||
placeholder: 'Filter endpoints by path'
|
||||
placeholder: Filter endpoints by path
|
||||
|
||||
columns:
|
||||
endpoint: 'Endpoint'
|
||||
createdAt: 'Created'
|
||||
enabled: 'Enabled'
|
||||
method: 'Method'
|
||||
endpoint: Endpoint
|
||||
createdAt: Created
|
||||
enabled: Enabled
|
||||
method: Method
|
||||
actions: ''
|
||||
state: State
|
||||
rows:
|
||||
filters:
|
||||
deleted: Deleted
|
||||
|
||||
settings:
|
||||
title: Settings
|
||||
profiler:
|
||||
label: Profiler
|
||||
enabled: Enabled
|
||||
global: Enabled globally
|
||||
proxy:
|
||||
label: Proxy
|
||||
follow: Follow redirects
|
||||
|
||||
editor:
|
||||
title: 'Edit route'
|
||||
new: 'New'
|
||||
permissions: 'Permissions'
|
||||
title: Edit route
|
||||
new: New
|
||||
permissions: Permissions
|
||||
|
||||
info:
|
||||
title: 'Basic information'
|
||||
title: Basic information
|
||||
|
||||
id: 'ID'
|
||||
endpoint: 'Endpoint'
|
||||
method: 'Method'
|
||||
enabled: 'Enabled'
|
||||
id: ID
|
||||
endpoint: Endpoint
|
||||
method: Method
|
||||
description: Description
|
||||
enabled: Enabled
|
||||
|
||||
delete: 'Delete'
|
||||
undelete: 'Undelete'
|
||||
deletedAt: 'Deleted at'
|
||||
delete: Delete
|
||||
undelete: Undelete
|
||||
deletedAt: Deleted at
|
||||
|
||||
updatedAt: 'Updated at'
|
||||
createdAt: 'Created at'
|
||||
updatedAt: Updated at
|
||||
createdAt: Created at
|
||||
|
||||
tooltip: 'Endpoint must begin with a slash "/" and can not contain any special characters except for the underscore "_" and hyphen "-"'
|
||||
tooltip: Endpoint must begin with a slash "/" and can not contain any special characters except for the underscore "_" and hyphen "-"
|
||||
validation:
|
||||
slash: 'Endpoint must begin with a slash "/"'
|
||||
minLength: 'Endpoint must contain at least one character'
|
||||
invalidCharacters: 'Endpoint contains invalid characters'
|
||||
slash: Endpoint must begin with a slash "/"
|
||||
minLength: Endpoint must contain at least one character
|
||||
invalidCharacters: Endpoint contains invalid characters
|
||||
|
||||
filters:
|
||||
title: 'Filter list'
|
||||
enabled: 'Enabled'
|
||||
disabled: 'Disabled'
|
||||
title: Filter list
|
||||
enabled: Enabled
|
||||
disabled: Disabled
|
||||
add: Add
|
||||
addFilter: Add filter
|
||||
addHeader: Add header
|
||||
params: Params
|
||||
filterListEmpty: Filter list is empty!
|
||||
|
||||
modal:
|
||||
title: 'Query parameters verifier'
|
||||
ok: 'Save & Close'
|
||||
title: Query parameters verifier
|
||||
ok: Save & Close
|
||||
|
||||
step_title:
|
||||
prefilter: 'Prefiltering'
|
||||
processer: 'Processing'
|
||||
postfilter: 'Postfiltering'
|
||||
prefilter: Prefiltering
|
||||
processer: Processing
|
||||
postfilter: Postfiltering
|
||||
|
||||
list:
|
||||
remove: 'Remove'
|
||||
filters: 'Filters'
|
||||
status: 'Status'
|
||||
actions: 'Actions'
|
||||
active: 'Active'
|
||||
noFilters: 'No filters'
|
||||
remove: Remove
|
||||
filters: Filters
|
||||
status: Status
|
||||
actions: Actions
|
||||
active: Active
|
||||
noFilters: No filters
|
||||
|
||||
labels:
|
||||
expr: 'Expression'
|
||||
location: 'URL'
|
||||
workflow: 'Workflow'
|
||||
status: 'HTTP Status'
|
||||
jsfunc: 'Function'
|
||||
input: 'Input'
|
||||
expr: Expression
|
||||
location: URL
|
||||
workflow: Workflow
|
||||
status: HTTP Status
|
||||
jsfunc: Function
|
||||
input: Input
|
||||
header: Headers
|
||||
name: Name
|
||||
value: Value
|
||||
|
||||
httpStatus:
|
||||
none: 'No Status'
|
||||
'300': '300 - Multiple Choices'
|
||||
'301': '301 - Moved Permanently'
|
||||
'302': '302 - Found'
|
||||
'303': '303 - See Other'
|
||||
'304': '304 - Not Modified'
|
||||
'307': '307 - Temporary Redirect'
|
||||
'308': '308 - Permanent Redirect'
|
||||
none: No Status
|
||||
'300': 300 - Multiple Choices
|
||||
'301': 301 - Moved Permanently
|
||||
'302': 302 - Found
|
||||
'303': 303 - See Other
|
||||
'304': 304 - Not Modified
|
||||
'307': 307 - Temporary Redirect
|
||||
'308': 308 - Permanent Redirect
|
||||
|
||||
placeholders:
|
||||
workflow: 'Select a workflow'
|
||||
|
||||
add: 'Add'
|
||||
addFilter: 'Add filter'
|
||||
params: 'Params'
|
||||
filterListEmpty: 'Filter list is empty!'
|
||||
workflow: Select a workflow
|
||||
|
||||
help:
|
||||
expression:
|
||||
example: 'Example == "match string" && match(SecondParam, "^foo\\s.*$")'
|
||||
link: 'Documentation'
|
||||
example: Example == "match string" && match(SecondParam, "^foo\\s.*$")
|
||||
link: Documentation
|
||||
|
||||
profiler:
|
||||
label: 'Profiler'
|
||||
title: 'Integration Gateway Profiler'
|
||||
label: Profiler
|
||||
title: Integration Gateway Profiler
|
||||
refreshingIn: Refreshing in {{seconds}}s
|
||||
description:
|
||||
globalEnabled: 'Showing routes for all incoming requests'
|
||||
globalDisabled: 'Showing only registered routes with profiler prefilter'
|
||||
description:
|
||||
globalEnabled: Showing routes for all incoming requests
|
||||
globalDisabled: Showing only registered routes with profiler prefilter
|
||||
purge:
|
||||
all: Purge requests for all routes
|
||||
this: Purge requests for this route
|
||||
|
||||
hit:
|
||||
title: 'Request Details'
|
||||
title: Request Details
|
||||
general:
|
||||
label: General
|
||||
id: 'Request ID'
|
||||
route: 'Request Route'
|
||||
URL: 'Request URL'
|
||||
method: 'Request Method'
|
||||
statusCode: 'Status Code'
|
||||
headers: 'Request Headers'
|
||||
remoteAddress: 'Remote Address'
|
||||
duration: 'Duration'
|
||||
start: 'Start'
|
||||
end: 'End'
|
||||
id: Request ID
|
||||
route: Request Route
|
||||
URL: Request URL
|
||||
method: Request Method
|
||||
statusCode: Status Code
|
||||
headers: Request Headers
|
||||
remoteAddress: Remote Address
|
||||
duration: Duration
|
||||
start: Start
|
||||
end: End
|
||||
openRoute: Open Route
|
||||
headers:
|
||||
label: 'Headers'
|
||||
label: Headers
|
||||
body:
|
||||
label: 'Body'
|
||||
|
||||
|
||||
filterForm:
|
||||
query:
|
||||
label: 'Filter route list'
|
||||
placeholder: 'Filter routes by name'
|
||||
excluded:
|
||||
label: 'Without'
|
||||
inclusive:
|
||||
label: 'Including'
|
||||
exclusive:
|
||||
label: 'Only'
|
||||
deleted:
|
||||
label: 'Deleted routes'
|
||||
label: Body
|
||||
|
||||
columns:
|
||||
actions: ''
|
||||
path: 'Route'
|
||||
count: 'Count'
|
||||
content_length: 'Content Length'
|
||||
http_method: 'Method'
|
||||
http_status_code: 'Status Code'
|
||||
size_min: 'Size (min)'
|
||||
size_max: 'Size (max)'
|
||||
size_avg: 'Size (avg)'
|
||||
time_min: 'Time (min)'
|
||||
time_max: 'Time (max)'
|
||||
time_avg: 'Time (avg)'
|
||||
time_start: 'Start time'
|
||||
time_finish: 'Finish time'
|
||||
time_duration: 'Duration'
|
||||
path: Route
|
||||
count: Count
|
||||
content_length: Content Length
|
||||
http_method: Method
|
||||
http_status_code: Status Code
|
||||
size_min: Size (min)
|
||||
size_max: Size (max)
|
||||
size_avg: Size (avg)
|
||||
time_min: Time (min)
|
||||
time_max: Time (max)
|
||||
time_avg: Time (avg)
|
||||
time_start: Start time
|
||||
time_finish: Finish time
|
||||
time_duration: Duration
|
||||
|
||||
Reference in New Issue
Block a user