mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-11 23:04:59 +00:00
✨ replace roles & users in uptime alert section
This commit is contained in:
@@ -1,18 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useMemo } from "react";
|
|
||||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { BellPlus, BellRing } from "lucide-react";
|
|
||||||
import {
|
|
||||||
SettingsSection,
|
|
||||||
SettingsSectionHeader,
|
|
||||||
SettingsSectionTitle,
|
|
||||||
SettingsSectionDescription,
|
|
||||||
SettingsSectionBody
|
|
||||||
} from "@app/components/Settings";
|
|
||||||
import UptimeBar from "@app/components/UptimeBar";
|
|
||||||
import { Button } from "@app/components/ui/button";
|
|
||||||
import {
|
import {
|
||||||
Credenza,
|
Credenza,
|
||||||
CredenzaBody,
|
CredenzaBody,
|
||||||
@@ -23,18 +10,32 @@ import {
|
|||||||
CredenzaHeader,
|
CredenzaHeader,
|
||||||
CredenzaTitle
|
CredenzaTitle
|
||||||
} from "@app/components/Credenza";
|
} from "@app/components/Credenza";
|
||||||
|
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
|
||||||
|
import {
|
||||||
|
SettingsSection,
|
||||||
|
SettingsSectionBody,
|
||||||
|
SettingsSectionDescription,
|
||||||
|
SettingsSectionHeader,
|
||||||
|
SettingsSectionTitle
|
||||||
|
} from "@app/components/Settings";
|
||||||
|
import UptimeBar from "@app/components/UptimeBar";
|
||||||
|
import { TagInput, type Tag } from "@app/components/tags/tag-input";
|
||||||
|
import { Button } from "@app/components/ui/button";
|
||||||
import { Input } from "@app/components/ui/input";
|
import { Input } from "@app/components/ui/input";
|
||||||
import { Label } from "@app/components/ui/label";
|
import { Label } from "@app/components/ui/label";
|
||||||
import { TagInput, type Tag } from "@app/components/tags/tag-input";
|
|
||||||
import { getUserDisplayName } from "@app/lib/getUserDisplayName";
|
|
||||||
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
|
||||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||||
import { toast } from "@app/hooks/useToast";
|
|
||||||
import { orgQueries } from "@app/lib/queries";
|
|
||||||
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
|
|
||||||
import { usePaidStatus } from "@app/hooks/usePaidStatus";
|
import { usePaidStatus } from "@app/hooks/usePaidStatus";
|
||||||
|
import { toast } from "@app/hooks/useToast";
|
||||||
|
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
||||||
|
import { orgQueries } from "@app/lib/queries";
|
||||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||||
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { BellPlus, BellRing } from "lucide-react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { RolesSelector } from "./roles-selector";
|
||||||
|
import { UsersSelector } from "./users-selector";
|
||||||
|
|
||||||
interface UptimeAlertSectionProps {
|
interface UptimeAlertSectionProps {
|
||||||
orgId: string;
|
orgId: string;
|
||||||
@@ -64,12 +65,7 @@ export default function UptimeAlertSection({
|
|||||||
const [userTags, setUserTags] = useState<Tag[]>([]);
|
const [userTags, setUserTags] = useState<Tag[]>([]);
|
||||||
const [roleTags, setRoleTags] = useState<Tag[]>([]);
|
const [roleTags, setRoleTags] = useState<Tag[]>([]);
|
||||||
const [emailTags, setEmailTags] = useState<Tag[]>([]);
|
const [emailTags, setEmailTags] = useState<Tag[]>([]);
|
||||||
const [activeUserTagIndex, setActiveUserTagIndex] = useState<number | null>(
|
|
||||||
null
|
|
||||||
);
|
|
||||||
const [activeRoleTagIndex, setActiveRoleTagIndex] = useState<number | null>(
|
|
||||||
null
|
|
||||||
);
|
|
||||||
const [activeEmailTagIndex, setActiveEmailTagIndex] = useState<
|
const [activeEmailTagIndex, setActiveEmailTagIndex] = useState<
|
||||||
number | null
|
number | null
|
||||||
>(null);
|
>(null);
|
||||||
@@ -80,27 +76,6 @@ export default function UptimeAlertSection({
|
|||||||
enabled: isPaid
|
enabled: isPaid
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: orgUsers = [] } = useQuery(orgQueries.users({ orgId }));
|
|
||||||
const { data: orgRoles = [] } = useQuery(orgQueries.roles({ orgId }));
|
|
||||||
|
|
||||||
const allUsers = useMemo(
|
|
||||||
() =>
|
|
||||||
orgUsers.map((u) => ({
|
|
||||||
id: String(u.id),
|
|
||||||
text: getUserDisplayName({
|
|
||||||
email: u.email,
|
|
||||||
name: u.name,
|
|
||||||
username: u.username
|
|
||||||
})
|
|
||||||
})),
|
|
||||||
[orgUsers]
|
|
||||||
);
|
|
||||||
|
|
||||||
const allRoles = useMemo(
|
|
||||||
() => orgRoles.map((r) => ({ id: String(r.roleId), text: r.name })),
|
|
||||||
[orgRoles]
|
|
||||||
);
|
|
||||||
|
|
||||||
const hasRules = (alertRules?.length ?? 0) > 0;
|
const hasRules = (alertRules?.length ?? 0) > 0;
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
@@ -227,10 +202,16 @@ export default function UptimeAlertSection({
|
|||||||
</CredenzaHeader>
|
</CredenzaHeader>
|
||||||
<CredenzaBody>
|
<CredenzaBody>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<PaidFeaturesAlert tiers={tierMatrix.alertingRules} />
|
<PaidFeaturesAlert
|
||||||
|
tiers={tierMatrix.alertingRules}
|
||||||
|
/>
|
||||||
<fieldset
|
<fieldset
|
||||||
disabled={!isPaid}
|
disabled={!isPaid}
|
||||||
className={!isPaid ? "opacity-50 pointer-events-none" : ""}
|
className={
|
||||||
|
!isPaid
|
||||||
|
? "opacity-50 pointer-events-none"
|
||||||
|
: ""
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -240,65 +221,53 @@ export default function UptimeAlertSection({
|
|||||||
<Input
|
<Input
|
||||||
id="alert-name"
|
id="alert-name"
|
||||||
value={name}
|
value={name}
|
||||||
onChange={(e) => setName(e.target.value)}
|
onChange={(e) =>
|
||||||
placeholder={t("uptimeAlertNamePlaceholder")}
|
setName(e.target.value)
|
||||||
|
}
|
||||||
|
placeholder={t(
|
||||||
|
"uptimeAlertNamePlaceholder"
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>{t("alertingNotifyUsers")}</Label>
|
<Label>
|
||||||
<TagInput
|
{t("alertingNotifyUsers")}
|
||||||
activeTagIndex={activeUserTagIndex}
|
</Label>
|
||||||
setActiveTagIndex={setActiveUserTagIndex}
|
<UsersSelector
|
||||||
placeholder={t("alertingSelectUsers")}
|
selectedUsers={userTags}
|
||||||
size="sm"
|
orgId={orgId}
|
||||||
tags={userTags}
|
onSelectUsers={setUserTags}
|
||||||
setTags={(newTags) => {
|
|
||||||
const next =
|
|
||||||
typeof newTags === "function"
|
|
||||||
? newTags(userTags)
|
|
||||||
: newTags;
|
|
||||||
setUserTags(next as Tag[]);
|
|
||||||
}}
|
|
||||||
enableAutocomplete
|
|
||||||
autocompleteOptions={allUsers}
|
|
||||||
restrictTagsToAutocompleteOptions
|
|
||||||
allowDuplicates={false}
|
|
||||||
sortTags
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>{t("alertingNotifyRoles")}</Label>
|
<Label>
|
||||||
<TagInput
|
{t("alertingNotifyRoles")}
|
||||||
activeTagIndex={activeRoleTagIndex}
|
</Label>
|
||||||
setActiveTagIndex={setActiveRoleTagIndex}
|
<RolesSelector
|
||||||
placeholder={t("alertingSelectRoles")}
|
selectedRoles={roleTags}
|
||||||
size="sm"
|
restrictAdminRole
|
||||||
tags={roleTags}
|
orgId={orgId}
|
||||||
setTags={(newTags) => {
|
onSelectRoles={setRoleTags}
|
||||||
const next =
|
|
||||||
typeof newTags === "function"
|
|
||||||
? newTags(roleTags)
|
|
||||||
: newTags;
|
|
||||||
setRoleTags(next as Tag[]);
|
|
||||||
}}
|
|
||||||
enableAutocomplete
|
|
||||||
autocompleteOptions={allRoles}
|
|
||||||
restrictTagsToAutocompleteOptions
|
|
||||||
allowDuplicates={false}
|
|
||||||
sortTags
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>{t("uptimeAdditionalEmails")}</Label>
|
<Label>
|
||||||
|
{t("uptimeAdditionalEmails")}
|
||||||
|
</Label>
|
||||||
<TagInput
|
<TagInput
|
||||||
activeTagIndex={activeEmailTagIndex}
|
activeTagIndex={activeEmailTagIndex}
|
||||||
setActiveTagIndex={setActiveEmailTagIndex}
|
setActiveTagIndex={
|
||||||
placeholder={t("alertingEmailPlaceholder")}
|
setActiveEmailTagIndex
|
||||||
|
}
|
||||||
|
placeholder={t(
|
||||||
|
"alertingEmailPlaceholder"
|
||||||
|
)}
|
||||||
size="sm"
|
size="sm"
|
||||||
tags={emailTags}
|
tags={emailTags}
|
||||||
setTags={(newTags) => {
|
setTags={(newTags) => {
|
||||||
const next =
|
const next =
|
||||||
typeof newTags === "function"
|
typeof newTags ===
|
||||||
|
"function"
|
||||||
? newTags(emailTags)
|
? newTags(emailTags)
|
||||||
: newTags;
|
: newTags;
|
||||||
setEmailTags(next as Tag[]);
|
setEmailTags(next as Tag[]);
|
||||||
@@ -306,7 +275,9 @@ export default function UptimeAlertSection({
|
|||||||
allowDuplicates={false}
|
allowDuplicates={false}
|
||||||
sortTags
|
sortTags
|
||||||
validateTag={(tag) =>
|
validateTag={(tag) =>
|
||||||
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(tag)
|
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(
|
||||||
|
tag
|
||||||
|
)
|
||||||
}
|
}
|
||||||
delimiterList={[",", "Enter"]}
|
delimiterList={[",", "Enter"]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user