|
| 1 | +<script setup lang="ts"> |
| 2 | +import { faLink, faShareAlt } from "@fortawesome/free-solid-svg-icons"; |
| 3 | +import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; |
| 4 | +import { |
| 5 | + BAlert, |
| 6 | + BButton, |
| 7 | + BFormInput, |
| 8 | + BInputGroup, |
| 9 | + BInputGroupAppend, |
| 10 | + BInputGroupPrepend, |
| 11 | + BInputGroupText, |
| 12 | + BModal, |
| 13 | +} from "bootstrap-vue"; |
| 14 | +import { computed, ref, watch } from "vue"; |
| 15 | +
|
| 16 | +import { getFullAppUrl } from "@/app/utils"; |
| 17 | +import { useWorkflowInstance } from "@/composables/useWorkflowInstance"; |
| 18 | +import { useHistoryStore } from "@/stores/historyStore"; |
| 19 | +
|
| 20 | +import { useWizard } from "../Common/Wizard/useWizard"; |
| 21 | +
|
| 22 | +import GenericWizard from "../Common/Wizard/GenericWizard.vue"; |
| 23 | +import CopyToClipboard from "../CopyToClipboard.vue"; |
| 24 | +import LoadingSpan from "../LoadingSpan.vue"; |
| 25 | +import SharingPage from "../Sharing/SharingPage.vue"; |
| 26 | +
|
| 27 | +const props = defineProps<{ |
| 28 | + invocationId: string; |
| 29 | + workflowId: string; |
| 30 | + historyId: string; |
| 31 | +}>(); |
| 32 | +
|
| 33 | +const modalToggle = ref(false); |
| 34 | +
|
| 35 | +// Workflow and History refs |
| 36 | +const { workflow, loading: workflowLoading, error: workflowError } = useWorkflowInstance(props.workflowId); |
| 37 | +const historyStore = useHistoryStore(); |
| 38 | +const history = computed(() => historyStore.getHistoryById(props.historyId, true)); |
| 39 | +
|
| 40 | +/** The link to the invocation. */ |
| 41 | +const invocationLink = computed(() => getFullAppUrl(`workflows/invocations/${props.invocationId}`)); |
| 42 | +
|
| 43 | +// Component references |
| 44 | +const historySharing = ref<InstanceType<typeof SharingPage> | null>(null); |
| 45 | +const workflowSharing = ref<InstanceType<typeof SharingPage> | null>(null); |
| 46 | +
|
| 47 | +// Computed properties to check if the workflow and history are accessible |
| 48 | +const workflowIsAccessible = computed(() => { |
| 49 | + const { item } = workflowSharing.value || {}; |
| 50 | + return Boolean(item?.importable) || Boolean(item?.users_shared_with?.length); |
| 51 | +}); |
| 52 | +const historyIsAccessible = computed(() => { |
| 53 | + const { item } = historySharing.value || {}; |
| 54 | + return Boolean(item?.importable) || Boolean(item?.users_shared_with?.length); |
| 55 | +}); |
| 56 | +
|
| 57 | +/** The workflow and history sharing wizard steps. */ |
| 58 | +const wizard = useWizard({ |
| 59 | + "share-workflow": { |
| 60 | + label: "Share workflow", |
| 61 | + instructions: "", |
| 62 | + isValid: () => workflowIsAccessible.value, |
| 63 | + isSkippable: () => false, |
| 64 | + }, |
| 65 | + "share-history": { |
| 66 | + label: "Share history", |
| 67 | + instructions: "", |
| 68 | + isValid: () => historyIsAccessible.value, |
| 69 | + isSkippable: () => false, |
| 70 | + }, |
| 71 | + "get-link": { |
| 72 | + label: "Share the invocation", |
| 73 | + instructions: "Here is a link to the invocation.", |
| 74 | + isValid: () => true, |
| 75 | + isSkippable: () => false, |
| 76 | + }, |
| 77 | +}); |
| 78 | +
|
| 79 | +/** Information to show in the instructional message. */ |
| 80 | +const currentItemInfo = computed(() => { |
| 81 | + if (wizard.isCurrent("share-workflow")) { |
| 82 | + return { |
| 83 | + type: "workflow", |
| 84 | + name: workflow.value?.name || "...", |
| 85 | + accessibleStatus: workflowIsAccessible.value, |
| 86 | + }; |
| 87 | + } else if (wizard.isCurrent("share-history")) { |
| 88 | + return { |
| 89 | + type: "history", |
| 90 | + name: history.value?.name || "...", |
| 91 | + accessibleStatus: historyIsAccessible.value, |
| 92 | + }; |
| 93 | + } else { |
| 94 | + return null; |
| 95 | + } |
| 96 | +}); |
| 97 | +
|
| 98 | +// This next block is used to navigate to the "get-link" step of the wizard |
| 99 | +// when the modal is opened and the workflow and history are already accessible. |
| 100 | +const navigatedToLinkOnce = ref(false); |
| 101 | +watch( |
| 102 | + () => modalToggle.value, |
| 103 | + (opened) => { |
| 104 | + if (opened && !navigatedToLinkOnce.value && !wizard.isCurrent("get-link")) { |
| 105 | + // A timeout is used to ensure that the sharing components are loaded |
| 106 | + setTimeout(() => { |
| 107 | + if (workflowIsAccessible.value && historyIsAccessible.value) { |
| 108 | + wizard.goTo("get-link"); |
| 109 | + } |
| 110 | + navigatedToLinkOnce.value = true; |
| 111 | + }, 1000); |
| 112 | + } |
| 113 | + }, |
| 114 | + { immediate: true } |
| 115 | +); |
| 116 | +</script> |
| 117 | + |
| 118 | +<template> |
| 119 | + <div> |
| 120 | + <BButton |
| 121 | + v-b-tooltip.noninteractive.hover |
| 122 | + title="Share Invocation" |
| 123 | + size="sm" |
| 124 | + class="text-decoration-none" |
| 125 | + variant="link" |
| 126 | + :disabled="!workflow || !history" |
| 127 | + @click="modalToggle = true"> |
| 128 | + <FontAwesomeIcon :icon="faShareAlt" fixed-width /> |
| 129 | + </BButton> |
| 130 | + |
| 131 | + <BModal |
| 132 | + v-model="modalToggle" |
| 133 | + title="Share Workflow Invocation" |
| 134 | + title-sr-only |
| 135 | + hide-header |
| 136 | + size="xl" |
| 137 | + scrollable |
| 138 | + dialog-class="invocation-share-dialog" |
| 139 | + ok-only |
| 140 | + ok-title="Exit" |
| 141 | + ok-variant="secondary"> |
| 142 | + <BAlert v-if="workflowError" variant="danger" show> |
| 143 | + {{ workflowError }} |
| 144 | + </BAlert> |
| 145 | + |
| 146 | + <LoadingSpan v-else-if="workflowLoading" message="Loading details for invocation" /> |
| 147 | + |
| 148 | + <GenericWizard |
| 149 | + v-else-if="!!workflow && !!history" |
| 150 | + title="Share the associated workflow and history first" |
| 151 | + :use="wizard" |
| 152 | + submit-button-label="Next" |
| 153 | + :is-busy="workflowLoading"> |
| 154 | + <div v-if="currentItemInfo?.accessibleStatus" class="donemessagelarge"> |
| 155 | + The {{ currentItemInfo.type }} |
| 156 | + <strong> "{{ currentItemInfo.name }}" </strong> |
| 157 | + is either made accessible via link or shared with at least one user. |
| 158 | + <strong>Click next to continue.</strong> |
| 159 | + </div> |
| 160 | + <BAlert v-else-if="currentItemInfo?.accessibleStatus === false" variant="info" show> |
| 161 | + The {{ currentItemInfo.type }} |
| 162 | + <strong> "{{ currentItemInfo.name }}" </strong> |
| 163 | + is not accessible via link or shared with any user. Select your sharing preferences below to make it |
| 164 | + accessible. |
| 165 | + </BAlert> |
| 166 | + |
| 167 | + <div v-show="wizard.isCurrent('share-workflow')" class="w-100"> |
| 168 | + <SharingPage |
| 169 | + :id="workflow.id" |
| 170 | + ref="workflowSharing" |
| 171 | + :key="`workflow-${workflow.id}`" |
| 172 | + class="sharing-view" |
| 173 | + plural-name="Workflows" |
| 174 | + model-class="Workflow" |
| 175 | + no-heading /> |
| 176 | + </div> |
| 177 | + |
| 178 | + <div v-show="wizard.isCurrent('share-history')" class="w-100"> |
| 179 | + <SharingPage |
| 180 | + :id="history.id" |
| 181 | + ref="historySharing" |
| 182 | + :key="`history-${history.id}`" |
| 183 | + class="sharing-view" |
| 184 | + plural-name="Histories" |
| 185 | + model-class="History" |
| 186 | + no-heading /> |
| 187 | + </div> |
| 188 | + |
| 189 | + <div v-if="wizard.isCurrent('get-link')" class="w-100"> |
| 190 | + <BInputGroup> |
| 191 | + <BInputGroupPrepend> |
| 192 | + <BInputGroupText> |
| 193 | + <FontAwesomeIcon :icon="faLink" /> |
| 194 | + </BInputGroupText> |
| 195 | + </BInputGroupPrepend> |
| 196 | + |
| 197 | + <BFormInput type="text" :value="invocationLink" disabled /> |
| 198 | + |
| 199 | + <BInputGroupAppend> |
| 200 | + <CopyToClipboard |
| 201 | + message="Link to invocation copied to clipboard" |
| 202 | + :text="invocationLink" |
| 203 | + title="Copy key" |
| 204 | + component="button" /> |
| 205 | + </BInputGroupAppend> |
| 206 | + </BInputGroup> |
| 207 | + |
| 208 | + <p class="mt-2"> |
| 209 | + <strong>Note:</strong> |
| 210 | + If you share this link with someone, and they are still unable to view the invocation, please go |
| 211 | + back and ensure that the workflow and history are either made accessible to anyone via link, or |
| 212 | + shared with the same user. |
| 213 | + </p> |
| 214 | + </div> |
| 215 | + </GenericWizard> |
| 216 | + </BModal> |
| 217 | + </div> |
| 218 | +</template> |
| 219 | + |
| 220 | +<style lang="scss"> |
| 221 | +.invocation-share-dialog { |
| 222 | + width: 900px; |
| 223 | +} |
| 224 | +</style> |
| 225 | + |
| 226 | +<style lang="scss" scoped> |
| 227 | +.sharing-view { |
| 228 | + container-type: unset; |
| 229 | + overflow-y: unset; |
| 230 | +} |
| 231 | +</style> |
0 commit comments