@revenexx/studio-integrations 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/module.d.mts +2 -2
- package/dist/module.json +1 -1
- package/dist/runtime/components/Integrations/CredentialCreateDialog.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +279 -0
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.d.vue.ts +20 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +342 -0
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue.d.ts +20 -0
- package/dist/runtime/components/Integrations/CredentialLogo.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/CredentialLogo.vue +37 -0
- package/dist/runtime/components/Integrations/CredentialLogo.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +364 -0
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.d.vue.ts +15 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue +71 -0
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue.d.ts +15 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.d.vue.ts +5 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.vue +151 -0
- package/dist/runtime/components/Integrations/DeadLettersPanel.vue.d.ts +5 -0
- package/dist/runtime/components/Integrations/EditorTip.d.vue.ts +17 -0
- package/dist/runtime/components/Integrations/EditorTip.vue +46 -0
- package/dist/runtime/components/Integrations/EditorTip.vue.d.ts +17 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue +64 -0
- package/dist/runtime/components/Integrations/EventTypeCombobox.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +19 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue +236 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +19 -0
- package/dist/runtime/components/Integrations/GroupFrameView.d.vue.ts +28 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue +222 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue.d.ts +28 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +184 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.d.vue.ts +16 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +102 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue.d.ts +16 -0
- package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +23 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue +587 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +23 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue +80 -0
- package/dist/runtime/components/Integrations/NodeDynamicOutputsResolver.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +22 -3
- package/dist/runtime/components/Integrations/NodeInspector.vue +1074 -294
- package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +22 -3
- package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/NodeLogo.vue +38 -0
- package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/NodePalette.d.vue.ts +22 -1
- package/dist/runtime/components/Integrations/NodePalette.vue +411 -90
- package/dist/runtime/components/Integrations/NodePalette.vue.d.ts +22 -1
- package/dist/runtime/components/Integrations/QueryBuilder.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/QueryBuilder.vue +239 -0
- package/dist/runtime/components/Integrations/QueryBuilder.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/{RunDetailDialog.d.vue.ts → RunActionsMenu.d.vue.ts} +3 -4
- package/dist/runtime/components/Integrations/RunActionsMenu.vue +86 -0
- package/dist/runtime/components/Integrations/{RunDetailDialog.vue.d.ts → RunActionsMenu.vue.d.ts} +3 -4
- package/dist/runtime/components/Integrations/RunDetailPanel.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/RunDetailPanel.vue +777 -0
- package/dist/runtime/components/Integrations/RunDetailPanel.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.vue +175 -0
- package/dist/runtime/components/Integrations/RunPayloadInput.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/RunResponseModal.d.vue.ts +27 -0
- package/dist/runtime/components/Integrations/RunResponseModal.vue +84 -0
- package/dist/runtime/components/Integrations/RunResponseModal.vue.d.ts +27 -0
- package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +21 -0
- package/dist/runtime/components/Integrations/RunsTable.vue +114 -0
- package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +21 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.d.vue.ts +11 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +91 -0
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue.d.ts +11 -0
- package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +28 -0
- package/dist/runtime/components/Integrations/StickyNoteView.vue +208 -0
- package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +28 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.d.vue.ts +29 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +201 -0
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue.d.ts +29 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.d.vue.ts +32 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +138 -0
- package/dist/runtime/components/Integrations/WorkflowContextMenu.vue.d.ts +32 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.d.vue.ts +9 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +322 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue.d.ts +9 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.d.vue.ts +18 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +63 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue.d.ts +18 -0
- package/dist/runtime/components/Integrations/WorkflowEdgeView.d.vue.ts +12 -1
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +68 -6
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue.d.ts +12 -1
- package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +8 -1
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +1424 -144
- package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +8 -1
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +417 -0
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.d.vue.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +89 -0
- package/dist/runtime/components/Integrations/WorkflowIconPicker.vue.d.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.d.vue.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.vue +35 -0
- package/dist/runtime/components/Integrations/WorkflowIconView.vue.d.ts +10 -0
- package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +5 -1
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue +114 -84
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +5 -1
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.d.vue.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +654 -0
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue.d.ts +12 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +36 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +136 -0
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +36 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.d.vue.ts +14 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +63 -0
- package/dist/runtime/components/Integrations/WorkflowTagsInput.vue.d.ts +14 -0
- package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +35 -15
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.d.vue.ts +13 -0
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +265 -0
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue.d.ts +13 -0
- package/dist/runtime/components/Integrations/WorkflowsTable.d.vue.ts +4 -1
- package/dist/runtime/components/Integrations/WorkflowsTable.vue +122 -39
- package/dist/runtime/components/Integrations/WorkflowsTable.vue.d.ts +4 -1
- package/dist/runtime/components/Integrations/workflowLayout.d.ts +5 -0
- package/dist/runtime/components/Integrations/workflowLayout.js +5 -3
- package/dist/runtime/composables/integrationsApi.d.ts +6 -7
- package/dist/runtime/composables/integrationsApi.js +6 -12
- package/dist/runtime/composables/useCanvasShortcuts.d.ts +37 -0
- package/dist/runtime/composables/useCanvasShortcuts.js +62 -0
- package/dist/runtime/composables/useCredentialTypes.js +2 -1
- package/dist/runtime/composables/useIntegrationsAudit.js +2 -1
- package/dist/runtime/composables/useIntegrationsCredentials.js +2 -1
- package/dist/runtime/composables/useIntegrationsDeadLetters.d.ts +22 -0
- package/dist/runtime/composables/useIntegrationsDeadLetters.js +50 -0
- package/dist/runtime/composables/useIntegrationsNodes.d.ts +4 -0
- package/dist/runtime/composables/useIntegrationsNodes.js +8 -4
- package/dist/runtime/composables/useIntegrationsRevisions.d.ts +40 -0
- package/dist/runtime/composables/useIntegrationsRevisions.js +52 -0
- package/dist/runtime/composables/useIntegrationsRuns.d.ts +21 -1
- package/dist/runtime/composables/useIntegrationsRuns.js +94 -5
- package/dist/runtime/composables/useIntegrationsSecrets.js +2 -1
- package/dist/runtime/composables/useIntegrationsTemplates.d.ts +1 -0
- package/dist/runtime/composables/useIntegrationsTemplates.js +34 -5
- package/dist/runtime/composables/useIntegrationsTriggers.js +2 -1
- package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +1 -0
- package/dist/runtime/composables/useIntegrationsWorkflows.js +59 -2
- package/dist/runtime/composables/useMiniMapLayout.d.ts +34 -0
- package/dist/runtime/composables/useMiniMapLayout.js +119 -0
- package/dist/runtime/composables/useNodeConfigResolve.d.ts +43 -0
- package/dist/runtime/composables/useNodeConfigResolve.js +124 -0
- package/dist/runtime/composables/useNodeDrag.d.ts +22 -0
- package/dist/runtime/composables/useNodeDrag.js +10 -0
- package/dist/runtime/composables/usePaletteLayout.d.ts +41 -0
- package/dist/runtime/composables/usePaletteLayout.js +113 -0
- package/dist/runtime/data/expressionEditor.d.ts +22 -0
- package/dist/runtime/data/expressionEditor.js +40 -0
- package/dist/runtime/data/integrationNodeCatalog.js +8 -8
- package/dist/runtime/data/nodeInputData.d.ts +37 -0
- package/dist/runtime/data/nodeInputData.js +62 -0
- package/dist/runtime/data/nodeRunData.d.ts +56 -0
- package/dist/runtime/data/nodeRunData.js +91 -0
- package/dist/runtime/data/payloadForm.d.ts +44 -0
- package/dist/runtime/data/payloadForm.js +126 -0
- package/dist/runtime/data/workflowIconCatalog.d.ts +34 -0
- package/dist/runtime/data/workflowIconCatalog.js +116 -0
- package/dist/runtime/pages/integrations/audit.vue +25 -35
- package/dist/runtime/pages/integrations/credentials.vue +117 -122
- package/dist/runtime/pages/integrations/index.vue +133 -36
- package/dist/runtime/pages/integrations/runs.vue +125 -75
- package/dist/runtime/pages/integrations/schedules.vue +5 -16
- package/dist/runtime/pages/integrations/secrets.vue +1 -3
- package/dist/runtime/pages/integrations/workflows/[id].vue +599 -194
- package/dist/runtime/pages/integrations/workflows/index.vue +10 -8
- package/dist/runtime/types/integrations.d.ts +190 -4
- package/dist/runtime/utils/apiError.d.ts +17 -0
- package/dist/runtime/utils/apiError.js +8 -0
- package/dist/runtime/utils/credentialState.d.ts +28 -0
- package/dist/runtime/utils/credentialState.js +29 -0
- package/dist/runtime/utils/localize.d.ts +3 -1
- package/dist/runtime/utils/localize.js +1 -2
- package/dist/runtime/utils/statusStyle.d.ts +6 -0
- package/dist/runtime/utils/statusStyle.js +15 -0
- package/package.json +20 -3
- package/dist/runtime/components/Integrations/RunDetailDialog.vue +0 -169
- package/dist/runtime/pages/integrations/workflows/new.d.vue.ts +0 -2
- package/dist/runtime/pages/integrations/workflows/new.vue +0 -153
- package/dist/runtime/pages/integrations/workflows/new.vue.d.ts +0 -2
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, reactive, ref, watch } from "vue";
|
|
3
|
+
import {
|
|
4
|
+
CheckCircle as CheckCircle2,
|
|
5
|
+
CloseCircle as XCircle,
|
|
6
|
+
RefreshCircle as Loader2,
|
|
7
|
+
TestTube as TestIcon,
|
|
8
|
+
TrashBinTrash as Trash2
|
|
9
|
+
} from "#solar-icons";
|
|
10
|
+
import {
|
|
11
|
+
Button,
|
|
12
|
+
Dialog,
|
|
13
|
+
DialogContent,
|
|
14
|
+
DialogDescription,
|
|
15
|
+
DialogHeader,
|
|
16
|
+
DialogTitle,
|
|
17
|
+
Input,
|
|
18
|
+
Label,
|
|
19
|
+
Switch,
|
|
20
|
+
Select,
|
|
21
|
+
SelectContent,
|
|
22
|
+
SelectItem,
|
|
23
|
+
SelectTrigger,
|
|
24
|
+
SelectValue
|
|
25
|
+
} from "@revenexx/studio";
|
|
26
|
+
import { toast } from "vue-sonner";
|
|
27
|
+
import { credentialState, relativeTime } from "../../utils/credentialState";
|
|
28
|
+
const props = defineProps({
|
|
29
|
+
open: { type: Boolean, required: true },
|
|
30
|
+
credential: { type: [Object, null], required: true },
|
|
31
|
+
type: { type: [Object, null], required: true }
|
|
32
|
+
});
|
|
33
|
+
const emit = defineEmits(["update:open", "changed"]);
|
|
34
|
+
const { update, remove, test, oauthAuthorizeUrl, load } = useIntegrationsCredentials();
|
|
35
|
+
const tab = ref("credentials");
|
|
36
|
+
const tabs = [
|
|
37
|
+
{ key: "credentials", label: "Credentials" },
|
|
38
|
+
{ key: "details", label: "Details" }
|
|
39
|
+
];
|
|
40
|
+
const form = reactive({ name: "", config: {} });
|
|
41
|
+
const sourceActive = ref(false);
|
|
42
|
+
const saving = ref(false);
|
|
43
|
+
const deleting = ref(false);
|
|
44
|
+
const testing = ref(false);
|
|
45
|
+
const liveTest = ref(null);
|
|
46
|
+
const connecting = ref(false);
|
|
47
|
+
function loc(v) {
|
|
48
|
+
if (!v) return "";
|
|
49
|
+
if (typeof v === "string") return v;
|
|
50
|
+
const o = v;
|
|
51
|
+
return o.en ?? o.de ?? Object.values(o)[0] ?? "";
|
|
52
|
+
}
|
|
53
|
+
const typeName = computed(() => loc(props.type?.name) || props.credential?.credential_type_slug || "");
|
|
54
|
+
const isOAuthAuthcode = computed(() => props.type?.auth_kind === "oauth2-authcode");
|
|
55
|
+
const state = computed(() => props.credential ? credentialState(props.credential) : null);
|
|
56
|
+
function fieldsOf(t) {
|
|
57
|
+
return t?.fields ?? [];
|
|
58
|
+
}
|
|
59
|
+
function formatDateTime(iso) {
|
|
60
|
+
if (!iso) return "\u2014";
|
|
61
|
+
try {
|
|
62
|
+
return new Date(iso).toLocaleString();
|
|
63
|
+
} catch {
|
|
64
|
+
return String(iso);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
watch(
|
|
68
|
+
() => [props.open, props.credential?.id],
|
|
69
|
+
() => {
|
|
70
|
+
if (!props.open || !props.credential) return;
|
|
71
|
+
tab.value = "credentials";
|
|
72
|
+
form.name = props.credential.name;
|
|
73
|
+
form.config = { ...props.credential.public_config ?? {} };
|
|
74
|
+
sourceActive.value = false;
|
|
75
|
+
liveTest.value = null;
|
|
76
|
+
},
|
|
77
|
+
{ immediate: true }
|
|
78
|
+
);
|
|
79
|
+
function buildConfigPayload() {
|
|
80
|
+
const out = {};
|
|
81
|
+
for (const f of fieldsOf(props.type)) {
|
|
82
|
+
const v = form.config[f.key];
|
|
83
|
+
if (f.type === "secret" && (v === void 0 || v === "")) continue;
|
|
84
|
+
if (v !== void 0) out[f.key] = v;
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
async function runTest() {
|
|
89
|
+
if (!props.credential) return;
|
|
90
|
+
testing.value = true;
|
|
91
|
+
liveTest.value = null;
|
|
92
|
+
try {
|
|
93
|
+
liveTest.value = await test(props.credential.id);
|
|
94
|
+
await load(true);
|
|
95
|
+
emit("changed");
|
|
96
|
+
} finally {
|
|
97
|
+
testing.value = false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async function save() {
|
|
101
|
+
if (!props.credential || !form.name.trim()) return;
|
|
102
|
+
saving.value = true;
|
|
103
|
+
try {
|
|
104
|
+
await update(props.credential.id, { name: form.name.trim(), config: buildConfigPayload() });
|
|
105
|
+
toast.success("Credential updated");
|
|
106
|
+
emit("changed");
|
|
107
|
+
emit("update:open", false);
|
|
108
|
+
} catch (e) {
|
|
109
|
+
toast.error(e?.message ?? "Could not save credential.");
|
|
110
|
+
} finally {
|
|
111
|
+
saving.value = false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function destroy() {
|
|
115
|
+
if (!props.credential) return;
|
|
116
|
+
if (!confirm(`Delete credential "${props.credential.name}"? Workflows referencing it will fail until re-bound.`)) return;
|
|
117
|
+
deleting.value = true;
|
|
118
|
+
try {
|
|
119
|
+
await remove(props.credential.id);
|
|
120
|
+
toast.success("Credential deleted");
|
|
121
|
+
emit("changed");
|
|
122
|
+
emit("update:open", false);
|
|
123
|
+
} catch (e) {
|
|
124
|
+
toast.error(e?.message ?? "Could not delete credential.");
|
|
125
|
+
} finally {
|
|
126
|
+
deleting.value = false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function connect() {
|
|
130
|
+
if (!props.credential) return;
|
|
131
|
+
connecting.value = true;
|
|
132
|
+
try {
|
|
133
|
+
const authorizeUrl = await oauthAuthorizeUrl(props.credential.id);
|
|
134
|
+
const popup = window.open(authorizeUrl, "oauth-connect", "width=600,height=720");
|
|
135
|
+
const onMessage = async (ev) => {
|
|
136
|
+
if (ev.data?.type === "integrations-oauth-complete") {
|
|
137
|
+
window.removeEventListener("message", onMessage);
|
|
138
|
+
await load(true);
|
|
139
|
+
emit("changed");
|
|
140
|
+
toast.success("Connected");
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
window.addEventListener("message", onMessage);
|
|
144
|
+
const poll = window.setInterval(async () => {
|
|
145
|
+
if (popup?.closed) {
|
|
146
|
+
window.clearInterval(poll);
|
|
147
|
+
window.removeEventListener("message", onMessage);
|
|
148
|
+
await load(true);
|
|
149
|
+
emit("changed");
|
|
150
|
+
}
|
|
151
|
+
}, 1e3);
|
|
152
|
+
} catch (e) {
|
|
153
|
+
toast.error(e?.message ?? "Could not start OAuth connect.");
|
|
154
|
+
} finally {
|
|
155
|
+
connecting.value = false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
</script>
|
|
159
|
+
|
|
160
|
+
<template>
|
|
161
|
+
<Dialog :open="open" @update:open="(v) => emit('update:open', v)">
|
|
162
|
+
<DialogContent class="sm:max-w-3xl">
|
|
163
|
+
<DialogHeader>
|
|
164
|
+
<div class="flex items-start gap-3">
|
|
165
|
+
<IntegrationsCredentialLogo :type="type" :size="22" />
|
|
166
|
+
<div class="min-w-0 flex-1">
|
|
167
|
+
<DialogTitle class="truncate">{{ credential?.name }}</DialogTitle>
|
|
168
|
+
<DialogDescription class="text-sm truncate">{{ typeName }}</DialogDescription>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
</DialogHeader>
|
|
172
|
+
|
|
173
|
+
<div v-if="credential && state">
|
|
174
|
+
<!-- Standard cockpit tab bar (violet underline) -->
|
|
175
|
+
<TabBar :model-value="tab" :tabs="tabs" @update:model-value="(k) => tab = k" />
|
|
176
|
+
|
|
177
|
+
<!-- Tab 1: Credentials -->
|
|
178
|
+
<div v-if="tab === 'credentials'" class="space-y-5 max-h-[62vh] overflow-y-auto pr-1 pt-4">
|
|
179
|
+
<!-- Connection state — the headline answer: are these credentials correct? -->
|
|
180
|
+
<div class="rounded-lg border p-3" :class="state.toneClass">
|
|
181
|
+
<div class="flex items-center gap-2">
|
|
182
|
+
<CheckCircle2 v-if="state.key === 'connected'" :size="16" class="shrink-0" />
|
|
183
|
+
<XCircle v-else-if="state.key === 'failed'" :size="16" class="shrink-0" />
|
|
184
|
+
<span class="font-medium">{{ state.label }}</span>
|
|
185
|
+
<span v-if="state.at" class="text-sm opacity-70">· verified {{ relativeTime(state.at) }}</span>
|
|
186
|
+
<div class="flex-1" />
|
|
187
|
+
<Button
|
|
188
|
+
v-if="isOAuthAuthcode"
|
|
189
|
+
size="sm"
|
|
190
|
+
variant="outline"
|
|
191
|
+
class="bg-white/60"
|
|
192
|
+
:disabled="connecting"
|
|
193
|
+
@click="connect"
|
|
194
|
+
>
|
|
195
|
+
<Loader2 v-if="connecting" :size="13" class="mr-1 animate-spin" />
|
|
196
|
+
Reconnect
|
|
197
|
+
</Button>
|
|
198
|
+
</div>
|
|
199
|
+
<p v-if="state.key === 'failed' && state.message" class="mt-1 text-sm break-words opacity-90">
|
|
200
|
+
{{ state.message }}
|
|
201
|
+
</p>
|
|
202
|
+
<p v-else-if="state.key === 'untested'" class="mt-1 text-sm opacity-80">
|
|
203
|
+
Run a test to verify these credentials actually connect.
|
|
204
|
+
</p>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
<!-- Editable fields -->
|
|
208
|
+
<div class="space-y-3">
|
|
209
|
+
<div class="space-y-1.5">
|
|
210
|
+
<Label for="detail-cred-name">Name</Label>
|
|
211
|
+
<Input id="detail-cred-name" v-model="form.name" class="bg-white" />
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<!-- "Use revenexx …" source picker (SFTP / Mail / API key) -->
|
|
215
|
+
<IntegrationsCredentialRevenexxSource
|
|
216
|
+
:type="type"
|
|
217
|
+
@update:active="(v) => sourceActive = v"
|
|
218
|
+
@apply="(c) => Object.assign(form.config, c)"
|
|
219
|
+
/>
|
|
220
|
+
|
|
221
|
+
<div v-for="f in fieldsOf(type)" v-show="!sourceActive" :key="f.key" class="space-y-1.5">
|
|
222
|
+
<Label>{{ loc(f.label) }}{{ f.required ? " *" : "" }}</Label>
|
|
223
|
+
|
|
224
|
+
<Input
|
|
225
|
+
v-if="f.type === 'secret'"
|
|
226
|
+
:model-value="form.config[f.key] ?? ''"
|
|
227
|
+
type="password"
|
|
228
|
+
autocomplete="new-password"
|
|
229
|
+
placeholder="Leave blank to keep current"
|
|
230
|
+
class="bg-white"
|
|
231
|
+
@update:model-value="(v) => form.config[f.key] = v"
|
|
232
|
+
/>
|
|
233
|
+
<Input
|
|
234
|
+
v-else-if="f.type === 'number'"
|
|
235
|
+
type="number"
|
|
236
|
+
:model-value="form.config[f.key] ?? ''"
|
|
237
|
+
class="bg-white"
|
|
238
|
+
@update:model-value="(v) => form.config[f.key] = v === '' ? void 0 : Number(v)"
|
|
239
|
+
/>
|
|
240
|
+
<div v-else-if="f.type === 'boolean'" class="flex items-center gap-2 pt-1">
|
|
241
|
+
<Switch :model-value="Boolean(form.config[f.key])" @update:model-value="(v) => form.config[f.key] = v" />
|
|
242
|
+
</div>
|
|
243
|
+
<Select
|
|
244
|
+
v-else-if="f.type === 'select'"
|
|
245
|
+
:model-value="form.config[f.key] ?? ''"
|
|
246
|
+
@update:model-value="(v) => form.config[f.key] = v"
|
|
247
|
+
>
|
|
248
|
+
<SelectTrigger class="bg-white">
|
|
249
|
+
<SelectValue placeholder="Pick one" />
|
|
250
|
+
</SelectTrigger>
|
|
251
|
+
<SelectContent>
|
|
252
|
+
<SelectItem v-for="opt in f.options ?? []" :key="String(opt.value)" :value="String(opt.value)">
|
|
253
|
+
{{ loc(opt.label) }}
|
|
254
|
+
</SelectItem>
|
|
255
|
+
</SelectContent>
|
|
256
|
+
</Select>
|
|
257
|
+
<Input
|
|
258
|
+
v-else
|
|
259
|
+
:model-value="form.config[f.key] ?? ''"
|
|
260
|
+
class="bg-white"
|
|
261
|
+
@update:model-value="(v) => form.config[f.key] = v"
|
|
262
|
+
/>
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
<!-- Live test feedback (from the test the operator just ran) -->
|
|
266
|
+
<div
|
|
267
|
+
v-if="liveTest"
|
|
268
|
+
class="rounded-md px-3 py-2 text-sm"
|
|
269
|
+
:class="liveTest.ok ? 'bg-emerald-500/10 text-emerald-700' : 'bg-rose-500/10 text-rose-700'"
|
|
270
|
+
>
|
|
271
|
+
{{ liveTest.ok ? "Connection ok." : liveTest.error ?? "Connection failed." }}
|
|
272
|
+
</div>
|
|
273
|
+
|
|
274
|
+
<div class="flex items-center gap-2 pt-1">
|
|
275
|
+
<div class="flex-1" />
|
|
276
|
+
<Button variant="outline" :disabled="testing || saving" @click="runTest">
|
|
277
|
+
<Loader2 v-if="testing" :size="14" class="mr-1 animate-spin" />
|
|
278
|
+
<TestIcon v-else :size="14" class="mr-1" />
|
|
279
|
+
Connect
|
|
280
|
+
</Button>
|
|
281
|
+
<Button :disabled="saving || !form.name.trim()" @click="save">
|
|
282
|
+
<Loader2 v-if="saving" :size="14" class="mr-1 animate-spin" />
|
|
283
|
+
Save
|
|
284
|
+
</Button>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
<!-- Tab 2: Details -->
|
|
291
|
+
<div v-else class="space-y-5 max-h-[62vh] overflow-y-auto pr-1 pt-4">
|
|
292
|
+
<div class="grid grid-cols-[9rem_1fr] gap-x-4 gap-y-2 text-sm">
|
|
293
|
+
<span class="text-muted-foreground">Type</span>
|
|
294
|
+
<span>{{ typeName }}</span>
|
|
295
|
+
|
|
296
|
+
<span class="text-muted-foreground">Type slug</span>
|
|
297
|
+
<span class="font-mono text-xs">{{ credential.credential_type_slug }}</span>
|
|
298
|
+
|
|
299
|
+
<span class="text-muted-foreground">Version</span>
|
|
300
|
+
<span class="font-mono text-xs">{{ type?.version ?? "\u2014" }}</span>
|
|
301
|
+
|
|
302
|
+
<span class="text-muted-foreground">Auth kind</span>
|
|
303
|
+
<span class="font-mono text-xs">{{ type?.auth_kind ?? "\u2014" }}</span>
|
|
304
|
+
|
|
305
|
+
<span class="text-muted-foreground">Last tested</span>
|
|
306
|
+
<span class="tabular-nums">{{ formatDateTime(credential.last_test_at) }}</span>
|
|
307
|
+
|
|
308
|
+
<span class="text-muted-foreground">Credential ID</span>
|
|
309
|
+
<span class="font-mono text-xs break-all">{{ credential.id }}</span>
|
|
310
|
+
|
|
311
|
+
<span class="text-muted-foreground">Created</span>
|
|
312
|
+
<span class="tabular-nums">{{ formatDateTime(credential.created_at) }}</span>
|
|
313
|
+
|
|
314
|
+
<span class="text-muted-foreground">Updated</span>
|
|
315
|
+
<span class="tabular-nums">{{ formatDateTime(credential.updated_at) }}</span>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
<!-- Danger zone -->
|
|
319
|
+
<div class="rounded-lg border border-rose-500/30 bg-rose-500/[0.03] p-3">
|
|
320
|
+
<div class="text-sm font-semibold text-rose-700">Danger zone</div>
|
|
321
|
+
<div class="mt-1.5 flex items-center justify-between gap-3">
|
|
322
|
+
<p class="text-sm text-muted-foreground">
|
|
323
|
+
Deleting this credential breaks any workflow that references it until it's re-bound.
|
|
324
|
+
</p>
|
|
325
|
+
<Button
|
|
326
|
+
variant="outline"
|
|
327
|
+
size="sm"
|
|
328
|
+
class="shrink-0 border-rose-500/40 text-rose-700 hover:bg-rose-500/10"
|
|
329
|
+
:disabled="deleting"
|
|
330
|
+
@click="destroy"
|
|
331
|
+
>
|
|
332
|
+
<Loader2 v-if="deleting" :size="14" class="mr-1 animate-spin" />
|
|
333
|
+
<Trash2 v-else :size="14" class="mr-1" />
|
|
334
|
+
Delete credential
|
|
335
|
+
</Button>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
</div>
|
|
340
|
+
</DialogContent>
|
|
341
|
+
</Dialog>
|
|
342
|
+
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Credential, CredentialType } from '../../types/integrations.js';
|
|
2
|
+
/**
|
|
3
|
+
* Credential detail / edit view — a single scrolling page (no tabs): the
|
|
4
|
+
* connection state up top, the editable fields, then read-only metadata.
|
|
5
|
+
* Self-contained — owns update / delete / test / OAuth reconnect against the
|
|
6
|
+
* Integrations service via the shared composable.
|
|
7
|
+
*/
|
|
8
|
+
type __VLS_Props = {
|
|
9
|
+
open: boolean;
|
|
10
|
+
credential: Credential | null;
|
|
11
|
+
type: CredentialType | null;
|
|
12
|
+
};
|
|
13
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
14
|
+
"update:open": (args_0: boolean) => any;
|
|
15
|
+
changed: () => any;
|
|
16
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
17
|
+
"onUpdate:open"?: ((args_0: boolean) => any) | undefined;
|
|
18
|
+
onChanged?: (() => any) | undefined;
|
|
19
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
20
|
+
export default _default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CredentialType } from '../../types/integrations.js';
|
|
2
|
+
/**
|
|
3
|
+
* A credential type's brand logo. Renders the `logo` image from the type's
|
|
4
|
+
* `images[]` (a short-lived signed URL from the credential-types API), falling
|
|
5
|
+
* back to a generic key glyph when no image is present or the image fails to
|
|
6
|
+
* load (expired signature / 404). This is the single place that knows how a
|
|
7
|
+
* credential type renders its icon.
|
|
8
|
+
*/
|
|
9
|
+
type __VLS_Props = {
|
|
10
|
+
type?: CredentialType | null;
|
|
11
|
+
size?: number;
|
|
12
|
+
};
|
|
13
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, ref, watch } from "vue";
|
|
3
|
+
import { ShieldKeyhole as KeyIcon } from "#solar-icons";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
type: { type: [Object, null], required: false },
|
|
6
|
+
size: { type: Number, required: false }
|
|
7
|
+
});
|
|
8
|
+
const box = computed(() => (props.size ?? 16) + 16);
|
|
9
|
+
const glyph = computed(() => props.size ?? 16);
|
|
10
|
+
const logoSrc = computed(() => {
|
|
11
|
+
const imgs = props.type?.images;
|
|
12
|
+
if (!imgs?.length) return null;
|
|
13
|
+
const pick = imgs.find((i) => i.category === "logo") ?? imgs[0];
|
|
14
|
+
return typeof pick?.src === "string" && pick.src ? pick.src : null;
|
|
15
|
+
});
|
|
16
|
+
const failed = ref(false);
|
|
17
|
+
watch(logoSrc, () => {
|
|
18
|
+
failed.value = false;
|
|
19
|
+
});
|
|
20
|
+
const showImg = computed(() => !!logoSrc.value && !failed.value);
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<span
|
|
25
|
+
class="flex items-center justify-center overflow-hidden rounded-md bg-slate-100 text-slate-500 shrink-0"
|
|
26
|
+
:style="{ width: `${box}px`, height: `${box}px` }"
|
|
27
|
+
>
|
|
28
|
+
<img
|
|
29
|
+
v-if="showImg"
|
|
30
|
+
:src="logoSrc"
|
|
31
|
+
alt=""
|
|
32
|
+
class="h-full w-full object-contain p-0.5"
|
|
33
|
+
@error="failed = true"
|
|
34
|
+
>
|
|
35
|
+
<KeyIcon v-else :size="glyph" />
|
|
36
|
+
</span>
|
|
37
|
+
</template>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CredentialType } from '../../types/integrations.js';
|
|
2
|
+
/**
|
|
3
|
+
* A credential type's brand logo. Renders the `logo` image from the type's
|
|
4
|
+
* `images[]` (a short-lived signed URL from the credential-types API), falling
|
|
5
|
+
* back to a generic key glyph when no image is present or the image fails to
|
|
6
|
+
* load (expired signature / 404). This is the single place that knows how a
|
|
7
|
+
* credential type renders its icon.
|
|
8
|
+
*/
|
|
9
|
+
type __VLS_Props = {
|
|
10
|
+
type?: CredentialType | null;
|
|
11
|
+
size?: number;
|
|
12
|
+
};
|
|
13
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CredentialType } from '../../types/integrations.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
type: CredentialType | null;
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
"update:active": (args_0: boolean) => any;
|
|
7
|
+
apply: (args_0: Record<string, unknown>) => any;
|
|
8
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
9
|
+
"onUpdate:active"?: ((args_0: boolean) => any) | undefined;
|
|
10
|
+
onApply?: ((args_0: Record<string, unknown>) => any) | undefined;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
export default _default;
|