feat: apply Frame component to webhooks settings page (#27291)
* feat: apply Frame component to webhooks settings page Co-Authored-By: peer@cal.com <peer@cal.com> * refactor: include header and description in Frame component Co-Authored-By: peer@cal.com <peer@cal.com> * refactor: wrap each webhook in individual FramePanel Co-Authored-By: peer@cal.com <peer@cal.com> * refactor: implement two-row badge limit with overflow tooltip for webhooks Co-Authored-By: peer@cal.com <peer@cal.com> * style: improve spacing between webhook items and header Co-Authored-By: peer@cal.com <peer@cal.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
peer@cal.com
Devin AI
parent
cb7960f571
commit
85f3cd6228
@@ -1,8 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
|
||||
import { getWebhookVersionLabel, getWebhookVersionDocsUrl } from "@calcom/features/webhooks/lib/constants";
|
||||
import { getWebhookVersionDocsUrl, getWebhookVersionLabel } from "@calcom/features/webhooks/lib/constants";
|
||||
import type { Webhook } from "@calcom/features/webhooks/lib/dto/types";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
@@ -23,6 +21,9 @@ import { showToast } from "@calcom/ui/components/toast";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
import { revalidateEventTypeEditPage } from "@calcom/web/app/(use-page-wrapper)/event-types/[type]/actions";
|
||||
import { revalidateWebhooksList } from "@calcom/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/webhooks/(with-loader)/actions";
|
||||
import Link from "next/link";
|
||||
|
||||
const MAX_BADGES_TWO_ROWS = 8; // Approximately 2 rows of badges
|
||||
|
||||
export default function WebhookListItem(props: {
|
||||
webhook: Webhook;
|
||||
@@ -105,7 +106,7 @@ export default function WebhookListItem(props: {
|
||||
</div>
|
||||
<Tooltip content={t("triggers_when")}>
|
||||
<div className="flex w-4/5 flex-wrap">
|
||||
{webhook.eventTriggers.map((trigger) => (
|
||||
{webhook.eventTriggers.slice(0, MAX_BADGES_TWO_ROWS).map((trigger) => (
|
||||
<Badge
|
||||
key={trigger}
|
||||
className="mt-2.5 basis-1/5 ltr:mr-2 rtl:ml-2"
|
||||
@@ -114,6 +115,22 @@ export default function WebhookListItem(props: {
|
||||
{t(`${trigger.toLowerCase()}`)}
|
||||
</Badge>
|
||||
))}
|
||||
{webhook.eventTriggers.length > MAX_BADGES_TWO_ROWS && (
|
||||
<Tooltip
|
||||
content={
|
||||
<div className="flex flex-col gap-1 p-1">
|
||||
{webhook.eventTriggers.slice(MAX_BADGES_TWO_ROWS).map((trigger) => (
|
||||
<span key={trigger} className="text-xs">
|
||||
{t(`${trigger.toLowerCase()}`)}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
}>
|
||||
<Badge className="mt-2.5 cursor-help ltr:mr-2 rtl:ml-2" variant="gray">
|
||||
+{webhook.eventTriggers.length - MAX_BADGES_TWO_ROWS} {t("more")}
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
"use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { useBookerUrl } from "@calcom/features/bookings/hooks/useBookerUrl";
|
||||
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
|
||||
import { APP_NAME, WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import classNames from "@calcom/ui/classNames";
|
||||
import { Avatar } from "@calcom/ui/components/avatar";
|
||||
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
|
||||
|
||||
import { WebhookListItem, CreateNewWebhookButton } from "../components";
|
||||
import { Frame, FrameDescription, FrameHeader, FramePanel, FrameTitle } from "@coss/ui/components/frame";
|
||||
import { useRouter } from "next/navigation";
|
||||
import React from "react";
|
||||
import { CreateNewWebhookButton, WebhookListItem } from "../components";
|
||||
|
||||
type WebhooksByViewer = RouterOutputs["viewer"]["webhook"]["getByViewer"];
|
||||
|
||||
@@ -36,17 +34,20 @@ const WebhooksList = ({ webhooksByViewer }: { webhooksByViewer: WebhooksByViewer
|
||||
const hasTeams = profiles && profiles.length > 1;
|
||||
|
||||
return (
|
||||
<SettingsHeader
|
||||
title={t("webhooks")}
|
||||
description={t("add_webhook_description", { appName: APP_NAME })}
|
||||
CTA={<CreateNewWebhookButton />}
|
||||
borderInShellHeader={true}>
|
||||
{webhookGroups.length ? (
|
||||
<Frame>
|
||||
<FrameHeader className="mb-2 flex-row items-center justify-between">
|
||||
<div>
|
||||
<FrameTitle className="text-lg">{t("webhooks")}</FrameTitle>
|
||||
<FrameDescription>{t("add_webhook_description", { appName: APP_NAME })}</FrameDescription>
|
||||
</div>
|
||||
<CreateNewWebhookButton />
|
||||
</FrameHeader>
|
||||
{webhookGroups.length ? (
|
||||
<>
|
||||
{webhookGroups.map((group) => (
|
||||
<div key={group.teamId}>
|
||||
<React.Fragment key={group.teamId}>
|
||||
{hasTeams && (
|
||||
<div className="items-centers flex">
|
||||
<div className="mb-2 mt-4 flex items-center px-1">
|
||||
<Avatar
|
||||
alt={group.profile.image || ""}
|
||||
imageSrc={group.profile.image || `${bookerUrl}/${group.profile.name}/avatar.png`}
|
||||
@@ -58,37 +59,35 @@ const WebhooksList = ({ webhooksByViewer }: { webhooksByViewer: WebhooksByViewer
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col" key={group.profile.slug}>
|
||||
<div className={classNames("border-subtle mb-8 rounded-b-lg border border-t-0", hasTeams && "mt-3")}>
|
||||
{group.webhooks.map((webhook, index) => (
|
||||
<WebhookListItem
|
||||
key={webhook.id}
|
||||
webhook={webhook}
|
||||
lastItem={group.webhooks.length === index + 1}
|
||||
permissions={{
|
||||
canEditWebhook: group?.metadata?.canModify ?? false,
|
||||
canDeleteWebhook: group?.metadata?.canDelete ?? false,
|
||||
}}
|
||||
onEditWebhook={() =>
|
||||
router.push(`${WEBAPP_URL}/settings/developer/webhooks/${webhook.id}`)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{group.webhooks.map((webhook) => (
|
||||
<FramePanel key={webhook.id} className="mt-2">
|
||||
<WebhookListItem
|
||||
webhook={webhook}
|
||||
lastItem={true}
|
||||
permissions={{
|
||||
canEditWebhook: group?.metadata?.canModify ?? false,
|
||||
canDeleteWebhook: group?.metadata?.canDelete ?? false,
|
||||
}}
|
||||
onEditWebhook={() =>
|
||||
router.push(`${WEBAPP_URL}/settings/developer/webhooks/${webhook.id}`)
|
||||
}
|
||||
/>
|
||||
</FramePanel>
|
||||
))}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<EmptyScreen
|
||||
Icon="link"
|
||||
headline={t("create_your_first_webhook")}
|
||||
description={t("create_your_first_webhook_description", { appName: APP_NAME })}
|
||||
className="rounded-b-lg rounded-t-none border-t-0"
|
||||
buttonRaw={<CreateNewWebhookButton />}
|
||||
/>
|
||||
<FramePanel>
|
||||
<EmptyScreen
|
||||
Icon="link"
|
||||
headline={t("create_your_first_webhook")}
|
||||
description={t("create_your_first_webhook_description", { appName: APP_NAME })}
|
||||
buttonRaw={<CreateNewWebhookButton />}
|
||||
/>
|
||||
</FramePanel>
|
||||
)}
|
||||
</SettingsHeader>
|
||||
</Frame>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user