Add npm packages app settings list (#19324)

solves
https://discord.com/channels/1130383047699738754/1488499318762635344
This commit is contained in:
martmull
2026-04-04 09:20:11 +02:00
committed by GitHub
parent 804e0539d9
commit 80c5cfc2ec
10 changed files with 196 additions and 55 deletions
@@ -1724,6 +1724,7 @@ enum FeatureFlagKey {
IS_AI_ENABLED IS_AI_ENABLED
IS_COMMAND_MENU_ITEM_ENABLED IS_COMMAND_MENU_ITEM_ENABLED
IS_MARKETPLACE_ENABLED IS_MARKETPLACE_ENABLED
IS_MARKETPLACE_SETTING_TAB_VISIBLE
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED
IS_PUBLIC_DOMAIN_ENABLED IS_PUBLIC_DOMAIN_ENABLED
IS_EMAILING_DOMAIN_ENABLED IS_EMAILING_DOMAIN_ENABLED
@@ -1424,7 +1424,7 @@ export interface PublicFeatureFlag {
__typename: 'PublicFeatureFlag' __typename: 'PublicFeatureFlag'
} }
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED' export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED'
export interface ClientConfigMaintenanceMode { export interface ClientConfigMaintenanceMode {
startAt: Scalars['DateTime'] startAt: Scalars['DateTime']
@@ -9092,6 +9092,7 @@ export const enumFeatureFlagKey = {
IS_AI_ENABLED: 'IS_AI_ENABLED' as const, IS_AI_ENABLED: 'IS_AI_ENABLED' as const,
IS_COMMAND_MENU_ITEM_ENABLED: 'IS_COMMAND_MENU_ITEM_ENABLED' as const, IS_COMMAND_MENU_ITEM_ENABLED: 'IS_COMMAND_MENU_ITEM_ENABLED' as const,
IS_MARKETPLACE_ENABLED: 'IS_MARKETPLACE_ENABLED' as const, IS_MARKETPLACE_ENABLED: 'IS_MARKETPLACE_ENABLED' as const,
IS_MARKETPLACE_SETTING_TAB_VISIBLE: 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' as const,
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' as const, IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' as const,
IS_PUBLIC_DOMAIN_ENABLED: 'IS_PUBLIC_DOMAIN_ENABLED' as const, IS_PUBLIC_DOMAIN_ENABLED: 'IS_PUBLIC_DOMAIN_ENABLED' as const,
IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const, IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const,
@@ -1729,6 +1729,7 @@ export enum FeatureFlagKey {
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED', IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED',
IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED', IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED',
IS_MARKETPLACE_SETTING_TAB_VISIBLE = 'IS_MARKETPLACE_SETTING_TAB_VISIBLE',
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED', IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED', IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED', IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED',
@@ -11,7 +11,7 @@ import { getSettingsPath } from 'twenty-shared/utils';
import { IconApps, IconCode, IconDownload } from 'twenty-ui/display'; import { IconApps, IconCode, IconDownload } from 'twenty-ui/display';
import { useQuery } from '@apollo/client/react'; import { useQuery } from '@apollo/client/react';
import { import {
type FeatureFlagKey, FeatureFlagKey,
PermissionFlagType, PermissionFlagType,
FindManyApplicationsDocument, FindManyApplicationsDocument,
} from '~/generated-metadata/graphql'; } from '~/generated-metadata/graphql';
@@ -33,6 +33,10 @@ export const SettingsApplications = () => {
'IS_MARKETPLACE_ENABLED' as FeatureFlagKey, 'IS_MARKETPLACE_ENABLED' as FeatureFlagKey,
); );
const isMarketplaceSettingTabVisible = useIsFeatureEnabled(
FeatureFlagKey.IS_MARKETPLACE_SETTING_TAB_VISIBLE,
);
const activeTabId = useAtomComponentStateValue( const activeTabId = useAtomComponentStateValue(
activeTabIdComponentState, activeTabIdComponentState,
APPLICATIONS_TAB_LIST_ID, APPLICATIONS_TAB_LIST_ID,
@@ -65,7 +69,9 @@ export const SettingsApplications = () => {
} }
const tabs = [ const tabs = [
{ id: 'marketplace', title: t`Marketplace`, Icon: IconDownload }, ...(isMarketplaceSettingTabVisible
? [{ id: 'marketplace', title: t`Marketplace`, Icon: IconDownload }]
: []),
{ id: 'installed', title: t`Installed`, Icon: IconApps }, { id: 'installed', title: t`Installed`, Icon: IconApps },
...(hasDeveloperAccess ...(hasDeveloperAccess
? [{ id: 'developer', title: t`Developer`, Icon: IconCode }] ? [{ id: 'developer', title: t`Developer`, Icon: IconCode }]
@@ -81,7 +87,11 @@ export const SettingsApplications = () => {
case 'developer': case 'developer':
return <SettingsApplicationsDeveloperTab />; return <SettingsApplicationsDeveloperTab />;
default: default:
return <SettingsApplicationsAvailableTab />; return isMarketplaceSettingTabVisible ? (
<SettingsApplicationsAvailableTab />
) : (
<SettingsApplicationsInstalledTab />
);
} }
}; };
@@ -97,11 +107,7 @@ export const SettingsApplications = () => {
]} ]}
> >
<SettingsPageContainer> <SettingsPageContainer>
<TabList <TabList tabs={tabs} componentInstanceId={APPLICATIONS_TAB_LIST_ID} />
tabs={tabs}
componentInstanceId={APPLICATIONS_TAB_LIST_ID}
behaveAsLinks={false}
/>
{renderActiveTabContent()} {renderActiveTabContent()}
</SettingsPageContainer> </SettingsPageContainer>
</SubMenuTopBarContainer> </SubMenuTopBarContainer>
@@ -22,8 +22,9 @@ const StyledTableContainer = styled.div`
margin-top: ${themeCssVariables.spacing[3]}; margin-top: ${themeCssVariables.spacing[3]};
`; `;
const StyledTableHeaderRowContainer = styled.div` const StyledTableRowsContainer = styled.div`
margin-bottom: ${themeCssVariables.spacing[2]}; border-bottom: 1px solid ${themeCssVariables.border.color.light};
padding: ${themeCssVariables.spacing[2]} 0;
`; `;
const StyledSearchInputContainer = styled.div` const StyledSearchInputContainer = styled.div`
@@ -64,47 +65,47 @@ export const SettingsApplicationsTable = ({
</StyledSearchInputContainer> </StyledSearchInputContainer>
<StyledTableContainer> <StyledTableContainer>
<Table> <Table>
<StyledTableHeaderRowContainer> <TableRow
<TableRow gridTemplateColumns={APPLICATION_TABLE_ROW_GRID_TEMPLATE_COLUMNS}
gridTemplateColumns={APPLICATION_TABLE_ROW_GRID_TEMPLATE_COLUMNS} >
> <TableHeader> {t`Name`}</TableHeader>
<TableHeader> {t`Name`}</TableHeader> <TableHeader> {t`Description`}</TableHeader>
<TableHeader> {t`Description`}</TableHeader> <TableHeader> {''}</TableHeader>
<TableHeader> {''}</TableHeader> <TableHeader />
<TableHeader /> </TableRow>
</TableRow> <StyledTableRowsContainer>
</StyledTableHeaderRowContainer> {filteredApplications.map((application) => {
{filteredApplications.map((application) => { const isNpmApp =
const isNpmApp = application.applicationRegistration?.sourceType ===
application.applicationRegistration?.sourceType === ApplicationRegistrationSourceType.NPM;
ApplicationRegistrationSourceType.NPM;
const latestVersion = const latestVersion =
application.applicationRegistration?.latestAvailableVersion; application.applicationRegistration?.latestAvailableVersion;
const hasUpdate = const hasUpdate =
isNpmApp && isNpmApp &&
isDefined(latestVersion) && isDefined(latestVersion) &&
isDefined(application.version) && isDefined(application.version) &&
isNewerSemver(latestVersion, application.version); isNewerSemver(latestVersion, application.version);
return ( return (
<SettingsApplicationTableRow <SettingsApplicationTableRow
key={application.id} key={application.id}
application={application} application={application}
hasUpdate={hasUpdate} hasUpdate={hasUpdate}
action={ action={
<IconChevronRight <IconChevronRight
size={theme.icon.size.md} size={theme.icon.size.md}
stroke={theme.icon.stroke.sm} stroke={theme.icon.stroke.sm}
/> />
} }
link={getSettingsPath(SettingsPath.ApplicationDetail, { link={getSettingsPath(SettingsPath.ApplicationDetail, {
applicationId: application.id, applicationId: application.id,
})} })}
/> />
); );
})} })}
</StyledTableRowsContainer>
</Table> </Table>
</StyledTableContainer> </StyledTableContainer>
</Section> </Section>
@@ -1,34 +1,68 @@
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { SettingsListCard } from '@/settings/components/SettingsListCard'; import { SettingsListCard } from '@/settings/components/SettingsListCard';
import {
StyledActionTableCell,
StyledNameTableCell,
} from '@/settings/data-model/object-details/components/SettingsObjectItemTableRowStyledComponents';
import { getDocumentationUrl } from '@/support/utils/getDocumentationUrl'; import { getDocumentationUrl } from '@/support/utils/getDocumentationUrl';
import { Table } from '@/ui/layout/table/components/Table';
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 { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useQuery } from '@apollo/client/react'; import { useQuery } from '@apollo/client/react';
import { styled } from '@linaria/react'; import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro'; import { useLingui } from '@lingui/react/macro';
import { useContext, useMemo, useState } from 'react';
import { SettingsPath } from 'twenty-shared/types'; import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils'; import { getSettingsPath } from 'twenty-shared/utils';
import { Tag } from 'twenty-ui/components'; import { Tag } from 'twenty-ui/components';
import { import {
Avatar,
CommandBlock, CommandBlock,
H2Title, H2Title,
IconApps, IconApps,
IconChevronRight,
IconCopy, IconCopy,
IconFileInfo, IconFileInfo,
OverflowingTextWithTooltip,
} from 'twenty-ui/display'; } from 'twenty-ui/display';
import { Button } from 'twenty-ui/input'; import { Button, SearchInput } from 'twenty-ui/input';
import { Section } from 'twenty-ui/layout'; import { Section } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants'; import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { import {
type ApplicationRegistrationFragmentFragment, type ApplicationRegistrationFragmentFragment,
ApplicationRegistrationSourceType, ApplicationRegistrationSourceType,
FeatureFlagKey,
FindManyApplicationRegistrationsDocument, FindManyApplicationRegistrationsDocument,
} from '~/generated-metadata/graphql'; } from '~/generated-metadata/graphql';
import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
import { useMarketplaceApps } from '~/modules/marketplace/hooks/useMarketplaceApps';
const StyledButtonContainer = styled.div` const StyledButtonContainer = styled.div`
display: flex;
justify-content: flex-end;
margin: ${themeCssVariables.spacing[2]} 0; margin: ${themeCssVariables.spacing[2]} 0;
`; `;
const StyledSearchInputContainer = styled.div`
padding-bottom: ${themeCssVariables.spacing[2]};
`;
const StyledEmptyState = styled.div`
color: ${themeCssVariables.font.color.tertiary};
padding: ${themeCssVariables.spacing[8]};
text-align: center;
`;
const StyledTableRowsContainer = styled.div`
border-bottom: 1px solid ${themeCssVariables.border.color.light};
padding: ${themeCssVariables.spacing[2]} 0;
`;
const NPM_PACKAGES_GRID_COLUMNS = '200px 1fr 36px';
const SOURCE_TYPE_BADGE_CONFIG: Record< const SOURCE_TYPE_BADGE_CONFIG: Record<
ApplicationRegistrationSourceType, ApplicationRegistrationSourceType,
{ label: string; color: 'gray' | 'blue' | 'green' } { label: string; color: 'gray' | 'blue' | 'green' }
@@ -53,12 +87,34 @@ const SOURCE_TYPE_BADGE_CONFIG: Record<
export const SettingsApplicationsDeveloperTab = () => { export const SettingsApplicationsDeveloperTab = () => {
const { t } = useLingui(); const { t } = useLingui();
const { theme } = useContext(ThemeContext);
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState); const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
const { copyToClipboard } = useCopyToClipboard(); const { copyToClipboard } = useCopyToClipboard();
const { data, loading } = useQuery(FindManyApplicationRegistrationsDocument); const { data, loading } = useQuery(FindManyApplicationRegistrationsDocument);
const isMarketplaceSettingTabVisible = useIsFeatureEnabled(
FeatureFlagKey.IS_MARKETPLACE_SETTING_TAB_VISIBLE,
);
const [npmSearchTerm, setNpmSearchTerm] = useState('');
const { data: marketplaceApps } = useMarketplaceApps();
const filteredMarketplaceApps = useMemo(() => {
if (!npmSearchTerm) {
return marketplaceApps;
}
const lowerSearch = npmSearchTerm.toLowerCase();
return marketplaceApps.filter(
(application) =>
application.name.toLowerCase().includes(lowerSearch) ||
application.description.toLowerCase().includes(lowerSearch),
);
}, [marketplaceApps, npmSearchTerm]);
const registrations: ApplicationRegistrationFragmentFragment[] = const registrations: ApplicationRegistrationFragmentFragment[] =
data?.findManyApplicationRegistrations ?? []; data?.findManyApplicationRegistrations ?? [];
@@ -123,8 +179,8 @@ export const SettingsApplicationsDeveloperTab = () => {
<> <>
<Section> <Section>
<H2Title <H2Title
title={t`Create & Develop`} title={t`Create an application`}
description={t`Scaffold a new app, then use the CLI to develop, publish, and distribute`} description={t`You can either create a private app or share it to others`}
/> />
<CommandBlock commands={createCommands} button={createCopyButton} /> <CommandBlock commands={createCommands} button={createCopyButton} />
<StyledButtonContainer> <StyledButtonContainer>
@@ -146,7 +202,7 @@ export const SettingsApplicationsDeveloperTab = () => {
<Section> <Section>
<H2Title <H2Title
title={t`Your Apps`} title={t`Your apps`}
description={t`All applications registered on this workspace`} description={t`All applications registered on this workspace`}
/> />
{registrations.length > 0 ? ( {registrations.length > 0 ? (
@@ -164,6 +220,74 @@ export const SettingsApplicationsDeveloperTab = () => {
) )
)} )}
</Section> </Section>
{!isMarketplaceSettingTabVisible && (
<Section>
<H2Title
title={t`NPM packages`}
description={t`Apps made by other developers published on npm`}
/>
<StyledSearchInputContainer>
<SearchInput
placeholder={t`Search an application`}
value={npmSearchTerm}
onChange={setNpmSearchTerm}
/>
</StyledSearchInputContainer>
{filteredMarketplaceApps.length === 0 ? (
<StyledEmptyState>{t`No application found`}</StyledEmptyState>
) : (
<Table>
<TableRow gridAutoColumns={NPM_PACKAGES_GRID_COLUMNS}>
<TableHeader>{t`Name`}</TableHeader>
<TableHeader>{t`Description`}</TableHeader>
<TableHeader />
</TableRow>
<StyledTableRowsContainer>
{filteredMarketplaceApps.map((application) => (
<TableRow
key={application.id}
gridAutoColumns={NPM_PACKAGES_GRID_COLUMNS}
to={getSettingsPath(
SettingsPath.AvailableApplicationDetail,
{
availableApplicationId: application.id,
},
)}
>
<StyledNameTableCell>
<Avatar
avatarUrl={application.logo || null}
placeholder={application.name}
placeholderColorSeed={application.name}
size="md"
type="squared"
/>
<OverflowingTextWithTooltip text={application.name} />
</StyledNameTableCell>
<TableCell
overflow="hidden"
textOverflow="ellipsis"
whiteSpace="nowrap"
>
<OverflowingTextWithTooltip
text={application.description}
/>
</TableCell>
<StyledActionTableCell>
<IconChevronRight
size={theme.icon.size.md}
stroke={theme.icon.stroke.sm}
color={theme.font.color.tertiary}
/>
</StyledActionTableCell>
</TableRow>
))}
</StyledTableRowsContainer>
</Table>
)}
</Section>
)}
</> </>
); );
}; };
@@ -234,6 +234,7 @@ describe('WorkspaceEntityManager', () => {
IS_JSON_FILTER_ENABLED: false, IS_JSON_FILTER_ENABLED: false,
IS_AI_ENABLED: false, IS_AI_ENABLED: false,
IS_MARKETPLACE_ENABLED: false, IS_MARKETPLACE_ENABLED: false,
IS_MARKETPLACE_SETTING_TAB_VISIBLE: false,
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: false, IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: false,
IS_PUBLIC_DOMAIN_ENABLED: false, IS_PUBLIC_DOMAIN_ENABLED: false,
IS_EMAILING_DOMAIN_ENABLED: false, IS_EMAILING_DOMAIN_ENABLED: false,
@@ -50,6 +50,11 @@ export const seedFeatureFlags = async ({
workspaceId: workspaceId, workspaceId: workspaceId,
value: true, value: true,
}, },
{
key: FeatureFlagKey.IS_MARKETPLACE_SETTING_TAB_VISIBLE,
workspaceId: workspaceId,
value: true,
},
{ {
key: FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED, key: FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED,
workspaceId: workspaceId, workspaceId: workspaceId,
@@ -4,6 +4,7 @@ export enum FeatureFlagKey {
IS_AI_ENABLED = 'IS_AI_ENABLED', IS_AI_ENABLED = 'IS_AI_ENABLED',
IS_COMMAND_MENU_ITEM_ENABLED = 'IS_COMMAND_MENU_ITEM_ENABLED', IS_COMMAND_MENU_ITEM_ENABLED = 'IS_COMMAND_MENU_ITEM_ENABLED',
IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED', IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED',
IS_MARKETPLACE_SETTING_TAB_VISIBLE = 'IS_MARKETPLACE_SETTING_TAB_VISIBLE',
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED', IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED', IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED', IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED',
@@ -5,7 +5,7 @@ import { themeCssVariables } from '@ui/theme-constants';
const StyledContainer = styled.div` const StyledContainer = styled.div`
border-radius: ${themeCssVariables.border.radius.sm}; border-radius: ${themeCssVariables.border.radius.sm};
border: 1px solid ${themeCssVariables.border.color.medium}; border: 1px solid ${themeCssVariables.border.color.medium};
background: ${themeCssVariables.background.transparent.secondary}; background: ${themeCssVariables.background.secondary};
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
padding: ${themeCssVariables.spacing[3]}; padding: ${themeCssVariables.spacing[3]};