Extend filter fields functionality with c-ace editor and autocomplete
This commit is contained in:
committed by
Jože Fortun
parent
af8216bdc3
commit
641ba76dd6
@@ -95,9 +95,11 @@
|
||||
:label="$t('calendar.recordFeed.prefilterLabel')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-textarea
|
||||
<c-input-expression
|
||||
v-model="feed.options.prefilter"
|
||||
:value="true"
|
||||
height="3.688rem"
|
||||
lang="javascript"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
:placeholder="$t('calendar.recordFeed.prefilterPlaceholder')"
|
||||
/>
|
||||
|
||||
@@ -142,7 +144,10 @@
|
||||
<script>
|
||||
import base from './base'
|
||||
import { components } from '@cortezaproject/corteza-vue'
|
||||
const { CInputColorPicker } = components
|
||||
import { compose, NoID } from '@cortezaproject/corteza-js'
|
||||
import autocomplete from 'corteza-webapp-compose/src/mixins/autocomplete.js'
|
||||
|
||||
const { CInputColorPicker, CInputExpression } = components
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
@@ -151,10 +156,26 @@ export default {
|
||||
|
||||
components: {
|
||||
CInputColorPicker,
|
||||
CInputExpression,
|
||||
},
|
||||
|
||||
extends: base,
|
||||
|
||||
mixins: [autocomplete],
|
||||
|
||||
props: {
|
||||
record: {
|
||||
type: compose.Record,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
|
||||
page: {
|
||||
type: compose.Page,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
/**
|
||||
* Finds the module, this feed configurator should use
|
||||
@@ -213,6 +234,14 @@ export default {
|
||||
themeSettings () {
|
||||
return this.$Settings.get('ui.studio.themes', [])
|
||||
},
|
||||
|
||||
isRecordPage () {
|
||||
return this.page && this.page.moduleID !== NoID
|
||||
},
|
||||
|
||||
recordAutoCompleteParams () {
|
||||
return this.processRecordAutoCompleteParams({ operators: true })
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
v-if="feed.resource && configurator(feed)"
|
||||
:feed="feed"
|
||||
:modules="modules"
|
||||
:page="page"
|
||||
:record="record"
|
||||
:module="module"
|
||||
/>
|
||||
</b-card>
|
||||
</b-col>
|
||||
@@ -65,11 +68,15 @@ export default {
|
||||
namespaces: 'block',
|
||||
},
|
||||
|
||||
components: {
|
||||
},
|
||||
|
||||
extends: base,
|
||||
|
||||
props: {
|
||||
page: {
|
||||
type: compose.Page,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters({
|
||||
modules: 'module/set',
|
||||
|
||||
@@ -44,9 +44,11 @@
|
||||
:label="$t('recordList.record.prefilterLabel')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-textarea
|
||||
<c-input-expression
|
||||
v-model.trim="options.filter"
|
||||
:value="true"
|
||||
height="3.688rem"
|
||||
lang="javascript"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
:placeholder="$t('recordList.record.prefilterPlaceholder')"
|
||||
/>
|
||||
|
||||
@@ -152,8 +154,12 @@
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { components } from '@cortezaproject/corteza-vue'
|
||||
import autocomplete from 'corteza-webapp-compose/src/mixins/autocomplete.js'
|
||||
import base from './base'
|
||||
|
||||
const { CInputExpression } = components
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
namespaces: 'block',
|
||||
@@ -161,7 +167,14 @@ export default {
|
||||
|
||||
name: 'CommentConfigurator',
|
||||
|
||||
components: {
|
||||
CInputExpression,
|
||||
},
|
||||
|
||||
extends: base,
|
||||
|
||||
mixins: [autocomplete],
|
||||
|
||||
data () {
|
||||
return {
|
||||
referenceList: [
|
||||
@@ -220,6 +233,10 @@ export default {
|
||||
}
|
||||
return []
|
||||
},
|
||||
|
||||
recordAutoCompleteParams () {
|
||||
return this.processRecordAutoCompleteParams({ module: this.selectedModule, operators: true })
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
||||
@@ -17,10 +17,15 @@
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-input-group>
|
||||
<b-form-input
|
||||
<c-input-expression
|
||||
id="title"
|
||||
v-model="block.title"
|
||||
auto-complete
|
||||
lang="javascript"
|
||||
:placeholder="$t('general.titlePlaceholder')"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
height="2.375rem"
|
||||
class="flex-grow-1"
|
||||
/>
|
||||
|
||||
<b-input-group-append>
|
||||
@@ -53,10 +58,15 @@
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-input-group>
|
||||
<b-form-textarea
|
||||
<c-input-expression
|
||||
id="description"
|
||||
v-model="block.description"
|
||||
auto-complete
|
||||
lang="javascript"
|
||||
:placeholder="$t('general.descriptionPlaceholder')"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
height="3.448rem"
|
||||
class="flex-grow-1"
|
||||
/>
|
||||
<b-input-group-append>
|
||||
<page-translator
|
||||
@@ -257,9 +267,15 @@
|
||||
ƒ
|
||||
</b-button>
|
||||
</b-input-group-prepend>
|
||||
<b-form-input
|
||||
<c-input-expression
|
||||
id="visibility-fields"
|
||||
v-model="block.meta.visibility.expression"
|
||||
auto-complete
|
||||
lang="javascript"
|
||||
:placeholder="$t('general.visibility.condition.placeholder')"
|
||||
:suggestion-params="visibilityAutoCompleteParams"
|
||||
height="2.375rem"
|
||||
class="flex-grow-1"
|
||||
/>
|
||||
<b-input-group-append>
|
||||
<b-button
|
||||
@@ -342,12 +358,16 @@
|
||||
</template>
|
||||
</b-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { compose, NoID } from '@cortezaproject/corteza-js'
|
||||
import { handle } from '@cortezaproject/corteza-vue'
|
||||
import { handle, components } from '@cortezaproject/corteza-vue'
|
||||
import PageTranslator from 'corteza-webapp-compose/src/components/Admin/Page/PageTranslator'
|
||||
import autocomplete from 'corteza-webapp-compose/src/mixins/autocomplete.js'
|
||||
import PageBlock from './index'
|
||||
|
||||
const { CInputExpression } = components
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
namespaces: 'block',
|
||||
@@ -356,18 +376,38 @@ export default {
|
||||
components: {
|
||||
PageBlock,
|
||||
PageTranslator,
|
||||
CInputExpression,
|
||||
},
|
||||
|
||||
mixins: [autocomplete],
|
||||
|
||||
props: {
|
||||
block: {
|
||||
type: compose.PageBlock,
|
||||
required: true,
|
||||
},
|
||||
|
||||
module: {
|
||||
type: compose.Module,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
|
||||
page: {
|
||||
type: compose.Page,
|
||||
required: true,
|
||||
},
|
||||
|
||||
record: {
|
||||
type: [Object, null],
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
|
||||
namespace: {
|
||||
type: compose.Namespace,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data () {
|
||||
@@ -494,6 +534,7 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mh-tab {
|
||||
max-height: calc(100vh - 16rem);
|
||||
|
||||
@@ -66,9 +66,11 @@
|
||||
:label="$t('calendar.recordFeed.prefilterLabel')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-textarea
|
||||
<c-input-expression
|
||||
v-model="feed.options.prefilter"
|
||||
:value="true"
|
||||
height="3.688rem"
|
||||
lang="javascript"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
:placeholder="$t('calendar.recordFeed.prefilterPlaceholder')"
|
||||
/>
|
||||
|
||||
@@ -146,7 +148,9 @@
|
||||
<script>
|
||||
import base from './base'
|
||||
import { components } from '@cortezaproject/corteza-vue'
|
||||
const { CInputColorPicker } = components
|
||||
import autocomplete from 'corteza-webapp-compose/src/mixins/autocomplete.js'
|
||||
|
||||
const { CInputColorPicker, CInputExpression } = components
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
@@ -155,10 +159,13 @@ export default {
|
||||
|
||||
components: {
|
||||
CInputColorPicker,
|
||||
CInputExpression,
|
||||
},
|
||||
|
||||
extends: base,
|
||||
|
||||
mixins: [autocomplete],
|
||||
|
||||
data () {
|
||||
return {
|
||||
checkboxLabel: {
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
v-if="feed.resource && configurator(feed)"
|
||||
:feed="feed"
|
||||
:modules="modules"
|
||||
:page="page"
|
||||
:record="record"
|
||||
/>
|
||||
</b-card>
|
||||
</b-col>
|
||||
|
||||
@@ -18,8 +18,12 @@
|
||||
:description="enableFromRecordURL ? $t('iframe.srcDesc') : ''"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-input
|
||||
<c-input-expression
|
||||
v-model="options.src"
|
||||
auto-complete
|
||||
lang="text"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
height="2.375rem"
|
||||
type="url"
|
||||
/>
|
||||
<i18next
|
||||
@@ -37,6 +41,10 @@
|
||||
</template>
|
||||
<script>
|
||||
import base from './base'
|
||||
import { components } from '@cortezaproject/corteza-vue'
|
||||
import autocomplete from 'corteza-webapp-compose/src/mixins/autocomplete.js'
|
||||
|
||||
const { CInputExpression } = components
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
@@ -45,8 +53,12 @@ export default {
|
||||
|
||||
name: 'IFrame',
|
||||
|
||||
components: { CInputExpression },
|
||||
|
||||
extends: base,
|
||||
|
||||
mixins: [autocomplete],
|
||||
|
||||
computed: {
|
||||
fields () {
|
||||
if (!this.module) {
|
||||
|
||||
@@ -147,10 +147,14 @@
|
||||
:label="$t('metric.edit.filterLabel')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-textarea
|
||||
<c-input-expression
|
||||
v-model="edit.filter"
|
||||
auto-complete
|
||||
lang="javascript"
|
||||
placeholder="(A > B) OR (A < C)"
|
||||
class="mb-1"
|
||||
height="3.448rem"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
/>
|
||||
|
||||
<i18next
|
||||
@@ -204,10 +208,14 @@
|
||||
:label="$t('metric.edit.transformFunctionLabel')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-textarea
|
||||
<c-input-expression
|
||||
v-model="edit.transformFx"
|
||||
auto-complete
|
||||
lang="javascript"
|
||||
placeholder="v"
|
||||
class="mb-1"
|
||||
height="3.448rem"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
/>
|
||||
|
||||
<small>{{ $t('metric.edit.transformFunctionDescription') }}</small>
|
||||
@@ -350,7 +358,11 @@ import MStyle from './MStyle'
|
||||
import { mapGetters } from 'vuex'
|
||||
import MetricBase from '../MetricBase'
|
||||
import ColumnPicker from 'corteza-webapp-compose/src/components/Admin/Module/Records/ColumnPicker'
|
||||
import autocomplete from 'corteza-webapp-compose/src/mixins/autocomplete.js'
|
||||
import { compose, NoID } from '@cortezaproject/corteza-js'
|
||||
import { components } from '@cortezaproject/corteza-vue'
|
||||
|
||||
const { CInputExpression } = components
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
@@ -362,9 +374,12 @@ export default {
|
||||
MStyle,
|
||||
MetricBase,
|
||||
ColumnPicker,
|
||||
CInputExpression,
|
||||
},
|
||||
extends: base,
|
||||
|
||||
mixins: [autocomplete],
|
||||
|
||||
data () {
|
||||
return {
|
||||
edit: undefined,
|
||||
@@ -436,6 +451,10 @@ export default {
|
||||
|
||||
return this.getModuleByID(this.edit.moduleID)
|
||||
},
|
||||
|
||||
recordAutoCompleteParams () {
|
||||
return this.processRecordAutoCompleteParams({ module: this.selectedMetricModule })
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
||||
@@ -50,10 +50,13 @@
|
||||
:label="$t('metric.edit.filterLabel')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-textarea
|
||||
<c-input-expression
|
||||
v-model="options.value.filter"
|
||||
height="3.688rem"
|
||||
lang="javascript"
|
||||
placeholder="(A > B) OR (A < C)"
|
||||
class="mb-1"
|
||||
:suggestion-params="recordAutoCompleteParams.value"
|
||||
/>
|
||||
<i18next
|
||||
path="metric.edit.filterFootnote"
|
||||
@@ -160,10 +163,13 @@
|
||||
:label="$t('metric.edit.filterLabel')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-textarea
|
||||
<c-input-expression
|
||||
v-model="options.minValue.filter"
|
||||
height="3.688rem"
|
||||
lang="javascript"
|
||||
placeholder="(A > B) OR (A < C)"
|
||||
class="mb-1"
|
||||
:suggestion-params="recordAutoCompleteParams.min"
|
||||
/>
|
||||
<i18next
|
||||
path="metric.edit.filterFootnote"
|
||||
@@ -270,10 +276,13 @@
|
||||
:label="$t('metric.edit.filterLabel')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-textarea
|
||||
<c-input-expression
|
||||
v-model="options.maxValue.filter"
|
||||
height="3.688rem"
|
||||
lang="javascript"
|
||||
placeholder="(A > B) OR (A < C)"
|
||||
class="mb-1"
|
||||
:suggestion-params="recordAutoCompleteParams.max"
|
||||
/>
|
||||
<i18next
|
||||
path="metric.edit.filterFootnote"
|
||||
@@ -532,9 +541,13 @@
|
||||
<script>
|
||||
import base from './base'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { components } from '@cortezaproject/corteza-vue'
|
||||
import { compose, validator } from '@cortezaproject/corteza-js'
|
||||
import autocomplete from 'corteza-webapp-compose/src/mixins/autocomplete.js'
|
||||
import FieldViewer from '../ModuleFields/Viewer'
|
||||
|
||||
const { CInputExpression } = components
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
namespaces: 'block',
|
||||
@@ -544,10 +557,13 @@ export default {
|
||||
|
||||
components: {
|
||||
FieldViewer,
|
||||
CInputExpression,
|
||||
},
|
||||
|
||||
extends: base,
|
||||
|
||||
mixins: [autocomplete],
|
||||
|
||||
data () {
|
||||
return {
|
||||
aggregationOperations: [
|
||||
@@ -606,13 +622,33 @@ export default {
|
||||
return this.returnValueModuleFields(this.options.value.moduleID)
|
||||
},
|
||||
|
||||
valueModule () {
|
||||
return this.moduleByID(this.options.value.moduleID)
|
||||
},
|
||||
|
||||
minValueModuleFields () {
|
||||
return this.returnValueModuleFields(this.options.minValue.moduleID)
|
||||
},
|
||||
|
||||
minValueModule () {
|
||||
return this.moduleByID(this.options.minValue.moduleID)
|
||||
},
|
||||
|
||||
maxValueModuleFields () {
|
||||
return this.returnValueModuleFields(this.options.maxValue.moduleID)
|
||||
},
|
||||
|
||||
maxValueModule () {
|
||||
return this.moduleByID(this.options.maxValue.moduleID)
|
||||
},
|
||||
|
||||
recordAutoCompleteParams () {
|
||||
return {
|
||||
value: this.processRecordAutoCompleteParams({ module: this.valueModule, operators: true }),
|
||||
min: this.processRecordAutoCompleteParams({ module: this.minValueModule, operators: true }),
|
||||
max: this.processRecordAutoCompleteParams({ module: this.maxValueModule, operators: true }),
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<c-form-table-wrapper hide-add-button>
|
||||
<b-form-group
|
||||
:label="$t('recordList.record.prefilterCommand')"
|
||||
label-class="text-primary"
|
||||
class="m-0"
|
||||
>
|
||||
<b-row v-if="textInput">
|
||||
<b-col>
|
||||
<b-form-group label-class="text-primary">
|
||||
<c-input-expression
|
||||
v-model="options.prefilter"
|
||||
height="3.688rem"
|
||||
lang="javascript"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
/>
|
||||
|
||||
<i18next
|
||||
path="recordList.record.prefilterFootnote"
|
||||
tag="small"
|
||||
class="text-muted"
|
||||
>
|
||||
<code>${record.values.fieldName}</code>
|
||||
<code>${recordID}</code>
|
||||
<code>${ownerID}</code>
|
||||
<span><code>${userID}</code>, <code>${user.name}</code></span>
|
||||
</i18next>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<c-form-table-wrapper
|
||||
v-else
|
||||
hide-add-button
|
||||
>
|
||||
<filter-toolbox
|
||||
v-model="filterGroup"
|
||||
:module="module"
|
||||
:namespace="namespace"
|
||||
:mock.sync="mock"
|
||||
reset-filter-on-created
|
||||
/>
|
||||
</c-form-table-wrapper>
|
||||
|
||||
<div class="mt-1 d-flex align-items-center">
|
||||
<b-button
|
||||
variant="link"
|
||||
size="sm"
|
||||
class="ml-auto text-decoration-none"
|
||||
@click="toggleFilterView"
|
||||
>
|
||||
{{ $t('recordList.prefilter.toggleInputType') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-form-group>
|
||||
</c-form-table-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { components } from '@cortezaproject/corteza-vue'
|
||||
import { compose, validator } from '@cortezaproject/corteza-js'
|
||||
import {
|
||||
getRecordListFilterSql,
|
||||
trimChar,
|
||||
} from 'corteza-webapp-compose/src/lib/record-filter.js'
|
||||
import FilterToolbox from 'corteza-webapp-compose/src/components/Common/FilterToolbox.vue'
|
||||
import autocomplete from 'corteza-webapp-compose/src/mixins/autocomplete.js'
|
||||
|
||||
const { CInputExpression } = components
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
namespaces: 'block',
|
||||
},
|
||||
|
||||
name: 'RecordListConfiguratorPrefilter',
|
||||
|
||||
components: {
|
||||
FilterToolbox,
|
||||
CInputExpression,
|
||||
},
|
||||
|
||||
mixins: [autocomplete],
|
||||
|
||||
props: {
|
||||
options: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
|
||||
namespace: {
|
||||
type: compose.Namespace,
|
||||
required: true,
|
||||
},
|
||||
|
||||
module: {
|
||||
type: compose.Module,
|
||||
required: true,
|
||||
},
|
||||
|
||||
record: {
|
||||
type: [Object, null],
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
textInput: true,
|
||||
filterGroup: [],
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
recordAutoCompleteParams () {
|
||||
return this.processRecordAutoCompleteParams({ operators: true })
|
||||
},
|
||||
},
|
||||
|
||||
created () {
|
||||
// Change all module fields to single value to keep multi value fields and single value
|
||||
const module = JSON.parse(JSON.stringify(this.module || {}))
|
||||
|
||||
module.fields = [
|
||||
...[...module.fields].map((f) => {
|
||||
f.multi = f.isMulti
|
||||
f.isMulti = false
|
||||
|
||||
// Disable edge case options
|
||||
if (f.kind === 'DateTime') {
|
||||
f.options.onlyFutureValues = false
|
||||
f.options.onlyPastValues = false
|
||||
}
|
||||
|
||||
return f
|
||||
}),
|
||||
...this.module.systemFields().map((sf) => {
|
||||
return { ...sf, label: this.$t(`field:system.${sf.name}`) }
|
||||
}),
|
||||
]
|
||||
|
||||
this.mock = {
|
||||
namespace: this.namespace,
|
||||
module,
|
||||
errors: new validator.Validated(),
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleFilterView () {
|
||||
if (!this.textInput) {
|
||||
this.options.prefilter = this.parseFilter()
|
||||
}
|
||||
|
||||
this.textInput = !this.textInput
|
||||
},
|
||||
|
||||
getOptionKey ({ name }) {
|
||||
return name
|
||||
},
|
||||
|
||||
processFilter (filterGroup = this.value) {
|
||||
return filterGroup.map(({ groupCondition, filter = [], name }) => {
|
||||
filter = filter.map(({ record, ...f }) => {
|
||||
if (record) {
|
||||
f.value = record[f.name] || record.values[f.name]
|
||||
}
|
||||
|
||||
if (this.isBetweenOperator(f.operator)) {
|
||||
f.value = {
|
||||
start: this.getField(f.name).isSystem
|
||||
? record[`${f.name}-start`]
|
||||
: record.values[`${f.name}-start`],
|
||||
end: this.getField(f.name).isSystem
|
||||
? record[`${f.name}-end`]
|
||||
: record.values[`${f.name}-end`],
|
||||
}
|
||||
}
|
||||
|
||||
return f
|
||||
})
|
||||
|
||||
return { groupCondition, filter, name }
|
||||
})
|
||||
},
|
||||
|
||||
isBetweenOperator (op) {
|
||||
return ['BETWEEN', 'NOT BETWEEN'].includes(op)
|
||||
},
|
||||
|
||||
parseFilter (filterGroup = this.filterGroup) {
|
||||
const filter = this.processFilter(filterGroup)
|
||||
|
||||
const filterSqlArray = filter
|
||||
.map(({ groupCondition, filter = [] }) => {
|
||||
groupCondition = groupCondition ? ` ${groupCondition} ` : ''
|
||||
filter = getRecordListFilterSql(filter)
|
||||
|
||||
return filter ? `${filter}${groupCondition}` : ''
|
||||
})
|
||||
.filter((filter) => filter)
|
||||
|
||||
const filterSql = trimChar(
|
||||
trimChar(filterSqlArray.join(''), ' AND '),
|
||||
' OR '
|
||||
)
|
||||
|
||||
return filterSql
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -264,30 +264,13 @@
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-row>
|
||||
<b-col>
|
||||
<b-form-group
|
||||
:label="$t('recordList.record.prefilterCommand')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-textarea
|
||||
v-model="options.prefilter"
|
||||
:placeholder="$t('recordList.record.prefilterPlaceholder')"
|
||||
/>
|
||||
|
||||
<i18next
|
||||
path="recordList.record.prefilterFootnote"
|
||||
tag="small"
|
||||
class="text-muted"
|
||||
>
|
||||
<code>${record.values.fieldName}</code>
|
||||
<code>${recordID}</code>
|
||||
<code>${ownerID}</code>
|
||||
<span><code>${userID}</code>, <code>${user.name}</code></span>
|
||||
</i18next>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<prefilter
|
||||
:record="record"
|
||||
:module="recordListModule"
|
||||
:namespace="namespace"
|
||||
:options="options"
|
||||
:page="page"
|
||||
/>
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
@@ -45,9 +45,11 @@
|
||||
:label="$t('recordList.record.prefilterLabel')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-textarea
|
||||
<c-input-expression
|
||||
v-model.trim="options.filter"
|
||||
:value="true"
|
||||
height="3.688rem"
|
||||
lang="javascript"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
:placeholder="$t('recordList.record.prefilterPlaceholder')"
|
||||
/>
|
||||
<i18next
|
||||
@@ -196,8 +198,13 @@
|
||||
import FieldEditor from '../ModuleFields/Editor'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { compose, validator } from '@cortezaproject/corteza-js'
|
||||
import { components } from '@cortezaproject/corteza-vue'
|
||||
import autocomplete from 'corteza-webapp-compose/src/mixins/autocomplete.js'
|
||||
|
||||
import base from './base'
|
||||
|
||||
const { CInputExpression } = components
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
namespaces: 'block',
|
||||
@@ -207,10 +214,13 @@ export default {
|
||||
|
||||
components: {
|
||||
FieldEditor,
|
||||
CInputExpression,
|
||||
},
|
||||
|
||||
extends: base,
|
||||
|
||||
mixins: [autocomplete],
|
||||
|
||||
data () {
|
||||
return {
|
||||
/*
|
||||
@@ -275,6 +285,10 @@ export default {
|
||||
{ value: 'modal', text: this.$t('recordOrganizer.openInModal') },
|
||||
]
|
||||
},
|
||||
|
||||
recordAutoCompleteParams () {
|
||||
return this.processRecordAutoCompleteParams({ module: this.selectedModule })
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
:button="currentButton"
|
||||
:script="currentScript"
|
||||
:trigger="currentTrigger"
|
||||
:record="record"
|
||||
:module="module"
|
||||
@delete="deleteButton(currentButton)"
|
||||
/>
|
||||
</b-col>
|
||||
|
||||
@@ -8,8 +8,13 @@
|
||||
:label="$t('buttonLabel')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<b-form-input
|
||||
<c-input-expression
|
||||
v-model="button.label"
|
||||
auto-complete
|
||||
lang="javascript"
|
||||
:suggestion-params="recordAutoCompleteParams"
|
||||
:page="page"
|
||||
height="2.375rem"
|
||||
/>
|
||||
<i18next
|
||||
path="block:interpolationFootnote"
|
||||
@@ -94,6 +99,10 @@
|
||||
</template>
|
||||
<script>
|
||||
import { compose, NoID } from '@cortezaproject/corteza-js'
|
||||
import { components } from '@cortezaproject/corteza-vue'
|
||||
import autocomplete from 'corteza-webapp-compose/src/mixins/autocomplete.js'
|
||||
|
||||
const { CInputExpression } = components
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
@@ -101,6 +110,12 @@ export default {
|
||||
keyPrefix: 'automation',
|
||||
},
|
||||
|
||||
components: {
|
||||
CInputExpression,
|
||||
},
|
||||
|
||||
extends: autocomplete,
|
||||
|
||||
props: {
|
||||
button: {
|
||||
type: Object,
|
||||
@@ -128,6 +143,12 @@ export default {
|
||||
type: compose.PageBlock,
|
||||
required: true,
|
||||
},
|
||||
|
||||
module: {
|
||||
type: compose.Module,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import { compose } from '@cortezaproject/corteza-js'
|
||||
import { compose, NoID } from '@cortezaproject/corteza-js'
|
||||
import Wrap from './Wrap'
|
||||
|
||||
export default {
|
||||
@@ -106,6 +106,35 @@ export default {
|
||||
|
||||
return !!recordPageID || !!magnifiedBlockID
|
||||
},
|
||||
|
||||
isRecordPage () {
|
||||
return this.page && this.page.moduleID !== NoID
|
||||
},
|
||||
|
||||
recordAutoCompleteParams () {
|
||||
const { fields = [] } = this.module || {}
|
||||
const moduleFields = fields.map(({ name }) => name)
|
||||
const userProperties = this.$auth.user.properties() || []
|
||||
|
||||
const recordSuggestions = this.isRecordPage ? [
|
||||
...(['ownerID', 'recordID'].map(value => ({ interpolate: true, value }))),
|
||||
{
|
||||
interpolate: true,
|
||||
value: 'record',
|
||||
properties: [
|
||||
...(this.record.properties || []),
|
||||
{ value: 'values', properties: Object.keys(this.record.values) || [] },
|
||||
],
|
||||
},
|
||||
] : []
|
||||
|
||||
return [
|
||||
...moduleFields,
|
||||
...recordSuggestions,
|
||||
{ interpolate: true, value: 'userID' },
|
||||
{ interpolate: true, value: 'user', properties: userProperties },
|
||||
]
|
||||
},
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
|
||||
81
client/web/compose/src/mixins/autocomplete.js
Normal file
81
client/web/compose/src/mixins/autocomplete.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import { compose, NoID } from '@cortezaproject/corteza-js'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
record: {
|
||||
type: compose.Record,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
|
||||
page: {
|
||||
type: compose.Page,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
isRecordPage () {
|
||||
return this.page && this.page.moduleID !== NoID
|
||||
},
|
||||
|
||||
recordAutoCompleteParams () {
|
||||
return this.processRecordAutoCompleteParams({})
|
||||
},
|
||||
|
||||
visibilityAutoCompleteParams () {
|
||||
return this.processVisibilityAutoCompleteParams({})
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
processRecordAutoCompleteParams ({ module = this.module, operators = false }) {
|
||||
const { fields = [] } = module || {}
|
||||
const moduleFields = fields.map(({ name }) => name)
|
||||
const userProperties = this.$auth.user.properties() || []
|
||||
|
||||
const recordSuggestions = this.isRecordPage ? [
|
||||
...(['ownerID', 'recordID'].map(value => ({ interpolate: true, value }))),
|
||||
{
|
||||
interpolate: true,
|
||||
value: 'record',
|
||||
properties: [
|
||||
...(this.record.properties || []),
|
||||
{ value: 'values', properties: Object.keys(this.record.values) || [] },
|
||||
],
|
||||
},
|
||||
] : []
|
||||
|
||||
return [
|
||||
...moduleFields,
|
||||
...recordSuggestions,
|
||||
...(operators ? ['AND', 'OR'] : []),
|
||||
{ interpolate: true, value: 'userID' },
|
||||
{ interpolate: true, value: 'user', properties: userProperties },
|
||||
]
|
||||
},
|
||||
|
||||
processVisibilityAutoCompleteParams ({ module = this.module }) {
|
||||
const { fields = [] } = module || {}
|
||||
const moduleFields = fields.map(({ name }) => name)
|
||||
const userProperties = this.$auth.user.properties() || []
|
||||
|
||||
const recordSuggestions = this.isRecordPage ? [
|
||||
{
|
||||
value: 'record',
|
||||
properties: [
|
||||
...(this.record.properties || []),
|
||||
{ value: 'values', properties: Object.keys(this.record.values) || [] },
|
||||
],
|
||||
},
|
||||
] : []
|
||||
|
||||
return [
|
||||
...moduleFields,
|
||||
...recordSuggestions,
|
||||
{ value: 'user', properties: userProperties },
|
||||
{ value: 'screen', properties: ['width', 'height', 'userAgent', 'breakpoint'] },
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -8,6 +8,7 @@ module.exports = {
|
||||
extends: [
|
||||
'standard',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:vue/recommended',
|
||||
'@vue/standard'
|
||||
],
|
||||
rules: {
|
||||
|
||||
@@ -447,4 +447,28 @@ export class Record {
|
||||
get labels (): object {
|
||||
return this.meta
|
||||
}
|
||||
|
||||
get properties (): string[] {
|
||||
return [
|
||||
'recordID',
|
||||
'moduleID',
|
||||
'namespaceID',
|
||||
'revision',
|
||||
'meta',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
'deletedAt',
|
||||
'ownedBy',
|
||||
'createdBy',
|
||||
'updatedBy',
|
||||
'deletedBy',
|
||||
'canUpdateRecord',
|
||||
'canReadRecord',
|
||||
'canDeleteRecord',
|
||||
'canUndeleteRecord',
|
||||
'canManageOwnerOnRecord',
|
||||
'canSearchRevision',
|
||||
'canGrant',
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,4 +112,25 @@ export class User {
|
||||
clone (): User {
|
||||
return new User(JSON.parse(JSON.stringify(this)))
|
||||
}
|
||||
|
||||
properties (): string[] {
|
||||
return [
|
||||
'userID',
|
||||
'handle',
|
||||
'username',
|
||||
'email',
|
||||
'name',
|
||||
'emailConfirmed',
|
||||
'labels',
|
||||
'meta',
|
||||
'canGrant',
|
||||
'canUpdateUser',
|
||||
'canDeleteUser',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
'deletedAt',
|
||||
'suspendedAt',
|
||||
'roles',
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
"eslint-plugin-node": "11.0.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"eslint-plugin-vue": "6.1.2",
|
||||
"eslint-plugin-vue": "^9.21.1",
|
||||
"esm": "^3.2.25",
|
||||
"i18next-pseudo": "^2.2.1",
|
||||
"mocha": "7.0.0",
|
||||
|
||||
@@ -19,6 +19,7 @@ export {
|
||||
CInputCheckbox,
|
||||
CInputColorPicker,
|
||||
CAceEditor,
|
||||
CInputExpression,
|
||||
CButtonSubmit,
|
||||
CInputSelect,
|
||||
CInputRole,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class="position-relative"
|
||||
>
|
||||
<ace-editor
|
||||
ref="aceeditor"
|
||||
v-model="editorValue"
|
||||
:lang="lang"
|
||||
:mode="lang"
|
||||
@@ -30,7 +31,7 @@
|
||||
<script>
|
||||
import AceEditor from 'vue2-ace-editor'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faExpandAlt} from '@fortawesome/free-solid-svg-icons'
|
||||
import { faExpandAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(faExpandAlt)
|
||||
|
||||
@@ -79,7 +80,7 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
|
||||
autoComplete: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -96,9 +97,24 @@ export default {
|
||||
},
|
||||
|
||||
autoCompleteSuggestions: {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
}
|
||||
type: [Array, Object],
|
||||
default: () => ([]),
|
||||
},
|
||||
|
||||
initExpressions: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
|
||||
fontFamily: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
@@ -122,7 +138,7 @@ export default {
|
||||
require('brace/mode/json')
|
||||
require('brace/mode/javascript')
|
||||
require('brace/mode/json')
|
||||
|
||||
|
||||
require('brace/snippets/text')
|
||||
require('brace/snippets/html')
|
||||
require('brace/snippets/css')
|
||||
@@ -147,33 +163,140 @@ export default {
|
||||
useWorker: false,
|
||||
readOnly: this.readOnly,
|
||||
highlightActiveLine: this.highlightActiveLine,
|
||||
cursorStyle: 'smooth',
|
||||
// // minLines: this.height,
|
||||
// maxPixelHeight: 100,
|
||||
|
||||
...(this.autoComplete && {
|
||||
enableBasicAutocompletion: true,
|
||||
enableLiveAutocompletion: true,
|
||||
enableSnippets: true,
|
||||
enableEmmet: true
|
||||
enableEmmet: true,
|
||||
}),
|
||||
})
|
||||
|
||||
const self = this;
|
||||
const staticWordCompleter = {
|
||||
getCompletions: function (editor, session, pos, prefix, callback) {
|
||||
var autoCompleteSuggestions = self.autoCompleteSuggestions;
|
||||
callback(
|
||||
null,
|
||||
autoCompleteSuggestions.map(function ({ caption, value, meta }) {
|
||||
return {
|
||||
caption,
|
||||
value,
|
||||
meta,
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
editor.completers.push(staticWordCompleter);
|
||||
...(this.fontFamily && { fontFamily: this.fontFamily }),
|
||||
...(this.fontSize && { fontSize: this.fontSize }),
|
||||
})
|
||||
|
||||
editor.on('input', this.updatePlaceholder)
|
||||
this.updatePlaceholder(undefined, editor)
|
||||
|
||||
if (this.initExpressions) {
|
||||
this.processExpressionAutoComplete(editor)
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const self = this
|
||||
const staticWordCompleter = {
|
||||
getCompletions: function (editor, session, pos, prefix, callback) {
|
||||
const autoCompleteSuggestions = self.autoCompleteSuggestions
|
||||
callback(
|
||||
null,
|
||||
autoCompleteSuggestions.map(function ({ caption, value, meta }) {
|
||||
return {
|
||||
caption,
|
||||
value,
|
||||
meta,
|
||||
}
|
||||
}),
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
editor.completers.push(staticWordCompleter)
|
||||
}
|
||||
},
|
||||
|
||||
updatePlaceholder (_, editor) {
|
||||
if (!this.placeholder) return
|
||||
|
||||
const shouldShow = !editor.session.getValue().length
|
||||
let node = editor.renderer.emptyMessageNode
|
||||
|
||||
if (!shouldShow && node) {
|
||||
editor.renderer.scroller.removeChild(editor.renderer.emptyMessageNode)
|
||||
editor.renderer.emptyMessageNode = null
|
||||
} else if (shouldShow && !node) {
|
||||
node = editor.renderer.emptyMessageNode = document.createElement('div')
|
||||
node.textContent = this.placeholder
|
||||
node.className = 'ace_placeholder'
|
||||
node.style.padding = '7px 10px'
|
||||
node.style.position = 'absolute'
|
||||
node.style.zIndex = 9
|
||||
node.style.opacity = 0.5
|
||||
editor.renderer.scroller.appendChild(node)
|
||||
}
|
||||
},
|
||||
|
||||
processExpressionAutoComplete (editor) {
|
||||
const staticWordCompleter = {
|
||||
getCompletions: (editor, session, pos, prefix, callback) => {
|
||||
const context = this.getContext(editor, session, pos)
|
||||
const suggestions = this.getSuggestionsForContext(context)
|
||||
|
||||
callback(null, suggestions.map(suggestion => {
|
||||
let caption = ''
|
||||
let value = ''
|
||||
|
||||
if (typeof suggestion === 'string') {
|
||||
caption = suggestion
|
||||
value = suggestion
|
||||
} else {
|
||||
caption = suggestion.caption
|
||||
value = suggestion.value
|
||||
}
|
||||
|
||||
return {
|
||||
caption,
|
||||
value,
|
||||
meta: 'variable',
|
||||
completer: {
|
||||
insertMatch: function (insertEditor, data) {
|
||||
const insertValue = data.value
|
||||
|
||||
insertEditor.jumpToMatching()
|
||||
const line = session.getLine(pos.row)
|
||||
let lastSpaceIndex = line.lastIndexOf(' ') >= 0 ? line.lastIndexOf(' ') : 0
|
||||
|
||||
if (lastSpaceIndex > 0) {
|
||||
lastSpaceIndex += 1
|
||||
}
|
||||
|
||||
insertEditor.session.replace({
|
||||
start: { row: pos.row, column: lastSpaceIndex },
|
||||
end: { row: pos.row, column: pos.column },
|
||||
}, insertValue)
|
||||
},
|
||||
},
|
||||
}
|
||||
}))
|
||||
},
|
||||
}
|
||||
|
||||
editor.completers = [staticWordCompleter]
|
||||
|
||||
editor.commands.on('afterExec', function (e) {
|
||||
if (['insertstring', 'Return'].includes(e.command.name) || /^[\w.($]$/.test(e.args)) {
|
||||
editor.execCommand('startAutocomplete')
|
||||
}
|
||||
})
|
||||
|
||||
editor.renderer.setScrollMargin(7, 7)
|
||||
editor.renderer.setPadding(10)
|
||||
},
|
||||
|
||||
getContext (editor, session, pos) {
|
||||
const line = session.getLine(pos.row)
|
||||
const lastSpaceIndex = line.lastIndexOf(' ') >= 0 ? line.lastIndexOf(' ') : 0
|
||||
const textBeforeCursor = line.slice(lastSpaceIndex, pos.column)
|
||||
const context = textBeforeCursor.split('.').slice(0, -1).join('.').trim()
|
||||
|
||||
return context
|
||||
},
|
||||
|
||||
getSuggestionsForContext (context) {
|
||||
const suggestions = this.autoCompleteSuggestions
|
||||
|
||||
return suggestions[context] || []
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
163
lib/vue/src/components/input/CInputExpression.vue
Normal file
163
lib/vue/src/components/input/CInputExpression.vue
Normal file
@@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<div
|
||||
class="position-relative"
|
||||
>
|
||||
<c-ace-editor
|
||||
v-model="editorValue"
|
||||
auto-complete
|
||||
init-expressions
|
||||
:auto-complete-suggestions="autoCompleteSuggestions"
|
||||
v-bind="{ ...$attrs, ...$props }"
|
||||
v-on="$listeners"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CAceEditor from './CAceEditor.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CAceEditor,
|
||||
},
|
||||
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
|
||||
lang: {
|
||||
type: String,
|
||||
default: 'text',
|
||||
},
|
||||
|
||||
height: {
|
||||
type: String,
|
||||
default: '80px',
|
||||
},
|
||||
|
||||
showLineNumbers: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
fontSize: {
|
||||
type: String,
|
||||
default: '14px',
|
||||
},
|
||||
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
|
||||
showPopout: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
highlightActiveLine: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
showPrintMargin: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
|
||||
suggestionParams: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
|
||||
fontFamily: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
editorValue: {
|
||||
get () {
|
||||
return this.value
|
||||
},
|
||||
|
||||
set (value = '') {
|
||||
this.$emit('update:value', value)
|
||||
},
|
||||
},
|
||||
|
||||
autoCompleteSuggestions () {
|
||||
return this.getRecordBasedSuggestions(this.suggestionParams)
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
getRecordBasedSuggestions (params = []) {
|
||||
const result = {}
|
||||
|
||||
function addSuggestion (key, caption, value) {
|
||||
if (!result[key]) result[key] = []
|
||||
result[key].push({ caption: caption, value: value })
|
||||
}
|
||||
|
||||
function processProperties (prefix, properties, interpolate) {
|
||||
(properties || []).forEach((prop) => {
|
||||
if (typeof prop === 'string') {
|
||||
const value = prefix + '.' + prop + (interpolate ? '}' : '')
|
||||
addSuggestion(prefix, prop, value)
|
||||
} else {
|
||||
const nestedPrefix = prefix + '.' + prop.value + '.'
|
||||
addSuggestion(prefix, prop.value, nestedPrefix)
|
||||
|
||||
if (prop.properties) {
|
||||
(prop.properties || []).forEach((nestedProp) => {
|
||||
const nestedValue = nestedPrefix + nestedProp + (interpolate ? '}' : '')
|
||||
addSuggestion(prefix + '.' + prop.value, nestedProp, nestedValue)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
(params || []).forEach((p) => {
|
||||
if (typeof p === 'string') {
|
||||
addSuggestion('', '', p)
|
||||
} else {
|
||||
const { interpolate = false, properties = [], value, root = true } = p
|
||||
const prefix = interpolate ? '${' : ''
|
||||
const suffix = interpolate && !properties.length ? '}' : ''
|
||||
const prefixAsValue = prefix + value + suffix + (properties.length > 0 ? '.' : '')
|
||||
|
||||
if (root) {
|
||||
addSuggestion('', '', prefixAsValue)
|
||||
}
|
||||
|
||||
if (interpolate) {
|
||||
addSuggestion('$', prefixAsValue.slice(1), prefixAsValue)
|
||||
addSuggestion('${', prefixAsValue.slice(2), prefixAsValue)
|
||||
}
|
||||
|
||||
if (properties.length) {
|
||||
processProperties(prefix + value, properties, interpolate)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -8,6 +8,7 @@ export { default as CRichTextInput } from './CRichTextInput/index.vue'
|
||||
export { default as CInputCheckbox } from './CInputCheckbox.vue'
|
||||
export { default as CInputColorPicker } from './CInputColorPicker.vue'
|
||||
export { default as CAceEditor } from './CAceEditor.vue'
|
||||
export { default as CInputExpression } from './CInputExpression.vue'
|
||||
export {
|
||||
CButtonSubmit,
|
||||
} from './button'
|
||||
|
||||
@@ -2209,7 +2209,7 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
|
||||
mime-types "~2.1.24"
|
||||
negotiator "0.6.2"
|
||||
|
||||
acorn-jsx@^5.2.0, acorn-jsx@^5.3.2:
|
||||
acorn-jsx@^5.3.2:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||
@@ -4708,13 +4708,19 @@ eslint-plugin-standard@^4.0.1:
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz#0c3bf3a67e853f8bbbc580fb4945fbf16f41b7c5"
|
||||
integrity sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ==
|
||||
|
||||
eslint-plugin-vue@6.1.2:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-6.1.2.tgz#4b05c28c83c0ec912669b64dbd998bb8bf692ef6"
|
||||
integrity sha512-M75oAB+2a/LNkLKRbeEaS07EjzjIUaV7/hYoHAfRFeeF8ZMmCbahUn8nQLsLP85mkar24+zDU3QW2iT1JRsACw==
|
||||
eslint-plugin-vue@^9.21.1:
|
||||
version "9.27.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.27.0.tgz#c22dae704a03d9ecefa81364ff89f60ce0481f94"
|
||||
integrity sha512-5Dw3yxEyuBSXTzT5/Ge1X5kIkRTQ3nvBn/VwPwInNiZBSJOO/timWMUaflONnFBzU6NhB68lxnCda7ULV5N7LA==
|
||||
dependencies:
|
||||
semver "^5.6.0"
|
||||
vue-eslint-parser "^7.0.0"
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
globals "^13.24.0"
|
||||
natural-compare "^1.4.0"
|
||||
nth-check "^2.1.1"
|
||||
postcss-selector-parser "^6.0.15"
|
||||
semver "^7.6.0"
|
||||
vue-eslint-parser "^9.4.3"
|
||||
xml-name-validator "^4.0.0"
|
||||
|
||||
eslint-scope@^4.0.3:
|
||||
version "4.0.3"
|
||||
@@ -4724,7 +4730,7 @@ eslint-scope@^4.0.3:
|
||||
esrecurse "^4.1.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-scope@^5.0.0, eslint-scope@^5.1.1:
|
||||
eslint-scope@^5.0.0:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
||||
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
|
||||
@@ -4806,15 +4812,6 @@ esm@^3.2.25:
|
||||
resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
|
||||
integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
|
||||
|
||||
espree@^6.2.1:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a"
|
||||
integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==
|
||||
dependencies:
|
||||
acorn "^7.1.1"
|
||||
acorn-jsx "^5.2.0"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
|
||||
espree@^9.3.1, espree@^9.6.0, espree@^9.6.1:
|
||||
version "9.6.1"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
|
||||
@@ -5595,7 +5592,7 @@ globals@^11.1.0:
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
|
||||
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
|
||||
|
||||
globals@^13.19.0:
|
||||
globals@^13.19.0, globals@^13.24.0:
|
||||
version "13.24.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171"
|
||||
integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==
|
||||
@@ -7916,6 +7913,13 @@ nth-check@^2.0.1:
|
||||
dependencies:
|
||||
boolbase "^1.0.0"
|
||||
|
||||
nth-check@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
|
||||
integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
|
||||
dependencies:
|
||||
boolbase "^1.0.0"
|
||||
|
||||
num2fraction@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
|
||||
@@ -9113,6 +9117,14 @@ postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
|
||||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
postcss-selector-parser@^6.0.15:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de"
|
||||
integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==
|
||||
dependencies:
|
||||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9:
|
||||
version "6.0.9"
|
||||
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f"
|
||||
@@ -10246,6 +10258,11 @@ semver@^7.5.4:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@^7.6.0:
|
||||
version "7.6.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
|
||||
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
|
||||
|
||||
send@0.17.2:
|
||||
version "0.17.2"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820"
|
||||
@@ -11714,19 +11731,6 @@ vue-echarts@6.7.3:
|
||||
resize-detector "^0.3.0"
|
||||
vue-demi "^0.13.11"
|
||||
|
||||
vue-eslint-parser@^7.0.0:
|
||||
version "7.11.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz#214b5dea961007fcffb2ee65b8912307628d0daf"
|
||||
integrity sha512-qh3VhDLeh773wjgNTl7ss0VejY9bMMa0GoDG2fQVyDzRFdiU3L7fw74tWZDHNQXdZqxO3EveQroa9ct39D2nqg==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
eslint-scope "^5.1.1"
|
||||
eslint-visitor-keys "^1.1.0"
|
||||
espree "^6.2.1"
|
||||
esquery "^1.4.0"
|
||||
lodash "^4.17.21"
|
||||
semver "^6.3.0"
|
||||
|
||||
vue-eslint-parser@^9.3.2:
|
||||
version "9.3.2"
|
||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz#6f9638e55703f1c77875a19026347548d93fd499"
|
||||
@@ -11740,6 +11744,19 @@ vue-eslint-parser@^9.3.2:
|
||||
lodash "^4.17.21"
|
||||
semver "^7.3.6"
|
||||
|
||||
vue-eslint-parser@^9.4.3:
|
||||
version "9.4.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz#9b04b22c71401f1e8bca9be7c3e3416a4bde76a8"
|
||||
integrity sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==
|
||||
dependencies:
|
||||
debug "^4.3.4"
|
||||
eslint-scope "^7.1.1"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
espree "^9.3.1"
|
||||
esquery "^1.4.0"
|
||||
lodash "^4.17.21"
|
||||
semver "^7.3.6"
|
||||
|
||||
vue-functional-data-merge@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-functional-data-merge/-/vue-functional-data-merge-3.1.0.tgz#08a7797583b7f35680587f8a1d51d729aa1dc657"
|
||||
@@ -12167,6 +12184,11 @@ xdg-basedir@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
|
||||
integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
|
||||
|
||||
xml-name-validator@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835"
|
||||
integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==
|
||||
|
||||
xtend@^4.0.0, xtend@~4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
|
||||
Reference in New Issue
Block a user