From c61748cd6eb0a03024be14b2cef8cce4c483c755 Mon Sep 17 00:00:00 2001 From: nitin <142569587+ehconitin@users.noreply.github.com> Date: Thu, 13 Mar 2025 01:25:38 +0530 Subject: [PATCH] Admin panel fixes (#10792) Screenshot 2025-03-12 at 17 36 44 Screenshot 2025-03-12 at 17 37 03 Screenshot 2025-03-12 at 17 37 14 Screenshot 2025-03-12 at 17 37 37 Screenshot 2025-03-12 at 17 37 50 --- .../SettingsAdminEnvCopyableText.tsx | 63 +++++++ .../components/SettingsAdminEnvVariables.tsx | 34 ++-- .../SettingsAdminEnvVariablesRow.tsx | 115 ++++++------ .../SettingsAdminEnvVariablesTable.tsx | 47 +++-- .../components/SettingsAdminGeneral.tsx | 79 +++++---- .../components/SettingsAdminTableCard.tsx | 93 ++++++++++ .../SettingsAdminVersionContainer.tsx | 107 ++++-------- .../SettingsAdminWorkspaceContent.tsx | 161 +++++++++++------ .../ConnectedAccountHealthStatus.tsx | 10 +- .../JsonDataIndicatorHealthStatus.tsx | 2 +- .../components/WorkerMetricsGraph.tsx | 165 ++++-------------- .../components/WorkerMetricsTooltip.tsx | 68 ++++++++ .../components/WorkerQueueMetricsSection.tsx | 44 ++++- .../SettingsListItemCardContent.tsx | 17 +- .../SettingsAdminIndicatorHealthStatus.tsx | 45 ++--- .../SettingsAdminSecondaryEnvVariables.tsx | 25 ++- .../constants/health-indicators.constants.ts | 14 +- .../{__tests__ => }/impersonate-guard.spec.ts | 0 .../display/icon/components/TablerIcons.ts | 10 +- .../display/typography/components/H2Title.tsx | 11 +- 20 files changed, 670 insertions(+), 440 deletions(-) create mode 100644 packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvCopyableText.tsx create mode 100644 packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx create mode 100644 packages/twenty-front/src/modules/settings/admin-panel/health-status/components/WorkerMetricsTooltip.tsx rename packages/twenty-server/src/engine/guards/{__tests__ => }/impersonate-guard.spec.ts (100%) diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvCopyableText.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvCopyableText.tsx new file mode 100644 index 000000000..798c85374 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvCopyableText.tsx @@ -0,0 +1,63 @@ +import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; +import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { useLingui } from '@lingui/react/macro'; +import { IconCopy, OverflowingTextWithTooltip } from 'twenty-ui'; +import { useDebouncedCallback } from 'use-debounce'; + +const StyledEllipsisLabel = styled.div` + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +`; + +const StyledExpandedEllipsisLabel = styled.div` + white-space: normal; + word-break: break-all; +`; + +const StyledCopyContainer = styled.span` + cursor: pointer; +`; +export const SettingsAdminEnvCopyableText = ({ + text, + displayText, + multiline = false, + maxRows, +}: { + text: string; + displayText?: React.ReactNode; + multiline?: boolean; + maxRows?: number; +}) => { + const { enqueueSnackBar } = useSnackBar(); + const theme = useTheme(); + const { t } = useLingui(); + + const copyToClipboardDebounced = useDebouncedCallback((value: string) => { + navigator.clipboard.writeText(value); + enqueueSnackBar(t`Copied to clipboard!`, { + variant: SnackBarVariant.Success, + icon: , + }); + }, 200); + + return ( + copyToClipboardDebounced(text)}> + {maxRows ? ( + + ) : multiline ? ( + + {displayText || text} + + ) : ( + {displayText || text} + )} + + ); +}; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariables.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariables.tsx index 206e33f39..6daf385be 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariables.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariables.tsx @@ -10,14 +10,16 @@ import { Card, H2Title, IconHeartRateMonitor, Section } from 'twenty-ui'; import { useGetEnvironmentVariablesGroupedQuery } from '~/generated/graphql'; import { getSettingsPath } from '~/utils/navigation/getSettingsPath'; -const StyledGroupContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(6)}; -`; +const StyledGroupContainer = styled.div``; const StyledInfoText = styled.div` color: ${({ theme }) => theme.font.color.secondary}; `; +const StyledCard = styled(Card)` + margin-bottom: ${({ theme }) => theme.spacing(8)}; +`; + export const SettingsAdminEnvVariables = () => { const theme = useTheme(); const { data: environmentVariables, loading: environmentVariablesLoading } = @@ -38,22 +40,20 @@ export const SettingsAdminEnvVariables = () => { <>
- {t` These are only the server values. Ensure your worker environment has the - same variables and values, this is required for asynchronous tasks like - email sync.`} + {t`These are only the server values. Ensure your worker environment has the same variables and values, this is required for asynchronous tasks like email sync.`}
-
- {visibleGroups.map((group) => ( - - - {group.variables.length > 0 && ( - - )} - - ))} + {visibleGroups.map((group) => ( + + + {group.variables.length > 0 && ( + + )} + + ))} - +
+ { LeftIcon={IconHeartRateMonitor} LeftIconColor={theme.font.color.tertiary} /> - +
); diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariablesRow.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariablesRow.tsx index 1ee2d278b..a914674da 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariablesRow.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariablesRow.tsx @@ -1,3 +1,5 @@ +import { SettingsAdminEnvCopyableText } from '@/settings/admin-panel/components/SettingsAdminEnvCopyableText'; +import { SettingsAdminTableCard } from '@/settings/admin-panel/components/SettingsAdminTableCard'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { useTheme } from '@emotion/react'; @@ -19,6 +21,8 @@ type SettingsAdminEnvVariablesRowProps = { value: string; sensitive: boolean; }; + isExpanded: boolean; + onExpandToggle: (name: string) => void; }; const StyledTruncatedCell = styled(TableCell)` @@ -43,53 +47,36 @@ const StyledButton = styled(motion.button)` const MotionIconChevronDown = motion(IconChevronRight); -const StyledExpandedDetails = styled.div` - background-color: ${({ theme }) => theme.background.secondary}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - margin: ${({ theme }) => theme.spacing(2)} 0; - padding: ${({ theme }) => theme.spacing(2)}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - display: grid; - grid-template-columns: auto 1fr; - gap: ${({ theme }) => theme.spacing(1)}; - height: fit-content; - min-height: min-content; -`; - -const StyledDetailLabel = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - padding-right: ${({ theme }) => theme.spacing(4)}; -`; - const StyledEllipsisLabel = styled.div` white-space: nowrap; text-overflow: ellipsis; overflow: hidden; `; -const StyledExpandedLabel = styled.div` - word-break: break-word; - white-space: normal; - overflow: visible; -`; - const StyledValueContainer = styled.div` - display: flex; align-items: center; + display: flex; + gap: ${({ theme }) => theme.spacing(1)}; justify-content: space-between; + width: 100%; `; const StyledTableRow = styled(TableRow)<{ isExpanded: boolean }>` background-color: ${({ isExpanded, theme }) => isExpanded ? theme.background.transparent.light : 'transparent'}; - margin-bottom: ${({ theme }) => theme.spacing(0.5)}; +`; + +const StyledExpandableContainer = styled.div` + width: 100%; + padding-top: ${({ theme }) => theme.spacing(2)}; + padding-bottom: ${({ theme }) => theme.spacing(2)}; `; export const SettingsAdminEnvVariablesRow = ({ variable, + isExpanded, + onExpandToggle, }: SettingsAdminEnvVariablesRowProps) => { - const [isExpanded, setIsExpanded] = useState(false); const [showSensitiveValue, setShowSensitiveValue] = useState(false); const theme = useTheme(); @@ -105,10 +92,47 @@ export const SettingsAdminEnvVariablesRow = ({ setShowSensitiveValue(!showSensitiveValue); }; + const environmentVariablesDetails = [ + { + label: 'Name', + value: , + }, + { + label: 'Description', + value: ( + + ), + }, + { + label: 'Value', + value: ( + + + {variable.sensitive && variable.value !== '' && ( + + )} + + ), + }, + ]; + return ( <> setIsExpanded(!isExpanded)} + onClick={() => onExpandToggle(variable.name)} gridAutoColumns="5fr 4fr 3fr 1fr" isExpanded={isExpanded} > @@ -122,7 +146,12 @@ export const SettingsAdminEnvVariablesRow = ({ {displayValue} - setIsExpanded(!isExpanded)}> + { + e.stopPropagation(); + onExpandToggle(variable.name); + }} + > - - Name - {variable.name} - Description - {variable.description} - Value - - - {displayValue} - {variable.sensitive && variable.value !== '' && ( - - )} - - - + + + ); diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariablesTable.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariablesTable.tsx index b4ccf799c..70aa04415 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariablesTable.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminEnvVariablesTable.tsx @@ -1,11 +1,13 @@ import { SettingsAdminEnvVariablesRow } from '@/settings/admin-panel/components/SettingsAdminEnvVariablesRow'; import { Table } from '@/ui/layout/table/components/Table'; +import { TableBody } from '@/ui/layout/table/components/TableBody'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import styled from '@emotion/styled'; +import { useState } from 'react'; -const StyledTable = styled(Table)` - margin-top: ${({ theme }) => theme.spacing(3)}; +const StyledTableBody = styled(TableBody)` + border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; `; type SettingsAdminEnvVariablesTableProps = { @@ -19,16 +21,31 @@ type SettingsAdminEnvVariablesTableProps = { export const SettingsAdminEnvVariablesTable = ({ variables, -}: SettingsAdminEnvVariablesTableProps) => ( - - - Name - Description - Value - - - {variables.map((variable) => ( - - ))} - -); +}: SettingsAdminEnvVariablesTableProps) => { + const [expandedRowName, setExpandedRowName] = useState(null); + + const handleExpandToggle = (name: string) => { + setExpandedRowName(expandedRowName === name ? null : name); + }; + + return ( + + + Name + Description + Value + + + + {variables.map((variable) => ( + + ))} + +
+ ); +}; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminGeneral.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminGeneral.tsx index f50cfaf90..3b6f98ef9 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminGeneral.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminGeneral.tsx @@ -16,16 +16,18 @@ import { useRecoilState, useRecoilValue } from 'recoil'; import { getImageAbsoluteURI, isDefined } from 'twenty-shared'; import { Button, - H1Title, - H1TitleFontColor, H2Title, + IconId, + IconMail, IconSearch, + IconUser, Section, } from 'twenty-ui'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { useUserLookupAdminPanelMutation } from '~/generated/graphql'; import { currentUserState } from '@/auth/states/currentUserState'; +import { SettingsAdminTableCard } from '@/settings/admin-panel/components/SettingsAdminTableCard'; import { SettingsAdminVersionContainer } from '@/settings/admin-panel/components/SettingsAdminVersionContainer'; const StyledContainer = styled.div` @@ -35,10 +37,6 @@ const StyledContainer = styled.div` gap: ${({ theme }) => theme.spacing(2)}; `; -const StyledUserInfo = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(5)}; -`; - const StyledTabListContainer = styled.div` align-items: center; border-bottom: ${({ theme }) => `1px solid ${theme.border.color.light}`}; @@ -47,12 +45,6 @@ const StyledTabListContainer = styled.div` gap: ${({ theme }) => theme.spacing(2)}; `; -const StyledContentContainer = styled.div` - flex: 1; - width: 100%; - padding: ${({ theme }) => theme.spacing(4)} 0; -`; - export const SettingsAdminGeneral = () => { const [userIdentifier, setUserIdentifier] = useState(''); const { enqueueSnackBar } = useSnackBar(); @@ -124,6 +116,24 @@ export const SettingsAdminGeneral = () => { userLookupResult?.user.lastName || '' }`.trim(); + const userInfoItems = [ + { + Icon: IconUser, + label: t`Name`, + value: userFullName, + }, + { + Icon: IconMail, + label: t`Email`, + value: userLookupResult?.user.email, + }, + { + Icon: IconId, + label: t`ID`, + value: userLookupResult?.user.id, + }, + ]; + return ( <> {canAccessFullAdminPanel && ( @@ -173,36 +183,31 @@ export const SettingsAdminGeneral = () => { )} {isDefined(userLookupResult) && ( -
- - +
+ + - +
+
- - + + + - - - - - - - -
+
+ )} ); diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx new file mode 100644 index 000000000..f7614641b --- /dev/null +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx @@ -0,0 +1,93 @@ +import { Table } from '@/ui/layout/table/components/Table'; +import { TableBody } from '@/ui/layout/table/components/TableBody'; +import { TableCell } from '@/ui/layout/table/components/TableCell'; +import { TableRow } from '@/ui/layout/table/components/TableRow'; +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { Card, IconComponent } from 'twenty-ui'; + +const StyledCard = styled(Card)` + background-color: ${({ theme }) => theme.background.secondary}; + border: 1px solid ${({ theme }) => theme.border.color.medium}; +`; + +const StyledTableRow = styled(TableRow)` + height: ${({ theme }) => theme.spacing(6)}; +`; + +const StyledTableCellLabel = styled(TableCell)<{ + align?: 'left' | 'center' | 'right'; +}>` + color: ${({ theme }) => theme.font.color.tertiary}; + height: ${({ theme }) => theme.spacing(6)}; + display: flex; + gap: ${({ theme }) => theme.spacing(2)}; + justify-content: ${({ align }) => + align === 'right' + ? 'flex-end' + : align === 'center' + ? 'center' + : 'flex-start'}; +`; + +const StyledTableCellValue = styled(TableCell)<{ + align?: 'left' | 'center' | 'right'; +}>` + color: ${({ theme }) => theme.font.color.primary}; + height: ${({ theme }) => theme.spacing(6)}; + justify-content: ${({ align }) => + align === 'left' + ? 'flex-start' + : align === 'center' + ? 'center' + : 'flex-end'}; +`; + +type TableItem = { + Icon?: IconComponent; + label: string; + value: string | number | React.ReactNode; +}; + +type SettingsAdminTableCardProps = { + items: TableItem[]; + rounded?: boolean; + gridAutoColumns?: string; + labelAlign?: 'left' | 'center' | 'right'; + valueAlign?: 'left' | 'center' | 'right'; + className?: string; +}; + +export const SettingsAdminTableCard = ({ + items, + rounded = false, + gridAutoColumns, + labelAlign = 'left', + valueAlign = 'left', + className, +}: SettingsAdminTableCardProps) => { + const theme = useTheme(); + + return ( + + + + {items.map((item, index) => ( + + + {item.Icon && } + {item.label} + + + {item.value} + + + ))} + +
+
+ ); +}; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminVersionContainer.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminVersionContainer.tsx index ff8bf72a3..d539629b3 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminVersionContainer.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminVersionContainer.tsx @@ -1,46 +1,20 @@ -import { IconCircleDot, IconComponent, IconStatusChange } from 'twenty-ui'; - -import { GITHUB_LINK } from '@ui/navigation/link/constants/GithubLink'; - +import { SettingsAdminTableCard } from '@/settings/admin-panel/components/SettingsAdminTableCard'; import { checkTwentyVersionExists } from '@/settings/admin-panel/utils/checkTwentyVersionExists'; import { fetchLatestTwentyRelease } from '@/settings/admin-panel/utils/fetchLatestTwentyRelease'; -import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; +import { GITHUB_LINK } from '@ui/navigation/link/constants/GithubLink'; import { useEffect, useState } from 'react'; +import { IconCircleDot, IconStatusChange } from 'twenty-ui'; import packageJson from '../../../../../package.json'; -const StyledVersionContainer = styled.div` - background: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.md}; - gap: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(3)}; - display: grid; -`; - -const StyledVersionDetails = styled.div` - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - display: flex; - flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; -`; - -const StyledVersionText = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.regular}; -`; - const StyledActionLink = styled.a` align-items: center; color: ${({ theme }) => theme.font.color.primary}; display: flex; font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-weight: ${({ theme }) => theme.font.weight.regular}; gap: ${({ theme }) => theme.spacing(1)}; - padding: 0 ${({ theme }) => theme.spacing(1)}; text-decoration: none; :hover { @@ -52,19 +26,10 @@ const StyledActionLink = styled.a` const StyledSpan = styled.span` color: ${({ theme }) => theme.font.color.primary}; font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; + font-weight: ${({ theme }) => theme.font.weight.regular}; `; -type VersionDetail = { - Icon: IconComponent; - text: string; - version: string | null; - link: string; - type: 'current' | 'latest'; -}; - export const SettingsAdminVersionContainer = () => { - const theme = useTheme(); const [latestVersion, setLatestVersion] = useState(null); const [currentVersionExists, setCurrentVersionExists] = useState(false); @@ -73,46 +38,44 @@ export const SettingsAdminVersionContainer = () => { checkTwentyVersionExists(packageJson.version).then(setCurrentVersionExists); }, []); - const VERSION_DETAILS: VersionDetail[] = [ + const versionItems = [ { Icon: IconCircleDot, - text: t`Current version:`, - version: packageJson.version, - link: `${GITHUB_LINK}/releases/tag/v${packageJson.version}`, - type: 'current', + label: t`Current version`, + value: currentVersionExists ? ( + + {packageJson.version} + + ) : ( + {packageJson.version} + ), }, { Icon: IconStatusChange, - text: t`Latest version:`, - version: latestVersion, - link: `${GITHUB_LINK}/releases/tag/v${latestVersion}`, - type: 'latest', + label: t`Latest version`, + value: latestVersion ? ( + + {latestVersion} + + ) : ( + {latestVersion ?? 'Loading...'} + ), }, ]; return ( - - {VERSION_DETAILS.map((versionDetail, index) => ( - - - {versionDetail.text} - {versionDetail.version && - (versionDetail.type === 'current' ? currentVersionExists : true) ? ( - - {versionDetail.version} - - ) : ( - {versionDetail.version} - )} - - ))} - + ); }; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminWorkspaceContent.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminWorkspaceContent.tsx index 501f05085..ad97886ef 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminWorkspaceContent.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminWorkspaceContent.tsx @@ -1,8 +1,19 @@ -import { Button, H2Title, IconUser, Toggle } from 'twenty-ui'; +import { + AvatarChip, + Button, + H2Title, + IconEyeShare, + IconHome, + IconId, + IconUser, + Section, + Toggle, +} from 'twenty-ui'; import { currentUserState } from '@/auth/states/currentUserState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { canManageFeatureFlagsState } from '@/client-config/states/canManageFeatureFlagsState'; +import { SettingsAdminTableCard } from '@/settings/admin-panel/components/SettingsAdminTableCard'; import { useFeatureFlagState } from '@/settings/admin-panel/hooks/useFeatureFlagState'; import { useImpersonationAuth } from '@/settings/admin-panel/hooks/useImpersonationAuth'; import { useImpersonationRedirect } from '@/settings/admin-panel/hooks/useImpersonationRedirect'; @@ -11,14 +22,18 @@ import { WorkspaceInfo } from '@/settings/admin-panel/types/WorkspaceInfo'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { Table } from '@/ui/layout/table/components/Table'; +import { TableBody } from '@/ui/layout/table/components/TableBody'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableRow } from '@/ui/layout/table/components/TableRow'; +import { DEFAULT_WORKSPACE_LOGO } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceLogo'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; +import { isNonEmptyString } from '@sniptt/guards'; import { useState } from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; -import { isDefined } from 'twenty-shared'; +import { getImageAbsoluteURI, isDefined } from 'twenty-shared'; +import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { FeatureFlagKey, useImpersonateMutation, @@ -29,7 +44,14 @@ type SettingsAdminWorkspaceContentProps = { activeWorkspace: WorkspaceInfo | undefined; }; -const StyledTable = styled(Table)` +const StyledContainer = styled.div` + display: flex; + flex-direction: column; + gap: ${({ theme }) => theme.spacing(3)}; + margin-top: ${({ theme }) => theme.spacing(6)}; +`; + +const StyledButtonContainer = styled.div` margin-top: ${({ theme }) => theme.spacing(3)}; `; @@ -115,64 +137,101 @@ export const SettingsAdminWorkspaceContent = ({ }); }; + const workspaceInfoItems = [ + { + Icon: IconHome, + label: t`Name`, + value: ( + + ), + }, + { + Icon: IconId, + label: t`ID`, + value: activeWorkspace?.id, + }, + { + Icon: IconUser, + label: t`Members`, + value: activeWorkspace?.totalUsers, + }, + ]; + if (!activeWorkspace) return null; return ( - <> - - 1 ? t`Users` : t`User` - }`} - description={t`Total Users`} - /> - {currentUser?.canImpersonate && ( -
{canManageFeatureFlags && ( - - - {t`Feature Flag`} - {t`Status`} - - - {activeWorkspace.featureFlags.map((flag) => ( + + - {flag.key} - - - handleFeatureFlagUpdate( - activeWorkspace.id, - flag.key, - newValue, - ) - } - /> - + {t`Feature Flag`} + {t`Status`} - ))} - + + {activeWorkspace.featureFlags.map((flag) => ( + + {flag.key} + + + handleFeatureFlagUpdate( + activeWorkspace.id, + flag.key, + newValue, + ) + } + /> + + + ))} + +
)} - + ); }; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/ConnectedAccountHealthStatus.tsx b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/ConnectedAccountHealthStatus.tsx index ad8907a70..0aeacf957 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/ConnectedAccountHealthStatus.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/ConnectedAccountHealthStatus.tsx @@ -10,6 +10,12 @@ const StyledErrorMessage = styled.div` margin-top: ${({ theme }) => theme.spacing(2)}; `; +const StyledContainer = styled.div` + display: flex; + flex-direction: column; + gap: ${({ theme }) => theme.spacing(8)}; +`; + export const ConnectedAccountHealthStatus = () => { const { indicatorHealth } = useContext(SettingsAdminIndicatorHealthContext); const details = indicatorHealth.details; @@ -35,7 +41,7 @@ export const ConnectedAccountHealthStatus = () => { } return ( - <> + {errorMessages.length > 0 && ( {`${errorMessages.join(' and ')} ${errorMessages.length > 1 ? 'are' : 'is'} not available because the service is down`} @@ -55,6 +61,6 @@ export const ConnectedAccountHealthStatus = () => { title={t`Calendar Sync Status`} /> )} - + ); }; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/JsonDataIndicatorHealthStatus.tsx b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/JsonDataIndicatorHealthStatus.tsx index 83b1e270c..7d2de522d 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/JsonDataIndicatorHealthStatus.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/JsonDataIndicatorHealthStatus.tsx @@ -10,8 +10,8 @@ const StyledDetailsContainer = styled.div` padding: ${({ theme }) => theme.spacing(4)}; border-radius: ${({ theme }) => theme.border.radius.md}; border: 1px solid ${({ theme }) => theme.border.color.medium}; - white-space: pre-wrap; font-size: ${({ theme }) => theme.font.size.sm}; + overflow-x: auto; `; const StyledErrorMessage = styled.div` diff --git a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/WorkerMetricsGraph.tsx b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/WorkerMetricsGraph.tsx index 3a229f7a0..223c56d6d 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/WorkerMetricsGraph.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/WorkerMetricsGraph.tsx @@ -1,55 +1,25 @@ +import { SettingsAdminTableCard } from '@/settings/admin-panel/components/SettingsAdminTableCard'; +import { WorkerMetricsTooltip } from '@/settings/admin-panel/health-status/components/WorkerMetricsTooltip'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { Select } from '@/ui/input/components/Select'; -import { Table } from '@/ui/layout/table/components/Table'; -import { TableCell } from '@/ui/layout/table/components/TableCell'; -import { TableRow } from '@/ui/layout/table/components/TableRow'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { ResponsiveLine } from '@nivo/line'; +import { isNumber } from '@tiptap/core'; import { QueueMetricsTimeRange, useGetQueueMetricsQuery, } from '~/generated/graphql'; -const StyledTableRow = styled(TableRow)` - height: ${({ theme }) => theme.spacing(6)}; -`; - -const StyledQueueMetricsTitle = styled.div` - color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.medium}; - margin-bottom: ${({ theme }) => theme.spacing(3)}; - padding-left: ${({ theme }) => theme.spacing(3)}; -`; - const StyledGraphContainer = styled.div` - background-color: ${({ theme }) => theme.background.tertiary}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - height: 230px; - margin-bottom: ${({ theme }) => theme.spacing(4)}; - padding-top: ${({ theme }) => theme.spacing(4)}; - padding-bottom: ${({ theme }) => theme.spacing(2)}; - width: 100%; -`; - -const StyledQueueMetricsContainer = styled.div` + background-color: ${({ theme }) => theme.background.secondary}; + border-radius: ${({ theme }) => theme.border.radius.md}; + height: 240px; border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - padding-top: ${({ theme }) => theme.spacing(1)}; - padding-bottom: ${({ theme }) => theme.spacing(3)}; - padding-left: ${({ theme }) => theme.spacing(3)}; - padding-right: ${({ theme }) => theme.spacing(3)}; -`; - -const StyledGraphControls = styled.div` - display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - justify-content: flex-end; - margin-bottom: ${({ theme }) => theme.spacing(2)}; - margin-top: ${({ theme }) => theme.spacing(1)}; + margin-bottom: ${({ theme }) => theme.spacing(4)}; + padding-top: ${({ theme }) => theme.spacing(2.5)}; + width: 100%; `; const StyledNoDataMessage = styled.div` @@ -60,31 +30,9 @@ const StyledNoDataMessage = styled.div` justify-content: center; `; -const StyledTooltipContainer = styled.div` - background-color: ${({ theme }) => theme.background.secondary}; - border: 1px solid ${({ theme }) => theme.border.color.medium}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - padding: ${({ theme }) => theme.spacing(2)}; - font-size: ${({ theme }) => theme.font.size.sm}; -`; - -const StyledTooltipItem = styled.div<{ color: string }>` - align-items: center; - color: ${({ theme }) => theme.font.color.primary}; - display: flex; - padding: ${({ theme }) => theme.spacing(0.5)} 0; -`; - -const StyledTooltipColorSquare = styled.div<{ color: string }>` - width: 12px; - height: 12px; - background-color: ${({ color }) => color}; - margin-right: ${({ theme }) => theme.spacing(1)}; -`; - -const StyledTooltipValue = styled.span` - font-weight: ${({ theme }) => theme.font.weight.medium}; +const StyledSettingsAdminTableCard = styled(SettingsAdminTableCard)` + padding-left: ${({ theme }) => theme.spacing(2)}; + padding-right: ${({ theme }) => theme.spacing(2)}; `; type WorkerMetricsGraphProps = { @@ -96,7 +44,6 @@ type WorkerMetricsGraphProps = { export const WorkerMetricsGraph = ({ queueName, timeRange, - onTimeRangeChange, }: WorkerMetricsGraphProps) => { const theme = useTheme(); const { enqueueSnackBar } = useSnackBar(); @@ -158,25 +105,6 @@ export const WorkerMetricsGraph = ({ return ( <> - - + + - + ); }; diff --git a/packages/twenty-front/src/modules/settings/components/SettingsListItemCardContent.tsx b/packages/twenty-front/src/modules/settings/components/SettingsListItemCardContent.tsx index 2aaa8b2f4..000e11522 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsListItemCardContent.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsListItemCardContent.tsx @@ -5,9 +5,9 @@ import { Link } from 'react-router-dom'; import { isDefined } from 'twenty-shared'; import { CardContent, IconChevronRight, IconComponent } from 'twenty-ui'; -const StyledRow = styled(CardContent)` +const StyledRow = styled(CardContent)<{ to?: boolean }>` align-items: center; - cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')}; + cursor: ${({ onClick, to }) => (onClick || to ? 'pointer' : 'default')}; display: flex; font-size: ${({ theme }) => theme.font.size.sm}; font-weight: ${({ theme }) => theme.font.weight.medium}; @@ -15,6 +15,11 @@ const StyledRow = styled(CardContent)` padding: ${({ theme }) => theme.spacing(2)}; padding-left: ${({ theme }) => theme.spacing(3)}; min-height: ${({ theme }) => theme.spacing(6)}; + + &:hover { + ${({ to, theme }) => + to && `background: ${theme.background.transparent.light};`} + } `; const StyledRightContainer = styled.div` @@ -36,12 +41,8 @@ const StyledDescription = styled.span` `; const StyledLink = styled(Link)` - text-decoration: none; color: ${({ theme }) => theme.font.color.secondary}; - - &:hover { - color: ${({ theme }) => theme.font.color.secondary}; - } + text-decoration: none; `; type SettingsListItemCardContentProps = { @@ -68,7 +69,7 @@ export const SettingsListItemCardContent = ({ const theme = useTheme(); const content = ( - + {!!LeftIcon && ( theme.spacing(2)}; -`; - -const StyledDescription = styled.div` - color: ${({ theme }) => theme.font.color.tertiary}; - font-size: ${({ theme }) => theme.font.size.sm}; - font-weight: ${({ theme }) => theme.font.weight.regular}; - margin-top: ${({ theme }) => theme.spacing(2)}; -`; - const StyledTitleContainer = styled.div` + align-items: center; display: flex; gap: ${({ theme }) => theme.spacing(4)}; -`; - -const StyledHealthStatusContainer = styled.div` margin-top: ${({ theme }) => theme.spacing(2)}; `; @@ -87,23 +74,25 @@ export const SettingsAdminIndicatorHealthStatus = () => { >
- + {data?.getIndicatorHealthStatus?.status && ( - - - + )} - - {data?.getIndicatorHealthStatus?.description} -
- - +
+ {data?.getIndicatorHealthStatus?.id !== HealthIndicatorId.worker && + data?.getIndicatorHealthStatus?.id !== + HealthIndicatorId.connectedAccount && ( + + )} + +
diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminSecondaryEnvVariables.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminSecondaryEnvVariables.tsx index 217c9ef60..01d9824cb 100644 --- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminSecondaryEnvVariables.tsx +++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminSecondaryEnvVariables.tsx @@ -5,13 +5,11 @@ import { SettingsPath } from '@/types/SettingsPath'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; -import { H2Title, Section } from 'twenty-ui'; +import { H2Title } from 'twenty-ui'; import { useGetEnvironmentVariablesGroupedQuery } from '~/generated/graphql'; import { getSettingsPath } from '~/utils/navigation/getSettingsPath'; -const StyledGroupContainer = styled.div` - margin-bottom: ${({ theme }) => theme.spacing(6)}; -`; +const StyledGroupContainer = styled.div``; export const SettingsAdminSecondaryEnvVariables = () => { const { data: environmentVariables, loading: environmentVariablesLoading } = @@ -30,6 +28,7 @@ export const SettingsAdminSecondaryEnvVariables = () => { return ( { ]} > -
- {hiddenGroups.map((group) => ( - - - {group.variables.length > 0 && ( - - )} - - ))} -
+ {hiddenGroups.map((group) => ( + + + {group.variables.length > 0 && ( + + )} + + ))}
); diff --git a/packages/twenty-server/src/engine/core-modules/admin-panel/constants/health-indicators.constants.ts b/packages/twenty-server/src/engine/core-modules/admin-panel/constants/health-indicators.constants.ts index d3df3051c..e3985258c 100644 --- a/packages/twenty-server/src/engine/core-modules/admin-panel/constants/health-indicators.constants.ts +++ b/packages/twenty-server/src/engine/core-modules/admin-panel/constants/health-indicators.constants.ts @@ -10,27 +10,27 @@ export const HEALTH_INDICATORS: Record = { [HealthIndicatorId.database]: { id: HealthIndicatorId.database, - label: 'Database Status', + label: 'Database', description: 'PostgreSQL database connection status', }, [HealthIndicatorId.redis]: { id: HealthIndicatorId.redis, - label: 'Redis Status', + label: 'Redis', description: 'Redis connection status', }, [HealthIndicatorId.worker]: { id: HealthIndicatorId.worker, - label: 'Worker Status', - description: 'Background job worker status', + label: 'Worker', + description: 'Background job worker health status', }, [HealthIndicatorId.connectedAccount]: { id: HealthIndicatorId.connectedAccount, - label: 'Connected Account Status', - description: 'Connected accounts status', + label: 'Connected Accounts', + description: 'Connected accounts health status', }, [HealthIndicatorId.app]: { id: HealthIndicatorId.app, - label: 'App Status', + label: 'App', description: 'Workspace metadata migration status check', }, }; diff --git a/packages/twenty-server/src/engine/guards/__tests__/impersonate-guard.spec.ts b/packages/twenty-server/src/engine/guards/impersonate-guard.spec.ts similarity index 100% rename from packages/twenty-server/src/engine/guards/__tests__/impersonate-guard.spec.ts rename to packages/twenty-server/src/engine/guards/impersonate-guard.spec.ts diff --git a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts index 5f136bbe7..5e6f95bf6 100644 --- a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts +++ b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts @@ -4,18 +4,18 @@ export { IconAlertCircle, IconAlertTriangle, IconApi, - IconAppWindow, IconApps, + IconAppWindow, IconArchive, IconArchiveOff, IconArrowBackUp, IconArrowDown, IconArrowLeft, IconArrowRight, - IconArrowUp, - IconArrowUpRight, IconArrowsDiagonal, IconArrowsVertical, + IconArrowUp, + IconArrowUpRight, IconAt, IconBaselineDensitySmall, IconBell, @@ -47,8 +47,8 @@ export { IconChevronDown, IconChevronLeft, IconChevronRight, - IconChevronUp, IconChevronsRight, + IconChevronUp, IconCircleDot, IconCircleOff, IconCirclePlus, @@ -128,6 +128,7 @@ export { IconExternalLink, IconEye, IconEyeOff, + IconEyeShare, IconFile, IconFileCheck, IconFileExport, @@ -167,6 +168,7 @@ export { IconHistoryToggle, IconHome, IconHours24, + IconId, IconInbox, IconInfoCircle, IconJson, diff --git a/packages/twenty-ui/src/display/typography/components/H2Title.tsx b/packages/twenty-ui/src/display/typography/components/H2Title.tsx index 4d2703c33..f02053f4f 100644 --- a/packages/twenty-ui/src/display/typography/components/H2Title.tsx +++ b/packages/twenty-ui/src/display/typography/components/H2Title.tsx @@ -1,4 +1,5 @@ import styled from '@emotion/styled'; +import { OverflowingTextWithTooltip } from '@ui/display/tooltip/OverflowingTextWithTooltip'; type H2TitleProps = { title: string; @@ -45,6 +46,14 @@ export const H2Title = ({ {title} {adornment} - {description && {description}} + {description && ( + + + + )} );