Add cancel buttons to all prompts
This commit is contained in:
parent
27e142c1a6
commit
3708ca9f32
@ -6,6 +6,7 @@
|
|||||||
:hide-footer="!current"
|
:hide-footer="!current"
|
||||||
:title="current ? current.title : 'Workflow prompts'"
|
:title="current ? current.title : 'Workflow prompts'"
|
||||||
:busy="isLoading"
|
:busy="isLoading"
|
||||||
|
footer-class="d-flex"
|
||||||
no-fade
|
no-fade
|
||||||
@hide="deactivate()"
|
@hide="deactivate()"
|
||||||
>
|
>
|
||||||
@ -20,29 +21,22 @@
|
|||||||
v-else
|
v-else
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="d-flex flex-grow-1 align-items-baseline"
|
class="d-flex flex-grow-1 align-items-baseline mb-2"
|
||||||
v-for="({ key, title, age, prompt }) in list"
|
v-for="({ key, title, age, prompt }) in list"
|
||||||
:key="key"
|
:key="key"
|
||||||
>
|
>
|
||||||
<span
|
<a
|
||||||
class="mr-auto"
|
class="p-0 mr-auto"
|
||||||
@click="activate(prompt)"
|
@click="activate(prompt)"
|
||||||
>
|
>
|
||||||
{{ title }}
|
{{ title }} -
|
||||||
<time
|
<time
|
||||||
class="muted small"
|
class="muted small"
|
||||||
:datetime="prompt.createdAt"
|
:datetime="prompt.createdAt"
|
||||||
>
|
>
|
||||||
{{ age }}
|
{{ age }}
|
||||||
</time>
|
</time>
|
||||||
</span>
|
</a>
|
||||||
<b-button
|
|
||||||
variant="link"
|
|
||||||
size="sm"
|
|
||||||
@click="remove(prompt)"
|
|
||||||
:disabled="isLoading"
|
|
||||||
v-if="false"
|
|
||||||
>Remove</b-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template
|
<template
|
||||||
@ -51,6 +45,7 @@
|
|||||||
>
|
>
|
||||||
<b-button
|
<b-button
|
||||||
variant="link"
|
variant="link"
|
||||||
|
class="mr-auto"
|
||||||
@click="activate(true)"
|
@click="activate(true)"
|
||||||
>
|
>
|
||||||
« Back to list
|
« Back to list
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div v-if="!hideToasts">
|
||||||
<b-toast
|
<b-toast
|
||||||
v-for="({ prompt, component, passive }) in toasts"
|
v-for="({ prompt, component, passive }) in toasts"
|
||||||
:id="'wfPromptToast-'+prompt.stateID"
|
:id="'wfPromptToast-'+prompt.stateID"
|
||||||
@ -9,21 +9,12 @@
|
|||||||
solid
|
solid
|
||||||
:no-auto-hide="!passive"
|
:no-auto-hide="!passive"
|
||||||
:auto-hide-delay="pVal(prompt, 'timeout', defaultTimeout) * 1000"
|
:auto-hide-delay="pVal(prompt, 'timeout', defaultTimeout) * 1000"
|
||||||
:no-close-button="!passive"
|
@hide="onToastHide({ prompt, passive })"
|
||||||
>
|
>
|
||||||
<template #toast-title>
|
<template #toast-title>
|
||||||
<div class="d-flex flex-grow-1 align-items-baseline">
|
<strong>{{ pVal(prompt, 'title', 'Workflow prompt') }}</strong>
|
||||||
<strong class="mr-auto">{{ pVal(prompt, 'title', 'Workflow prompt') }}</strong>
|
|
||||||
<b-button
|
|
||||||
variant="link"
|
|
||||||
size="sm"
|
|
||||||
v-if="!passive && active.length > 1"
|
|
||||||
@click="activate(true)"
|
|
||||||
>
|
|
||||||
{{ active.length }} waiting
|
|
||||||
</b-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<component
|
<component
|
||||||
v-if="component"
|
v-if="component"
|
||||||
:is="component"
|
:is="component"
|
||||||
@ -52,12 +43,6 @@ export default {
|
|||||||
return {
|
return {
|
||||||
passive: new Set(),
|
passive: new Set(),
|
||||||
|
|
||||||
/**
|
|
||||||
* Set initial value to NULL
|
|
||||||
*
|
|
||||||
* First interval will detect that null is not true|false
|
|
||||||
* and set it accordingly to the current state
|
|
||||||
*/
|
|
||||||
hasFocus: null,
|
hasFocus: null,
|
||||||
hasFocusObserver: 0,
|
hasFocusObserver: 0,
|
||||||
}
|
}
|
||||||
@ -163,6 +148,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
...mapActions({
|
...mapActions({
|
||||||
resume: 'wfPrompts/resume',
|
resume: 'wfPrompts/resume',
|
||||||
|
cancel: 'wfPrompts/cancel',
|
||||||
activate: 'wfPrompts/activate',
|
activate: 'wfPrompts/activate',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@ -175,6 +161,12 @@ export default {
|
|||||||
this.resume(values)
|
this.resume(values)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onToastHide ({ prompt, passive}) {
|
||||||
|
if (passive) return
|
||||||
|
|
||||||
|
this.cancel(prompt)
|
||||||
|
},
|
||||||
|
|
||||||
pVal (prompt, k, def = undefined) {
|
pVal (prompt, k, def = undefined) {
|
||||||
return pVal(prompt.payload, k, def)
|
return pVal(prompt.payload, k, def)
|
||||||
},
|
},
|
||||||
@ -200,7 +192,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
setDefaultValues () {
|
setDefaultValues () {
|
||||||
this.passive.clear()
|
this.toasts = []
|
||||||
this.hasFocus = null
|
this.hasFocus = null
|
||||||
this.hasFocusObserver = 0
|
this.hasFocusObserver = 0
|
||||||
},
|
},
|
||||||
@ -208,16 +200,58 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style lang="scss">
|
||||||
.slide-enter-active {
|
.toast-header {
|
||||||
transition: all .3s ease;
|
align-items: start;
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
|
||||||
|
strong {
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.slide-leave-active {
|
|
||||||
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
|
// .b-toaster-leave-active {
|
||||||
|
// width: 100%;
|
||||||
|
// }
|
||||||
|
|
||||||
|
.b-toaster {
|
||||||
|
&.b-toaster-top-right,
|
||||||
|
&.b-toaster-top-left,
|
||||||
|
&.b-toaster-bottom-right,
|
||||||
|
&.b-toaster-bottom-left {
|
||||||
|
.b-toast {
|
||||||
|
&.b-toaster-enter-active,
|
||||||
|
&.b-toaster-leave-active,
|
||||||
|
&.b-toaster-move {
|
||||||
|
transition: transform 0.3s ease-in-out; /* Adjust the timing function for smoother transitions */
|
||||||
|
opacity: 1; /* Ensure opacity is set to avoid flickering during transition */
|
||||||
|
}
|
||||||
|
|
||||||
|
&.b-toaster-enter {
|
||||||
|
transform: translate(0, -100%); /* Start off-screen when entering */
|
||||||
|
opacity: 0; /* Start with 0 opacity */
|
||||||
|
}
|
||||||
|
|
||||||
|
&.b-toaster-enter-to,
|
||||||
|
&.b-toaster-enter-active {
|
||||||
|
transform: translate(0, 0); /* Move to the visible position */
|
||||||
|
opacity: 1; /* Fade in during the transition */
|
||||||
|
}
|
||||||
|
|
||||||
|
&.b-toaster-leave-active {
|
||||||
|
position: absolute;
|
||||||
|
transform: translate(0, -100%); /* Move off-screen when leaving */
|
||||||
|
opacity: 0; /* Fade out during the transition */
|
||||||
|
}
|
||||||
|
|
||||||
|
&.b-toaster-leave-to {
|
||||||
|
opacity: 0; /* Ensure 0 opacity at the end of the transition */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.slide-enter, .slide-leave-to
|
</style>
|
||||||
/* .slide-leave-active below version 2.1.8 */ {
|
|
||||||
transform: translateX(10px);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,9 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p v-html="message"></p>
|
<p v-if="!!message" v-html="message" />
|
||||||
<div
|
|
||||||
class="text-center m-2"
|
<div class="d-flex justify-content-end gap-1">
|
||||||
>
|
|
||||||
<b-button
|
<b-button
|
||||||
@click="$emit('submit', { confirmed: pRaw('buttonValue', true, 'Boolean') })"
|
@click="$emit('submit', { confirmed: pRaw('buttonValue', true, 'Boolean') })"
|
||||||
:variant="pVal('buttonVariant', 'primary')"
|
:variant="pVal('buttonVariant', 'primary')"
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p v-html="message"></p>
|
<p v-if="!!message" v-html="message" />
|
||||||
<div
|
|
||||||
class="text-center m-2"
|
<div class="d-flex align-items-between justify-content-center gap-2">
|
||||||
>
|
|
||||||
<b-button
|
<b-button
|
||||||
@click="$emit('submit', { value: pRaw('confirmButtonValue', true, 'Boolean') })"
|
@click="$emit('submit', { value: pRaw('confirmButtonValue', true, 'Boolean') })"
|
||||||
:variant="pVal('confirmButtonVariant', 'primary')"
|
:variant="pVal('confirmButtonVariant', 'primary')"
|
||||||
@ -11,10 +10,11 @@
|
|||||||
>
|
>
|
||||||
{{ pVal('confirmButtonLabel', 'Yes') }}
|
{{ pVal('confirmButtonLabel', 'Yes') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
|
|
||||||
<b-button
|
<b-button
|
||||||
@click="$emit('submit', { value: pRaw('rejectButtonValue', false, 'Boolean') })"
|
@click="$emit('submit', { value: pRaw('rejectButtonValue', false, 'Boolean') })"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
:variant="pVal('rejectButtonVariant', 'primary')"
|
:variant="pVal('rejectButtonVariant', 'light')"
|
||||||
>
|
>
|
||||||
{{ pVal('rejectButtonLabel', 'No') }}
|
{{ pVal('rejectButtonLabel', 'No') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
|
|||||||
@ -1,22 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p v-if="!!message" v-html="message" />
|
||||||
{{ message }}
|
|
||||||
</p>
|
<div class="d-flex flex-column gap-1">
|
||||||
<div
|
|
||||||
class="text-center m-2"
|
|
||||||
>
|
|
||||||
<c-input-select
|
<c-input-select
|
||||||
v-model="value"
|
v-model="value"
|
||||||
:options="options"
|
:options="options"
|
||||||
:get-option-key="getOptionKey"
|
:get-option-key="getOptionKey"
|
||||||
:loading="processing"
|
:loading="processing"
|
||||||
append-to-body
|
append-to-body
|
||||||
:calculate-position="calculateDropdownPosition"
|
|
||||||
option-value="recordID"
|
option-value="recordID"
|
||||||
option-text="label"
|
option-text="label"
|
||||||
placeholder="Select record"
|
placeholder="Select record"
|
||||||
:filterable="false"
|
:filterable="false"
|
||||||
|
:reduce="r => r.recordID"
|
||||||
class="w-100 mb-3"
|
class="w-100 mb-3"
|
||||||
@search="search"
|
@search="search"
|
||||||
>
|
>
|
||||||
@ -31,8 +28,10 @@
|
|||||||
</c-input-select>
|
</c-input-select>
|
||||||
|
|
||||||
<b-button
|
<b-button
|
||||||
@click="$emit('submit', { value: encodeValue() })"
|
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
|
variant="primary"
|
||||||
|
class="ml-auto"
|
||||||
|
@click="$emit('submit', { value: encodeValue() })"
|
||||||
>
|
>
|
||||||
{{ pVal('buttonLabel', 'Submit') }}
|
{{ pVal('buttonLabel', 'Submit') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
@ -45,7 +44,6 @@ import CPagination from '../common/CPagination.vue'
|
|||||||
import { pVal } from '../utils.ts'
|
import { pVal } from '../utils.ts'
|
||||||
import CInputSelect from '../../input/CInputSelect.vue'
|
import CInputSelect from '../../input/CInputSelect.vue'
|
||||||
import { compose, NoID } from '@cortezaproject/corteza-js'
|
import { compose, NoID } from '@cortezaproject/corteza-js'
|
||||||
import { createPopper } from '@popperjs/core'
|
|
||||||
import { debounce } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -79,12 +77,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
// moduleFields returns the available field names
|
labelField () {
|
||||||
moduleFields () {
|
return this.module.fields.find(f => f.name === this.pVal('labelField'))
|
||||||
if (!this.module) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return this.module.fields.map(({ name }) => name)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
showPagination () {
|
showPagination () {
|
||||||
@ -165,7 +159,9 @@ export default {
|
|||||||
return { '@type': 'Any', '@value': null }
|
return { '@type': 'Any', '@value': null }
|
||||||
}
|
}
|
||||||
|
|
||||||
return { '@type': 'ComposeRecord', '@value': this.value.record }
|
const record = this.options.find(({ recordID }) => recordID === this.value)
|
||||||
|
|
||||||
|
return { '@type': 'ComposeRecord', '@value': record }
|
||||||
},
|
},
|
||||||
|
|
||||||
loadLatest () {
|
loadLatest () {
|
||||||
@ -206,51 +202,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}, 300),
|
}, 300),
|
||||||
|
|
||||||
calculateDropdownPosition (dropdownList, component, { width }) {
|
|
||||||
/**
|
|
||||||
* We need to explicitly define the dropdown width since
|
|
||||||
* it is usually inherited from the parent with CSS.
|
|
||||||
*/
|
|
||||||
dropdownList.style.width = width
|
|
||||||
dropdownList.style['z-index'] = 10000
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Here we position the dropdownList relative to the $refs.toggle Element.
|
|
||||||
*
|
|
||||||
* The 'offset' modifier aligns the dropdown so that the $refs.toggle and
|
|
||||||
* the dropdownList overlap by 1 pixel.
|
|
||||||
*
|
|
||||||
* The 'toggleClass' modifier adds a 'drop-up' class to the Vue Select
|
|
||||||
* wrapper so that we can set some styles for when the dropdown is placed
|
|
||||||
* above.
|
|
||||||
*/
|
|
||||||
const popper = createPopper(component.$refs.toggle, dropdownList, {
|
|
||||||
placement: 'bottom',
|
|
||||||
modifiers: [
|
|
||||||
{
|
|
||||||
name: 'offset',
|
|
||||||
options: {
|
|
||||||
offset: [0, -1],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'toggleClass',
|
|
||||||
enabled: true,
|
|
||||||
phase: 'write',
|
|
||||||
fn ({ state }) {
|
|
||||||
component.$el.classList.toggle('drop-up', state.placement === 'top')
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To prevent memory leaks Popper needs to be destroyed.
|
|
||||||
* If you return function, it will be called just before dropdown is removed from DOM.
|
|
||||||
*/
|
|
||||||
return () => popper.destroy()
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
fetchPrefiltered (q) {
|
fetchPrefiltered (q) {
|
||||||
this.processing = true
|
this.processing = true
|
||||||
|
|
||||||
@ -273,11 +224,15 @@ export default {
|
|||||||
|
|
||||||
this.options = set.map(r => {
|
this.options = set.map(r => {
|
||||||
const record = new compose.Record(this.module, r)
|
const record = new compose.Record(this.module, r)
|
||||||
const label = record.values[this.pVal('labelField')] || record.recordID
|
|
||||||
|
let label
|
||||||
|
if (this.labelField) {
|
||||||
|
label = this.labelField.isMulti ? record.values[this.pVal('labelField')].join(', ') : record.values[this.pVal('labelField')]
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
recordID: record.recordID,
|
recordID: record.recordID,
|
||||||
label,
|
label: label || record.recordID,
|
||||||
record,
|
record,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p v-html="message"></p>
|
<p v-if="!!message" v-html="message" />
|
||||||
|
|
||||||
<b-form-group
|
<b-form-group
|
||||||
:label="label"
|
:label="label"
|
||||||
label-class="text-primary"
|
label-class="text-primary"
|
||||||
@ -13,6 +14,7 @@
|
|||||||
</b-form-group>
|
</b-form-group>
|
||||||
<b-button
|
<b-button
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
|
variant="primary"
|
||||||
@click="$emit('submit', { value: { '@value': value, '@type': 'String' }})"
|
@click="$emit('submit', { value: { '@value': value, '@type': 'String' }})"
|
||||||
>
|
>
|
||||||
{{ pVal('buttonLabel', 'Submit') }}
|
{{ pVal('buttonLabel', 'Submit') }}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p v-html="message"></p>
|
<p v-if="!!message" v-html="message" />
|
||||||
|
|
||||||
<b-form-group
|
<b-form-group
|
||||||
:label="pVal('label', 'Input')"
|
:label="pVal('label', 'Input')"
|
||||||
label-class="text-primary"
|
label-class="text-primary"
|
||||||
@ -28,8 +29,10 @@
|
|||||||
:options="options"
|
:options="options"
|
||||||
/>
|
/>
|
||||||
</b-form-group>
|
</b-form-group>
|
||||||
|
|
||||||
<b-button
|
<b-button
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
|
variant="primary"
|
||||||
@click="$emit('submit', { value: encodeValue() })"
|
@click="$emit('submit', { value: encodeValue() })"
|
||||||
>
|
>
|
||||||
{{ pVal('buttonLabel', 'Submit') }}
|
{{ pVal('buttonLabel', 'Submit') }}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ export default {
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
message () {
|
message () {
|
||||||
return this.pVal('message', '<i>Default prompt message.</i>')
|
return this.pVal('message', '')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user