feat: enhance team account creation with policy checks and UI updates (#436)
* feat: enhance team account creation with policy checks and UI updates
This commit is contained in:
committed by
GitHub
parent
ab57b24518
commit
5237d34e6f
@@ -19,10 +19,12 @@ import { loadUserWorkspace } from '../_lib/server/load-user-workspace';
|
||||
import { HomeAddAccountButton } from './home-add-account-button';
|
||||
|
||||
export function HomeAccountsList() {
|
||||
const { accounts } = use(loadUserWorkspace());
|
||||
const { accounts, canCreateTeamAccount } = use(loadUserWorkspace());
|
||||
|
||||
if (!accounts.length) {
|
||||
return <HomeAccountsListEmptyState />;
|
||||
return (
|
||||
<HomeAccountsListEmptyState canCreateTeamAccount={canCreateTeamAccount} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -42,12 +44,17 @@ export function HomeAccountsList() {
|
||||
);
|
||||
}
|
||||
|
||||
function HomeAccountsListEmptyState() {
|
||||
function HomeAccountsListEmptyState(props: {
|
||||
canCreateTeamAccount: { allowed: boolean; reason?: string };
|
||||
}) {
|
||||
return (
|
||||
<div className={'flex flex-1'}>
|
||||
<EmptyState>
|
||||
<EmptyStateButton asChild>
|
||||
<HomeAddAccountButton className={'mt-4'} />
|
||||
<HomeAddAccountButton
|
||||
className={'mt-4'}
|
||||
canCreateTeamAccount={props.canCreateTeamAccount}
|
||||
/>
|
||||
</EmptyStateButton>
|
||||
<EmptyStateHeading>
|
||||
<Trans i18nKey={'account:noTeamsYet'} />
|
||||
|
||||
@@ -4,19 +4,54 @@ import { useState } from 'react';
|
||||
|
||||
import { CreateTeamAccountDialog } from '@kit/team-accounts/components';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '@kit/ui/tooltip';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
export function HomeAddAccountButton(props: { className?: string }) {
|
||||
interface HomeAddAccountButtonProps {
|
||||
className?: string;
|
||||
canCreateTeamAccount?: {
|
||||
allowed: boolean;
|
||||
reason?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function HomeAddAccountButton(props: HomeAddAccountButtonProps) {
|
||||
const [isAddingAccount, setIsAddingAccount] = useState(false);
|
||||
|
||||
const canCreate = props.canCreateTeamAccount?.allowed ?? true;
|
||||
const reason = props.canCreateTeamAccount?.reason;
|
||||
|
||||
const button = (
|
||||
<Button
|
||||
className={props.className}
|
||||
onClick={() => setIsAddingAccount(true)}
|
||||
disabled={!canCreate}
|
||||
>
|
||||
<Trans i18nKey={'account:createTeamButtonLabel'} />
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
className={props.className}
|
||||
onClick={() => setIsAddingAccount(true)}
|
||||
>
|
||||
<Trans i18nKey={'account:createTeamButtonLabel'} />
|
||||
</Button>
|
||||
{!canCreate && reason ? (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="cursor-not-allowed">{button}</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<Trans i18nKey={reason} defaults={reason} />
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
) : (
|
||||
button
|
||||
)}
|
||||
|
||||
<CreateTeamAccountDialog
|
||||
isOpen={isAddingAccount}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { cache } from 'react';
|
||||
|
||||
import { createAccountsApi } from '@kit/accounts/api';
|
||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||
import { createAccountCreationPolicyEvaluator } from '@kit/team-accounts/policies';
|
||||
|
||||
import featureFlagsConfig from '~/config/feature-flags.config';
|
||||
import { requireUserInServerComponent } from '~/lib/server/require-user-in-server-component';
|
||||
@@ -34,9 +35,41 @@ async function workspaceLoader() {
|
||||
requireUserInServerComponent(),
|
||||
]);
|
||||
|
||||
// Check if user can create team accounts (policy check)
|
||||
const canCreateTeamAccount = shouldLoadAccounts
|
||||
? await checkCanCreateTeamAccount(user.id)
|
||||
: { allowed: false, reason: undefined };
|
||||
|
||||
return {
|
||||
accounts,
|
||||
workspace,
|
||||
user,
|
||||
canCreateTeamAccount,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user can create a team account based on policies.
|
||||
* Preliminary checks run without account name - name validation happens during submission.
|
||||
*/
|
||||
async function checkCanCreateTeamAccount(userId: string) {
|
||||
const evaluator = createAccountCreationPolicyEvaluator();
|
||||
const hasPolicies = await evaluator.hasPoliciesForStage('preliminary');
|
||||
|
||||
if (!hasPolicies) {
|
||||
return { allowed: true, reason: undefined };
|
||||
}
|
||||
|
||||
const context = {
|
||||
timestamp: new Date().toISOString(),
|
||||
userId,
|
||||
accountName: '',
|
||||
};
|
||||
|
||||
const result = await evaluator.canCreateAccount(context, 'preliminary');
|
||||
|
||||
return {
|
||||
allowed: result.allowed,
|
||||
reason: result.reasons[0],
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user