mirror of https://github.com/buster-so/buster.git
Make slack cards better
This commit is contained in:
parent
35a160301a
commit
6f6e70c54c
|
@ -1,7 +1,4 @@
|
||||||
import type {
|
import type { GetIntegrationResponse, GetChannelsResponse } from '@buster/server-shared/slack';
|
||||||
GetIntegrationResponse,
|
|
||||||
GetChannelsResponse
|
|
||||||
} from '@buster/server-shared/slack';
|
|
||||||
import { queryOptions } from '@tanstack/react-query';
|
import { queryOptions } from '@tanstack/react-query';
|
||||||
|
|
||||||
export const slackGetIntegration = queryOptions<GetIntegrationResponse>({
|
export const slackGetIntegration = queryOptions<GetIntegrationResponse>({
|
||||||
|
@ -9,7 +6,7 @@ export const slackGetIntegration = queryOptions<GetIntegrationResponse>({
|
||||||
});
|
});
|
||||||
|
|
||||||
export const slackGetChannels = queryOptions<GetChannelsResponse>({
|
export const slackGetChannels = queryOptions<GetChannelsResponse>({
|
||||||
queryKey: ['slack', 'channels']
|
queryKey: ['slack', 'channels', 'list']
|
||||||
});
|
});
|
||||||
|
|
||||||
export const slackQueryKeys = {
|
export const slackQueryKeys = {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { SettingsCards } from '../settings/SettingsCard';
|
import { SettingsCards } from '../settings/SettingsCard';
|
||||||
import { SlackIcon } from '@/components/ui/icons/customIcons/SlackIcon';
|
import { SlackIcon } from '@/components/ui/icons/customIcons/SlackIcon';
|
||||||
import { Text } from '@/components/ui/typography';
|
import { Text } from '@/components/ui/typography';
|
||||||
|
@ -15,25 +15,34 @@ import {
|
||||||
import { Dropdown, type DropdownItems } from '@/components/ui/dropdown';
|
import { Dropdown, type DropdownItems } from '@/components/ui/dropdown';
|
||||||
import { LinkSlash, Refresh2 } from '@/components/ui/icons';
|
import { LinkSlash, Refresh2 } from '@/components/ui/icons';
|
||||||
import { Select } from '@/components/ui/select';
|
import { Select } from '@/components/ui/select';
|
||||||
|
import { StatusCard } from '@/components/ui/card/StatusCard';
|
||||||
|
import { useMemoizedFn } from '@/hooks';
|
||||||
|
|
||||||
export const SlackIntegrations = React.memo(() => {
|
export const SlackIntegrations = React.memo(() => {
|
||||||
const { data: slackIntegration } = useGetSlackIntegration();
|
const {
|
||||||
|
data: slackIntegration,
|
||||||
|
isFetched: isFetchedSlackIntegration,
|
||||||
|
error: slackIntegrationError
|
||||||
|
} = useGetSlackIntegration();
|
||||||
const isConnected = slackIntegration?.connected ?? false;
|
const isConnected = slackIntegration?.connected ?? false;
|
||||||
|
|
||||||
return (
|
const cards = useMemo(() => {
|
||||||
<SettingsCards
|
const sections = [
|
||||||
title="Slack"
|
<ConnectSlackCard key="connect-slack-card" />,
|
||||||
description="Connect Buster with Slack"
|
isConnected && <ConnectedSlackChannels key="connected-slack-channels" />
|
||||||
cards={[
|
].filter(Boolean);
|
||||||
{
|
return [{ sections }];
|
||||||
sections: [
|
}, [isConnected]);
|
||||||
<ConnectSlackCard key="connect-slack-card" />,
|
|
||||||
isConnected && <ConnectedSlackChannels key="connected-slack-channels" />
|
if (slackIntegrationError) {
|
||||||
].filter(Boolean)
|
return <StatusCard message="Error fetching slack integration." variant={'danger'} />;
|
||||||
}
|
}
|
||||||
]}
|
|
||||||
/>
|
if (!isFetchedSlackIntegration) {
|
||||||
);
|
return <div className="bg-gray-light/50 h-24 w-full animate-pulse rounded"></div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <SettingsCards title="Slack" description="Connect Buster with Slack" cards={cards} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
SlackIntegrations.displayName = 'SlackIntegrations';
|
SlackIntegrations.displayName = 'SlackIntegrations';
|
||||||
|
@ -112,6 +121,21 @@ const ConnectedSlackChannels = React.memo(() => {
|
||||||
const channels = slackChannelsData?.channels || [];
|
const channels = slackChannelsData?.channels || [];
|
||||||
const selectedChannelId = slackIntegration?.integration?.default_channel?.id;
|
const selectedChannelId = slackIntegration?.integration?.default_channel?.id;
|
||||||
|
|
||||||
|
const items = useMemo(() => {
|
||||||
|
return channels.map((channel) => ({
|
||||||
|
label: channel.name,
|
||||||
|
value: channel.id
|
||||||
|
}));
|
||||||
|
}, [channels]);
|
||||||
|
|
||||||
|
const onChange = useMemoizedFn((channelId: string) => {
|
||||||
|
const channel = channels.find((channel) => channel.id === channelId);
|
||||||
|
if (!channel) return;
|
||||||
|
updateSlackIntegration({
|
||||||
|
default_channel: channel
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between space-x-4">
|
<div className="flex items-center justify-between space-x-4">
|
||||||
<div className="flex flex-col space-y-0.5">
|
<div className="flex flex-col space-y-0.5">
|
||||||
|
@ -125,7 +149,7 @@ const ConnectedSlackChannels = React.memo(() => {
|
||||||
<>
|
<>
|
||||||
{isFetchedSlackChannels && (
|
{isFetchedSlackChannels && (
|
||||||
<Button
|
<Button
|
||||||
size={'small'}
|
size={'tall'}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
suffix={<Refresh2 />}
|
suffix={<Refresh2 />}
|
||||||
onClick={() => refetchSlackChannels()}>
|
onClick={() => refetchSlackChannels()}>
|
||||||
|
@ -135,19 +159,10 @@ const ConnectedSlackChannels = React.memo(() => {
|
||||||
|
|
||||||
<Select
|
<Select
|
||||||
className="w-fit min-w-40"
|
className="w-fit min-w-40"
|
||||||
items={channels.map((channel) => ({
|
items={items}
|
||||||
label: channel.name,
|
|
||||||
value: channel.id
|
|
||||||
}))}
|
|
||||||
placeholder="Select a channel"
|
placeholder="Select a channel"
|
||||||
value={selectedChannelId}
|
value={selectedChannelId}
|
||||||
onChange={(channelId) => {
|
onChange={onChange}
|
||||||
const channel = channels.find((channel) => channel.id === channelId);
|
|
||||||
if (!channel) return;
|
|
||||||
updateSlackIntegration({
|
|
||||||
default_channel: channel
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
loading={isLoadingSlackChannels || isLoadingSlackIntegration}
|
loading={isLoadingSlackChannels || isLoadingSlackIntegration}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -10,21 +10,24 @@ interface SettingsCardsProps {
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SettingsCards: React.FC<SettingsCardsProps> = ({ title, description, cards }) => {
|
export const SettingsCards: React.FC<SettingsCardsProps> = React.memo(
|
||||||
return (
|
({ title, description, cards }) => {
|
||||||
<div className="flex flex-col space-y-3.5">
|
return (
|
||||||
<div className="flex flex-col space-y-1.5">
|
<div className="flex flex-col space-y-3.5">
|
||||||
<Title as="h3" className="text-lg">
|
<div className="flex flex-col space-y-1.5">
|
||||||
{title}
|
<Title as="h3" className="text-lg">
|
||||||
</Title>
|
{title}
|
||||||
<Paragraph variant="secondary">{description}</Paragraph>
|
</Title>
|
||||||
|
<Paragraph variant="secondary">{description}</Paragraph>
|
||||||
|
</div>
|
||||||
|
{cards.map((card, index) => (
|
||||||
|
<SettingsCard key={index} sections={card.sections} />
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
{cards.map((card, index) => (
|
);
|
||||||
<SettingsCard key={index} sections={card.sections} />
|
}
|
||||||
))}
|
);
|
||||||
</div>
|
SettingsCards.displayName = 'SettingsCards';
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const SettingsCard = ({ sections }: { sections: React.ReactNode[] }) => {
|
const SettingsCard = ({ sections }: { sections: React.ReactNode[] }) => {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -8,7 +8,7 @@ const buster = packageJson.version;
|
||||||
|
|
||||||
export const PERSIST_TIME = 1000 * 60 * 60 * 24 * 7; // 7 days
|
export const PERSIST_TIME = 1000 * 60 * 60 * 24 * 7; // 7 days
|
||||||
|
|
||||||
export const PERSISTED_QUERIES = [].map(hashKey);
|
export const PERSISTED_QUERIES = [queryKeys.slackGetChannels.queryKey].map(hashKey);
|
||||||
|
|
||||||
export const PERMANENT_QUERIES = [queryKeys.getCurrencies.queryKey].map(hashKey);
|
export const PERMANENT_QUERIES = [queryKeys.getCurrencies.queryKey].map(hashKey);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue