@nuxtagentic/integrations 0.0.0-stage → 0.1.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/LICENSE.md +9 -0
- package/README.md +175 -2
- package/client.ts +124 -0
- package/module.ts +44 -0
- package/package.json +52 -3
- package/runtime/assets/logos/discord.svg +1 -0
- package/runtime/assets/logos/github.svg +1 -0
- package/runtime/assets/logos/gmail.svg +1 -0
- package/runtime/assets/logos/googleads.svg +1 -0
- package/runtime/assets/logos/googleanalytics.svg +1 -0
- package/runtime/assets/logos/googlecalendar.svg +1 -0
- package/runtime/assets/logos/googledrive.svg +1 -0
- package/runtime/assets/logos/googlesearchconsole.svg +1 -0
- package/runtime/assets/logos/hubspot.svg +1 -0
- package/runtime/assets/logos/intercom.svg +1 -0
- package/runtime/assets/logos/linear.svg +1 -0
- package/runtime/assets/logos/mcp.svg +1 -0
- package/runtime/assets/logos/meta.svg +1 -0
- package/runtime/assets/logos/notion.svg +1 -0
- package/runtime/assets/logos/reddit.svg +1 -0
- package/runtime/assets/logos/sentry.svg +1 -0
- package/runtime/assets/logos/shopify.svg +1 -0
- package/runtime/assets/logos/slack.svg +1 -0
- package/runtime/assets/logos/stripe.svg +1 -0
- package/runtime/assets/logos/tiktok-dark.svg +1 -0
- package/runtime/assets/logos/tiktok.svg +1 -0
- package/runtime/assets/logos/vercel.svg +1 -0
- package/runtime/assets/logos/x.svg +1 -0
- package/runtime/components/IntegrationCard.vue +82 -0
- package/runtime/components/IntegrationCatalog.vue +130 -0
- package/runtime/components/IntegrationConnectionPanel.vue +589 -0
- package/runtime/components/IntegrationLogo.vue +41 -0
- package/runtime/pages/integrations.vue +481 -0
- package/runtime/server/api/integrations/approvals/[id].post.ts +69 -0
- package/runtime/server/api/integrations/catalog/[provider]/action.post.ts +35 -0
- package/runtime/server/api/integrations/catalog/[provider]/connection.post.ts +242 -0
- package/runtime/server/api/integrations/catalog/[provider]/tools.get.ts +40 -0
- package/runtime/server/api/integrations/catalog/index.get.ts +48 -0
- package/runtime/server/api/integrations/catalog/tools.get.ts +27 -0
- package/runtime/server/plugins/connect-maintenance.ts +30 -0
- package/runtime/server/utils/approval-continuation.ts +37 -0
- package/runtime/server/utils/google-mcp.ts +296 -0
- package/runtime/server/utils/integration-adapters.ts +836 -0
- package/runtime/server/utils/integration-context.ts +510 -0
- package/runtime/server/utils/integration-crypto.ts +13 -0
- package/runtime/server/utils/request-body.ts +38 -0
- package/runtime/shared/agent.ts +14 -0
- package/runtime/shared/catalog.ts +566 -0
- package/runtime/shared/google-mcp.ts +8 -0
- package/runtime/workspace.ts +15 -0
- package/schema.ts +179 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import type { IntegrationConnection } from '../../client'
|
|
4
|
+
import {
|
|
5
|
+
INTEGRATION_CATALOG,
|
|
6
|
+
INTEGRATION_CATEGORIES,
|
|
7
|
+
type IntegrationDefinition,
|
|
8
|
+
} from '../shared/catalog'
|
|
9
|
+
import IntegrationCard from './IntegrationCard.vue'
|
|
10
|
+
|
|
11
|
+
const tab = defineModel<string>('tab', { required: true })
|
|
12
|
+
const category = defineModel<string>('category', { required: true })
|
|
13
|
+
const search = defineModel<string>('search', { required: true })
|
|
14
|
+
const { connections, loading, error } = defineProps<{
|
|
15
|
+
connections: IntegrationConnection[]
|
|
16
|
+
loading?: boolean
|
|
17
|
+
error?: boolean
|
|
18
|
+
}>()
|
|
19
|
+
defineEmits<{ select: [integration: IntegrationDefinition, event: MouseEvent] }>()
|
|
20
|
+
|
|
21
|
+
const connectionsOf = (provider: string) =>
|
|
22
|
+
connections.filter((entry) => entry.provider === provider)
|
|
23
|
+
const isConnected = (provider: string) => connectionsOf(provider).some((entry) => entry.enabled)
|
|
24
|
+
const filteredCatalog = computed(() => {
|
|
25
|
+
const query = search.value.trim().toLowerCase()
|
|
26
|
+
return INTEGRATION_CATALOG.filter(
|
|
27
|
+
(entry) =>
|
|
28
|
+
(category.value === 'All' || entry.category === category.value) &&
|
|
29
|
+
`${entry.name} ${entry.category} ${entry.description}`.toLowerCase().includes(query),
|
|
30
|
+
)
|
|
31
|
+
})
|
|
32
|
+
const visible = computed(() =>
|
|
33
|
+
filteredCatalog.value.filter(
|
|
34
|
+
(entry) => tab.value === 'all' || (tab.value === 'connected') === isConnected(entry.id),
|
|
35
|
+
),
|
|
36
|
+
)
|
|
37
|
+
const tabs = computed(() => {
|
|
38
|
+
const total = filteredCatalog.value.length
|
|
39
|
+
const connectedCount = filteredCatalog.value.filter((entry) => isConnected(entry.id)).length
|
|
40
|
+
return [
|
|
41
|
+
{ label: 'All', value: 'all', count: total },
|
|
42
|
+
{ label: 'Connected', value: 'connected', count: connectedCount },
|
|
43
|
+
{ label: 'Available', value: 'available', count: total - connectedCount },
|
|
44
|
+
]
|
|
45
|
+
})
|
|
46
|
+
const emptyMessage = computed(() => {
|
|
47
|
+
if (!filteredCatalog.value.length) {
|
|
48
|
+
return 'No integrations match your filters.'
|
|
49
|
+
}
|
|
50
|
+
return tab.value === 'connected'
|
|
51
|
+
? 'No connected integrations here yet. Choose Available to connect an app.'
|
|
52
|
+
: 'All integrations here are connected. Choose Connected to manage them.'
|
|
53
|
+
})
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<template>
|
|
57
|
+
<div class="flex flex-col gap-5">
|
|
58
|
+
<div class="flex flex-wrap items-center gap-3">
|
|
59
|
+
<UTabs
|
|
60
|
+
:model-value="tab"
|
|
61
|
+
:items="tabs"
|
|
62
|
+
:content="false"
|
|
63
|
+
color="neutral"
|
|
64
|
+
variant="pill"
|
|
65
|
+
aria-label="Integration status"
|
|
66
|
+
class="w-full sm:w-[350px]"
|
|
67
|
+
:ui="{
|
|
68
|
+
root: 'gap-0',
|
|
69
|
+
list: 'h-9 rounded-lg border border-(--gray-500) bg-(--gray-200) p-0.5',
|
|
70
|
+
trigger:
|
|
71
|
+
'flex-auto cursor-pointer gap-2 rounded-md px-2 py-0 text-[13px] font-normal data-[state=active]:text-highlighted sm:px-3',
|
|
72
|
+
indicator: 'inset-y-0.5 rounded-md bg-(--gray-400) shadow-none ring-0',
|
|
73
|
+
}"
|
|
74
|
+
@update:model-value="tab = String($event)"
|
|
75
|
+
>
|
|
76
|
+
<template #trailing="{ item }">
|
|
77
|
+
<span class="text-xs text-dimmed tabular-nums group-data-[state=active]:text-muted">
|
|
78
|
+
{{ item.count }}
|
|
79
|
+
</span>
|
|
80
|
+
</template>
|
|
81
|
+
</UTabs>
|
|
82
|
+
<UInput
|
|
83
|
+
v-model="search"
|
|
84
|
+
icon="i-lucide-search"
|
|
85
|
+
placeholder="Search integrations"
|
|
86
|
+
aria-label="Search integrations"
|
|
87
|
+
class="w-full sm:ms-auto sm:w-60"
|
|
88
|
+
:ui="{ base: 'h-9 rounded-lg bg-transparent text-[13px]', leadingIcon: 'size-3.5' }"
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
<div class="flex flex-wrap gap-1.5">
|
|
92
|
+
<UButton
|
|
93
|
+
v-for="item in INTEGRATION_CATEGORIES"
|
|
94
|
+
:key="item"
|
|
95
|
+
:label="item"
|
|
96
|
+
color="neutral"
|
|
97
|
+
:variant="category === item ? 'soft' : 'ghost'"
|
|
98
|
+
class="h-7 rounded-full px-3 text-[13px] font-normal"
|
|
99
|
+
:class="category === item ? 'bg-(--gray-400) text-highlighted ring ring-(--gray-500)' : ''"
|
|
100
|
+
:aria-pressed="category === item"
|
|
101
|
+
@click="category = item"
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
<div
|
|
105
|
+
v-if="loading"
|
|
106
|
+
class="flex items-center gap-2 text-sm text-muted"
|
|
107
|
+
>
|
|
108
|
+
<UIcon
|
|
109
|
+
name="i-lucide-loader-circle"
|
|
110
|
+
class="size-4 animate-spin"
|
|
111
|
+
/>
|
|
112
|
+
Loading connections…
|
|
113
|
+
</div>
|
|
114
|
+
<div class="grid grid-cols-[repeat(auto-fill,minmax(min(260px,100%),1fr))] gap-3">
|
|
115
|
+
<IntegrationCard
|
|
116
|
+
v-for="entry in visible"
|
|
117
|
+
:key="entry.id"
|
|
118
|
+
:integration="entry"
|
|
119
|
+
:connections="connectionsOf(entry.id)"
|
|
120
|
+
@select="$emit('select', entry, $event)"
|
|
121
|
+
/>
|
|
122
|
+
</div>
|
|
123
|
+
<p
|
|
124
|
+
v-if="!loading && !error && !visible.length"
|
|
125
|
+
class="mt-6 text-center text-sm text-dimmed"
|
|
126
|
+
>
|
|
127
|
+
{{ emptyMessage }}
|
|
128
|
+
</p>
|
|
129
|
+
</div>
|
|
130
|
+
</template>
|