PublishBtn.vue 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <template>
  2. <el-popover
  3. ref="popoverRef"
  4. width="240px"
  5. trigger="click"
  6. :disabled="publishNodes.length <= 1 || isPublishing"
  7. >
  8. <div v-if="publishNodes.length > 1" class="publish-selector">
  9. <div class="publish-selector__title">{{ t('pages.editor.selectPublishNode') }}</div>
  10. <button
  11. v-for="node in publishNodes"
  12. :key="node.id"
  13. type="button"
  14. class="publish-selector__item"
  15. @click="handleSelectPublishNode(node.id)"
  16. >
  17. <span class="publish-selector__name">{{ node.name }}</span>
  18. <span class="publish-selector__type">{{ getNodeDisplayName(node.nodeType) }}</span>
  19. </button>
  20. </div>
  21. <template #reference>
  22. <el-button
  23. :type="isPublished ? 'success' : 'default'"
  24. size="small"
  25. :disabled="!publishNodes.length"
  26. :loading="isPublishing"
  27. @click="handlePublishClick"
  28. >
  29. <Icon v-if="isPublished" icon="ix:success" class="mr-1" />
  30. {{
  31. isPublished ? t('pages.editor.status.published') : t('pages.editor.status.unpublished')
  32. }}
  33. </el-button>
  34. </template>
  35. </el-popover>
  36. </template>
  37. <script setup lang="ts">
  38. import { computed, ref } from 'vue'
  39. import { ElMessage, type PopoverInstance } from 'element-plus'
  40. import { agent } from '@repo/api-service'
  41. import { Icon } from '@repo/ui'
  42. import type { IWorkflow } from '@repo/workflow'
  43. import { useI18n } from '@/composables/useI18n'
  44. import { getNodeDisplayName } from '@/nodes/i18n'
  45. const props = defineProps<{
  46. workflow: IWorkflow
  47. }>()
  48. const emit = defineEmits<{
  49. (e: 'published'): void
  50. }>()
  51. const { t } = useI18n()
  52. const popoverRef = ref<PopoverInstance>()
  53. const isPublishing = ref(false)
  54. const PUBLISHABLE_NODE_TYPES = ['start', 'trigger-schedule', 'trigger-webhook']
  55. const isPublished = computed(() => props.workflow?.status === 'published')
  56. const publishNodes = computed(() => {
  57. return (props.workflow?.nodes || [])
  58. .filter((node) => {
  59. const nodeType = (node as any)?.nodeType || (node as any)?.data?.nodeType
  60. return PUBLISHABLE_NODE_TYPES.includes(nodeType || '')
  61. })
  62. .map((node) => {
  63. const nodeType = ((node as any)?.nodeType || (node as any)?.data?.nodeType || '') as string
  64. return {
  65. id: node.id,
  66. name: node.name || node.data?.title || getNodeDisplayName(nodeType) || nodeType,
  67. nodeType
  68. }
  69. })
  70. })
  71. const publishAgent = async (nodeId?: string) => {
  72. if (!nodeId) {
  73. ElMessage.warning(t('pages.editor.messages.missingPublishNode'))
  74. return
  75. }
  76. if (isPublishing.value) {
  77. return
  78. }
  79. isPublishing.value = true
  80. try {
  81. const response = await agent.postAgentDoAgentPublish({
  82. start_node_id: nodeId,
  83. appAgentId: props.workflow.id
  84. })
  85. if (response?.isSuccess) {
  86. props.workflow.status = 'published'
  87. popoverRef.value?.hide()
  88. ElMessage.success(t('pages.editor.messages.publishSuccess'))
  89. emit('published')
  90. return
  91. }
  92. if ((response as any)?.error) {
  93. ElMessage.error((response as any).error)
  94. return
  95. }
  96. ElMessage.error(t('pages.editor.messages.publishFailed'))
  97. } catch (error) {
  98. console.error('postAgentDoAgentPublish error', error)
  99. ElMessage.error(t('pages.editor.messages.publishFailed'))
  100. } finally {
  101. isPublishing.value = false
  102. }
  103. }
  104. const handlePublishClick = () => {
  105. if (publishNodes.value.length <= 1) {
  106. publishAgent(publishNodes.value[0]?.id)
  107. }
  108. }
  109. const handleSelectPublishNode = (id: string) => {
  110. publishAgent(id)
  111. }
  112. </script>
  113. <style scoped>
  114. .publish-selector {
  115. display: flex;
  116. flex-direction: column;
  117. gap: 8px;
  118. }
  119. .publish-selector__title {
  120. font-size: 13px;
  121. font-weight: 600;
  122. color: #344054;
  123. }
  124. .publish-selector__item {
  125. display: flex;
  126. align-items: center;
  127. justify-content: space-between;
  128. gap: 12px;
  129. width: 100%;
  130. padding: 10px 12px;
  131. border: 1px solid #e4e7ec;
  132. border-radius: 10px;
  133. background: #fff;
  134. cursor: pointer;
  135. text-align: left;
  136. }
  137. .publish-selector__item:hover {
  138. border-color: #2563eb;
  139. background: #f8fbff;
  140. }
  141. .publish-selector__name {
  142. font-size: 13px;
  143. font-weight: 600;
  144. color: #344054;
  145. }
  146. .publish-selector__type {
  147. font-size: 12px;
  148. color: #667085;
  149. }
  150. </style>