Add cancel buttons to all prompts
This commit is contained in:
parent
27e142c1a6
commit
3708ca9f32
@ -6,6 +6,7 @@
|
||||
:hide-footer="!current"
|
||||
:title="current ? current.title : 'Workflow prompts'"
|
||||
:busy="isLoading"
|
||||
footer-class="d-flex"
|
||||
no-fade
|
||||
@hide="deactivate()"
|
||||
>
|
||||
@ -20,29 +21,22 @@
|
||||
v-else
|
||||
>
|
||||
<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"
|
||||
:key="key"
|
||||
>
|
||||
<span
|
||||
class="mr-auto"
|
||||
<a
|
||||
class="p-0 mr-auto"
|
||||
@click="activate(prompt)"
|
||||
>
|
||||
{{ title }}
|
||||
{{ title }} -
|
||||
<time
|
||||
class="muted small"
|
||||
:datetime="prompt.createdAt"
|
||||
>
|
||||
{{ age }}
|
||||
</time>
|
||||
</span>
|
||||
<b-button
|
||||
variant="link"
|
||||
size="sm"
|
||||
@click="remove(prompt)"
|
||||
:disabled="isLoading"
|
||||
v-if="false"
|
||||
>Remove</b-button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<template
|
||||
@ -51,6 +45,7 @@
|
||||
>
|
||||
<b-button
|
||||
variant="link"
|
||||
class="mr-auto"
|
||||
@click="activate(true)"
|
||||
>
|
||||
« Back to list
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="!hideToasts">
|
||||
<b-toast
|
||||
v-for="({ prompt, component, passive }) in toasts"
|
||||
:id="'wfPromptToast-'+prompt.stateID"
|
||||
@ -9,21 +9,12 @@
|
||||
solid
|
||||
:no-auto-hide="!passive"
|
||||
:auto-hide-delay="pVal(prompt, 'timeout', defaultTimeout) * 1000"
|
||||
:no-close-button="!passive"
|
||||
@hide="onToastHide({ prompt, passive })"
|
||||
>
|
||||
<template #toast-title>
|
||||
<div class="d-flex flex-grow-1 align-items-baseline">
|
||||
<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>
|
||||
<strong>{{ pVal(prompt, 'title', 'Workflow prompt') }}</strong>
|
||||
</template>
|
||||
|
||||
<component
|
||||
v-if="component"
|
||||
:is="component"
|
||||
@ -52,12 +43,6 @@ export default {
|
||||
return {
|
||||
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,
|
||||
hasFocusObserver: 0,
|
||||
}
|
||||
@ -163,6 +148,7 @@ export default {
|
||||
methods: {
|
||||
...mapActions({
|
||||
resume: 'wfPrompts/resume',
|
||||
cancel: 'wfPrompts/cancel',
|
||||
activate: 'wfPrompts/activate',
|
||||
}),
|
||||
|
||||
@ -175,6 +161,12 @@ export default {
|
||||
this.resume(values)
|
||||
},
|
||||
|
||||
onToastHide ({ prompt, passive}) {
|
||||
if (passive) return
|
||||
|
||||
this.cancel(prompt)
|
||||
},
|
||||
|
||||
pVal (prompt, k, def = undefined) {
|
||||
return pVal(prompt.payload, k, def)
|
||||
},
|
||||
@ -200,7 +192,7 @@ export default {
|
||||
},
|
||||
|
||||
setDefaultValues () {
|
||||
this.passive.clear()
|
||||
this.toasts = []
|
||||
this.hasFocus = null
|
||||
this.hasFocusObserver = 0
|
||||
},
|
||||
@ -208,16 +200,58 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.slide-enter-active {
|
||||
transition: all .3s ease;
|
||||
<style lang="scss">
|
||||
.toast-header {
|
||||
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
|
||||
/* .slide-leave-active below version 2.1.8 */ {
|
||||
transform: translateX(10px);
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@ -1,9 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<p v-html="message"></p>
|
||||
<div
|
||||
class="text-center m-2"
|
||||
>
|
||||
<p v-if="!!message" v-html="message" />
|
||||
|
||||
<div class="d-flex justify-content-end gap-1">
|
||||
<b-button
|
||||
@click="$emit('submit', { confirmed: pRaw('buttonValue', true, 'Boolean') })"
|
||||
:variant="pVal('buttonVariant', 'primary')"
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<p v-html="message"></p>
|
||||
<div
|
||||
class="text-center m-2"
|
||||
>
|
||||
<p v-if="!!message" v-html="message" />
|
||||
|
||||
<div class="d-flex align-items-between justify-content-center gap-2">
|
||||
<b-button
|
||||
@click="$emit('submit', { value: pRaw('confirmButtonValue', true, 'Boolean') })"
|
||||
:variant="pVal('confirmButtonVariant', 'primary')"
|
||||
@ -11,10 +10,11 @@
|
||||
>
|
||||
{{ pVal('confirmButtonLabel', 'Yes') }}
|
||||
</b-button>
|
||||
|
||||
<b-button
|
||||
@click="$emit('submit', { value: pRaw('rejectButtonValue', false, 'Boolean') })"
|
||||
:disabled="loading"
|
||||
:variant="pVal('rejectButtonVariant', 'primary')"
|
||||
:variant="pVal('rejectButtonVariant', 'light')"
|
||||
>
|
||||
{{ pVal('rejectButtonLabel', 'No') }}
|
||||
</b-button>
|
||||
|
||||
@ -1,22 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
<p>
|
||||
{{ message }}
|
||||
</p>
|
||||
<div
|
||||
class="text-center m-2"
|
||||
>
|
||||
<p v-if="!!message" v-html="message" />
|
||||
|
||||
<div class="d-flex flex-column gap-1">
|
||||
<c-input-select
|
||||
v-model="value"
|
||||
:options="options"
|
||||
:get-option-key="getOptionKey"
|
||||
:loading="processing"
|
||||
append-to-body
|
||||
:calculate-position="calculateDropdownPosition"
|
||||
option-value="recordID"
|
||||
option-text="label"
|
||||
placeholder="Select record"
|
||||
:filterable="false"
|
||||
:reduce="r => r.recordID"
|
||||
class="w-100 mb-3"
|
||||
@search="search"
|
||||
>
|
||||
@ -31,8 +28,10 @@
|
||||
</c-input-select>
|
||||
|
||||
<b-button
|
||||
@click="$emit('submit', { value: encodeValue() })"
|
||||
:disabled="loading"
|
||||
variant="primary"
|
||||
class="ml-auto"
|
||||
@click="$emit('submit', { value: encodeValue() })"
|
||||
>
|
||||
{{ pVal('buttonLabel', 'Submit') }}
|
||||
</b-button>
|
||||
@ -45,7 +44,6 @@ import CPagination from '../common/CPagination.vue'
|
||||
import { pVal } from '../utils.ts'
|
||||
import CInputSelect from '../../input/CInputSelect.vue'
|
||||
import { compose, NoID } from '@cortezaproject/corteza-js'
|
||||
import { createPopper } from '@popperjs/core'
|
||||
import { debounce } from 'lodash'
|
||||
|
||||
export default {
|
||||
@ -79,12 +77,8 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
// moduleFields returns the available field names
|
||||
moduleFields () {
|
||||
if (!this.module) {
|
||||
return []
|
||||
}
|
||||
return this.module.fields.map(({ name }) => name)
|
||||
labelField () {
|
||||
return this.module.fields.find(f => f.name === this.pVal('labelField'))
|
||||
},
|
||||
|
||||
showPagination () {
|
||||
@ -165,7 +159,9 @@ export default {
|
||||
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 () {
|
||||
@ -206,51 +202,6 @@ export default {
|
||||
}
|
||||
}, 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) {
|
||||
this.processing = true
|
||||
|
||||
@ -273,11 +224,15 @@ export default {
|
||||
|
||||
this.options = set.map(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 {
|
||||
recordID: record.recordID,
|
||||
label,
|
||||
label: label || record.recordID,
|
||||
record,
|
||||
}
|
||||
})
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<p v-html="message"></p>
|
||||
<p v-if="!!message" v-html="message" />
|
||||
|
||||
<b-form-group
|
||||
:label="label"
|
||||
label-class="text-primary"
|
||||
@ -13,6 +14,7 @@
|
||||
</b-form-group>
|
||||
<b-button
|
||||
:disabled="loading"
|
||||
variant="primary"
|
||||
@click="$emit('submit', { value: { '@value': value, '@type': 'String' }})"
|
||||
>
|
||||
{{ pVal('buttonLabel', 'Submit') }}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<p v-html="message"></p>
|
||||
<p v-if="!!message" v-html="message" />
|
||||
|
||||
<b-form-group
|
||||
:label="pVal('label', 'Input')"
|
||||
label-class="text-primary"
|
||||
@ -28,8 +29,10 @@
|
||||
:options="options"
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
<b-button
|
||||
:disabled="loading"
|
||||
variant="primary"
|
||||
@click="$emit('submit', { value: encodeValue() })"
|
||||
>
|
||||
{{ pVal('buttonLabel', 'Submit') }}
|
||||
|
||||
@ -15,7 +15,7 @@ export default {
|
||||
|
||||
computed: {
|
||||
message () {
|
||||
return this.pVal('message', '<i>Default prompt message.</i>')
|
||||
return this.pVal('message', '')
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user