feat: better tool card

This commit is contained in:
Shivam Mishra
2025-10-03 19:19:19 +05:30
parent 90d4fcf95d
commit 6947ea7f04
3 changed files with 166 additions and 23 deletions

View File

@@ -0,0 +1,142 @@
<script setup>
import { computed } from 'vue';
import { useToggle } from '@vueuse/core';
import { useI18n } from 'vue-i18n';
import { dynamicTime } from 'shared/helpers/timeHelper';
import CardLayout from 'dashboard/components-next/CardLayout.vue';
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
import Button from 'dashboard/components-next/button/Button.vue';
import Policy from 'dashboard/components/policy.vue';
const props = defineProps({
id: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
description: {
type: String,
default: '',
},
authType: {
type: String,
default: 'none',
},
paramSchema: {
type: Array,
default: () => [],
},
updatedAt: {
type: Number,
required: true,
},
createdAt: {
type: Number,
required: true,
},
});
const emit = defineEmits(['action']);
const { t } = useI18n();
const [showActionsDropdown, toggleDropdown] = useToggle();
const menuItems = computed(() => [
{
label: t('CAPTAIN.CUSTOM_TOOLS.OPTIONS.EDIT_TOOL'),
value: 'edit',
action: 'edit',
icon: 'i-lucide-pencil-line',
},
{
label: t('CAPTAIN.CUSTOM_TOOLS.OPTIONS.DELETE_TOOL'),
value: 'delete',
action: 'delete',
icon: 'i-lucide-trash',
},
]);
const timestamp = computed(() =>
dynamicTime(props.updatedAt || props.createdAt)
);
const handleAction = ({ action, value }) => {
toggleDropdown(false);
emit('action', { action, value, id: props.id });
};
const authTypeLabel = computed(() => {
return t(
`CAPTAIN.CUSTOM_TOOLS.FORM.AUTH_TYPES.${props.authType.toUpperCase()}`
);
});
const parameterNames = computed(() => {
if (!props.paramSchema || props.paramSchema.length === 0) return '';
return props.paramSchema.map(p => p.name).join(', ');
});
</script>
<template>
<CardLayout class="relative">
<div class="flex relative justify-between w-full gap-1">
<span class="text-base text-n-slate-12 line-clamp-1 font-medium">
{{ title }}
</span>
<div class="flex items-center gap-2">
<Policy
v-on-clickaway="() => toggleDropdown(false)"
:permissions="['administrator']"
class="relative flex items-center group"
>
<Button
icon="i-lucide-ellipsis-vertical"
color="slate"
size="xs"
class="rounded-md group-hover:bg-n-alpha-2"
@click="toggleDropdown()"
/>
<DropdownMenu
v-if="showActionsDropdown"
:menu-items="menuItems"
class="mt-1 ltr:right-0 rtl:right-0 top-full"
@action="handleAction($event)"
/>
</Policy>
</div>
</div>
<div class="flex items-center justify-between w-full gap-4">
<div class="flex items-center gap-3 flex-1">
<span
v-if="description"
class="text-sm truncate text-n-slate-11 flex-1"
>
{{ description }}
</span>
<span
v-if="authType !== 'none'"
class="text-sm shrink-0 text-n-slate-11 inline-flex items-center gap-1"
>
<i class="i-lucide-lock text-base" />
{{ authTypeLabel }}
</span>
<span
v-if="paramSchema.length > 0"
class="text-sm shrink-0 text-n-slate-11 inline-flex items-center gap-1"
:title="parameterNames"
>
<i class="i-lucide-braces text-base" />
{{ parameterNames }}
</span>
</div>
<span class="text-sm text-n-slate-11 line-clamp-1 shrink-0">
{{ timestamp }}
</span>
</div>
</CardLayout>
</template>

View File

@@ -762,6 +762,10 @@
}
},
"FORM_DESCRIPTION": "Configure your custom tool to connect with external APIs",
"OPTIONS": {
"EDIT_TOOL": "Edit tool",
"DELETE_TOOL": "Delete tool"
},
"CREATE": {
"TITLE": "Create Custom Tool",
"SUCCESS_MESSAGE": "Custom tool created successfully",

View File

@@ -7,6 +7,7 @@ import PageLayout from 'dashboard/components-next/captain/PageLayout.vue';
import CaptainPaywall from 'dashboard/components-next/captain/pageComponents/Paywall.vue';
import CustomToolsPageEmptyState from 'dashboard/components-next/captain/pageComponents/emptyStates/CustomToolsPageEmptyState.vue';
import CreateCustomToolDialog from 'dashboard/components-next/captain/pageComponents/customTool/CreateCustomToolDialog.vue';
import CustomToolCard from 'dashboard/components-next/captain/pageComponents/customTool/CustomToolCard.vue';
const store = useStore();
@@ -27,6 +28,12 @@ const openCreateDialog = () => {
createDialogRef.value.dialogRef.open();
};
const handleAction = ({ action, id }) => {
// TODO: Implement edit and delete actions
// eslint-disable-next-line no-console
console.log('Action:', action, 'ID:', id);
};
onMounted(() => {
fetchCustomTools();
});
@@ -56,31 +63,21 @@ onMounted(() => {
<template #body>
<div class="flex flex-col gap-4">
<div
<CustomToolCard
v-for="tool in customTools"
:id="tool.id"
:key="tool.id"
class="border border-slate-100 dark:border-slate-800 rounded-lg p-4"
>
<h3 class="text-base font-medium text-slate-900 dark:text-slate-100">
{{ tool.title }}
</h3>
<p
v-if="tool.description"
class="text-sm text-slate-600 dark:text-slate-400 mt-1"
>
{{ tool.description }}
</p>
<div class="flex items-center gap-2 mt-2">
<span
class="text-xs px-2 py-1 rounded bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300"
>
{{ tool.http_method }}
</span>
<span class="text-xs text-slate-500 dark:text-slate-400 truncate">
{{ tool.endpoint_url }}
</span>
</div>
</div>
:title="tool.title"
:description="tool.description"
:endpoint-url="tool.endpoint_url"
:http-method="tool.http_method"
:auth-type="tool.auth_type"
:param-schema="tool.param_schema"
:enabled="tool.enabled"
:created-at="tool.created_at"
:updated-at="tool.updated_at"
@action="handleAction"
/>
</div>
</template>
</PageLayout>