Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore: add managed ai usage consumption to license view#18934

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
ibetitsmike wants to merge4 commits intomain
base:main
Choose a base branch
Loading
frommike/add-managed-ai-usage-to-license-view
Open
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletionsite/package.json
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -191,7 +191,11 @@
"vite-plugin-checker":"0.9.3",
"vite-plugin-turbosnap":"1.0.3"
},
"browserslist": ["chrome 110","firefox 111","safari 16.0"],
"browserslist": [
"chrome 110",
"firefox 111",
"safari 16.0"
],
"resolutions": {
"optionator":"0.9.3",
"semver":"7.6.2"
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -85,6 +85,9 @@ const LicensesSettingsPage: FC = () => {
isRemovingLicense={isRemovingLicense}
removeLicense={(licenseId:number)=>removeLicenseApi(licenseId)}
activeUsers={userStatusCount?.active}
managedAgentFeature={
entitlementsQuery.data?.features.managed_agent_limit
}
refreshEntitlements={async()=>{
try{
awaitrefreshEntitlementsMutation.mutateAsync();
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,7 +4,7 @@ import MuiLink from "@mui/material/Link";
import Skeleton from "@mui/material/Skeleton";
import Tooltip from "@mui/material/Tooltip";
import type { GetLicensesResponse } from "api/api";
import type { UserStatusChangeCount } from "api/typesGenerated";
import type {Feature,UserStatusChangeCount } from "api/typesGenerated";
import { Button } from "components/Button/Button";
import {
SettingsHeader,
Expand All@@ -20,6 +20,7 @@ import Confetti from "react-confetti";
import { Link } from "react-router-dom";
import { LicenseCard } from "./LicenseCard";
import { LicenseSeatConsumptionChart } from "./LicenseSeatConsumptionChart";
import { ManagedAgentsConsumption } from "./ManagedAgentsConsumption";

type Props = {
showConfetti: boolean;
Expand All@@ -32,6 +33,7 @@ type Props = {
removeLicense: (licenseId: number) => void;
refreshEntitlements: () => void;
activeUsers: UserStatusChangeCount[] | undefined;
managedAgentFeature?: Feature;
};

const LicensesSettingsPageView: FC<Props> = ({
Expand All@@ -45,9 +47,13 @@ const LicensesSettingsPageView: FC<Props> = ({
removeLicense,
refreshEntitlements,
activeUsers,
managedAgentFeature,
}) => {
const theme = useTheme();
const { width, height } = useWindowSize();
const managedAgentLimitStarts = managedAgentFeature?.usage_period?.start;
const managedAgentLimitExpires = managedAgentFeature?.usage_period?.end;
const managedAgentFeatureEnabled = managedAgentFeature?.enabled;

return (
<>
Expand DownExpand Up@@ -151,6 +157,17 @@ const LicensesSettingsPageView: FC<Props> = ({
}))}
/>
)}

{licenses && licenses.length > 0 && managedAgentFeature && (
<ManagedAgentsConsumption
usage={managedAgentFeature.actual || 0}
included={managedAgentFeature.soft_limit || 0}
limit={managedAgentFeature.limit || 0}
startDate={managedAgentLimitStarts || ""}
endDate={managedAgentLimitExpires || ""}
enabled={managedAgentFeatureEnabled}
/>
)}
</div>
</>
);
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
import type { Meta, StoryObj } from "@storybook/react";
import { ManagedAgentsConsumption } from "./ManagedAgentsConsumption";

const meta: Meta<typeof ManagedAgentsConsumption> = {
title:
"pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption",
Comment on lines +5 to +6
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I love how the formatter decided to put this on it's own line to wrap it even though it would take more space 🙄

component: ManagedAgentsConsumption,
args: {
usage: 50000,
included: 60000,
limit: 120000,
startDate: "February 27, 2025",
endDate: "February 27, 2026",
},
};

export default meta;
type Story = StoryObj<typeof ManagedAgentsConsumption>;

export const Default: Story = {};

export const NearLimit: Story = {
args: {
usage: 115000,
included: 60000,
limit: 120000,
},
};

export const OverIncluded: Story = {
args: {
usage: 80000,
included: 60000,
limit: 120000,
},
};

export const LowUsage: Story = {
args: {
usage: 25000,
included: 60000,
limit: 120000,
},
};

export const Disabled: Story = {
args: {
usage: Number.NaN,
included: Number.NaN,
limit: Number.NaN,
},
};
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
import type { Interpolation, Theme } from "@emotion/react";
import MuiLink from "@mui/material/Link";
import { Button } from "components/Button/Button";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "components/Collapsible/Collapsible";
import { Stack } from "components/Stack/Stack";
import dayjs from "dayjs";
import { ChevronRightIcon } from "lucide-react";
import type { FC } from "react";

interface ManagedAgentsConsumptionProps {
usage: number;
included: number;
limit: number;
startDate: string;
endDate: string;
enabled?: boolean;
}

export const ManagedAgentsConsumption: FC<ManagedAgentsConsumptionProps> = ({
usage,
included,
limit,
startDate,
endDate,
enabled = true,
}) => {
if (!enabled) {
return (
<div css={styles.disabledRoot}>
<Stack alignItems="center" spacing={1}>
<Stack alignItems="center" spacing={0.5}>
<span css={styles.disabledTitle}>
Managed AI Agent Feature Disabled
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
ManagedAIAgentFeatureDisabled
ManagedAIAgentsDisabled

</span>
<span css={styles.disabledDescription}>
The managed AI agent feature is not included in your current
license. Contact{" "}
Comment on lines +40 to +41
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
ThemanagedAIagentfeatureisnotincludedinyourcurrent
license.Contact{" "}
ManagedAIagentsarenotincludedinyourcurrentlicense.
Contact{" "}

<MuiLink href="mailto:sales@coder.com">sales</MuiLink> to upgrade
your license and unlock this feature.
</span>
</Stack>
</Stack>
</div>
);
}

const usagePercentage = Math.min((usage / limit) * 100, 100);
const includedPercentage = Math.min((included / limit) * 100, 100);
const remainingPercentage = Math.max(100 - includedPercentage, 0);

return (
<section className="border border-solid rounded">
<div className="p-4">
<Collapsible>
<header className="flex flex-col gap-2 items-start">
<h3 className="text-md m-0 font-medium">
Managed agents consumption
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

IDK what's better, "managed agents consumption" or "managed agent consumption" (like below). But we should probably stick to one

</h3>

<CollapsibleTrigger asChild>
<Button
className={`
h-auto p-0 border-0 bg-transparent font-medium text-content-secondary
hover:bg-transparent hover:text-content-primary
[&[data-state=open]_svg]:rotate-90
`}
>
<ChevronRightIcon />
How we calculate managed agent consumption
</Button>
</CollapsibleTrigger>
</header>

<CollapsibleContent
className={`
pt-2 pl-7 pr-5 space-y-4 font-medium max-w-[720px]
text-sm text-content-secondary
[&_p]:m-0 [&_ul]:m-0 [&_ul]:p-0 [&_ul]:list-none
`}
>
<p>
Managed agents are counted based on the amount of started
workspaces with an AI agent.
Comment on lines +86 to +87
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
Managedagentsarecountedbasedontheamountofstarted
workspaceswithanAIagent.
Managedagentsarecountedbasedontheamountofsuccessfully
startedworkspaceswithanAIagent.

</p>
<ul>
<li className="flex items-center gap-2">
<div
className="rounded-[2px] bg-highlight-green size-3 inline-block"
aria-label="Legend for current usage in the chart"
/>
Amount of started workspaces with an AI agent.
</li>
<li className="flex items-center gap-2">
<div
className="rounded-[2px] bg-content-disabled size-3 inline-block"
aria-label="Legend for included allowance in the chart"
/>
Included allowance from your current license plan.
</li>
<li className="flex items-center gap-2">
<div
className="size-3 inline-flex items-center justify-center"
aria-label="Legend for total limit in the chart"
>
<div className="w-full border-b-1 border-t-1 border-dashed border-content-disabled" />
</div>
Total limit after which the feature will be disabled.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
Totallimitafterwhichthefeaturewillbedisabled.
TotallimitafterwhichfurtherAIworkspacebuildswillbeblocked.

</li>
</ul>
</CollapsibleContent>
</Collapsible>
</div>

<div className="p-6 border-0 border-t border-solid">
<div className="flex justify-between text-sm text-content-secondary mb-4">
<span>
{startDate ? dayjs(startDate).format("MMMM D, YYYY") : ""}
</span>
<span>{endDate ? dayjs(endDate).format("MMMM D, YYYY") : ""}</span>
</div>

<div className="relative h-6 bg-surface-secondary rounded overflow-hidden">
<div
className="absolute top-0 left-0 h-full bg-highlight-green transition-all duration-300"
style={{ width: `${usagePercentage}%` }}
/>

<div
className="absolute top-0 h-full bg-content-disabled opacity-30"
style={{
left: `${includedPercentage}%`,
width: `${remainingPercentage}%`,
}}
/>
</div>

<div className="relative flex justify-between mt-4 text-sm">
<div className="flex flex-col items-start">
<span className="text-content-secondary">Actual:</span>
<span className="font-medium">{usage.toLocaleString()}</span>
</div>

<div
className="absolute flex flex-col items-center transform -translate-x-1/2"
style={{
left: `${Math.max(Math.min(includedPercentage, 90), 10)}%`,
}}
>
<span className="text-content-secondary">Included:</span>
<span className="font-medium">{included.toLocaleString()}</span>
</div>

<div className="flex flex-col items-end">
<span className="text-content-secondary">Limit:</span>
<span className="font-medium">{limit.toLocaleString()}</span>
</div>
</div>
</div>
</section>
);
};

const styles = {
disabledTitle: {
fontSize: 16,
},

disabledRoot: (theme) => ({
minHeight: 240,
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: 8,
border: `1px solid ${theme.palette.divider}`,
padding: 48,
}),

disabledDescription: (theme) => ({
color: theme.palette.text.secondary,
textAlign: "center",
maxWidth: 464,
marginTop: 8,
}),
} satisfies Record<string, Interpolation<Theme>>;
Loading

[8]ページ先頭

©2009-2025 Movatter.jp