Skip to content

chore: update workspaces top bar to display org name #14596

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion site/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1684,11 +1684,13 @@ class ApiMethods {
};

getWorkspaceQuota = async (
organizationName: string,
username: string,
): Promise<TypesGen.WorkspaceQuota> => {
const response = await this.axios.get(
`/api/v2/workspace-quota/${encodeURIComponent(username)}`,
`/api/v2/organizations/${encodeURIComponent(organizationName)}/members/${encodeURIComponent(username)}/workspace-quota`,
);

return response.data;
};

Expand Down
16 changes: 9 additions & 7 deletions site/src/api/queries/workspaceQuota.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { API } from "api/api";

export const getWorkspaceQuotaQueryKey = (username: string) => [
username,
"workspaceQuota",
];
export const getWorkspaceQuotaQueryKey = (
organizationName: string,
username: string,
) => {
return ["workspaceQuota", organizationName, username];
};

export const workspaceQuota = (username: string) => {
export const workspaceQuota = (organizationName: string, username: string) => {
return {
queryKey: getWorkspaceQuotaQueryKey(username),
queryFn: () => API.getWorkspaceQuota(username),
queryKey: getWorkspaceQuotaQueryKey(organizationName, username),
queryFn: () => API.getWorkspaceQuota(organizationName, username),
};
};

Expand Down
2 changes: 1 addition & 1 deletion site/src/modules/dashboard/DashboardProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface DashboardValue {
entitlements: Entitlements;
experiments: Experiments;
appearance: AppearanceConfig;
organizations: Organization[];
organizations: readonly Organization[];
showOrganizations: boolean;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,8 @@ export const GroupsPage: FC = () => {

export default GroupsPage;

export const getOrganizationNameByDefault = (organizations: Organization[]) =>
organizations.find((org) => org.is_default)?.name;
export const getOrganizationNameByDefault = (
organizations: readonly Organization[],
) => {
return organizations.find((org) => org.is_default)?.name;
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import { Outlet } from "react-router-dom";
import { DeploySettingsContext } from "../DeploySettingsPage/DeploySettingsLayout";
import { Sidebar } from "./Sidebar";

type OrganizationSettingsValue = {
organizations: Organization[];
};
type OrganizationSettingsValue = Readonly<{
organizations: readonly Organization[];
}>;

export const useOrganizationSettings = (): OrganizationSettingsValue => {
const { organizations } = useDashboard();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,9 @@ const OrganizationProvisionersPage: FC = () => {

export default OrganizationProvisionersPage;

const getOrganizationByName = (organizations: Organization[], name: string) =>
organizations.find((org) => org.name === name);
const getOrganizationByName = (
organizations: readonly Organization[],
name: string,
) => {
return organizations.find((org) => org.name === name);
};
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const OrganizationSettingsPage: FC = () => {
// Redirect /organizations => /organizations/default-org, or if they cannot edit
// the default org, then the first org they can edit, if any.
if (!organizationName) {
const editableOrg = organizations
const editableOrg = [...organizations]
.sort((a, b) => {
// Prefer default org (it may not be first).
// JavaScript will happily subtract booleans, but use numbers to keep
Expand Down Expand Up @@ -112,5 +112,9 @@ const OrganizationSettingsPage: FC = () => {

export default OrganizationSettingsPage;

const getOrganizationByName = (organizations: Organization[], name: string) =>
organizations.find((org) => org.name === name);
const getOrganizationByName = (
organizations: readonly Organization[],
name: string,
) => {
return organizations.find((org) => org.name === name);
};
7 changes: 5 additions & 2 deletions site/src/pages/TemplatePage/TemplateRedirectController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ export const TemplateRedirectController: FC = () => {
return <Outlet />;
};

const getOrganizationNameByDefault = (organizations: Organization[]) =>
organizations.find((org) => org.is_default)?.name;
const getOrganizationNameByDefault = (
organizations: readonly Organization[],
) => {
return organizations.find((org) => org.is_default)?.name;
};

// I really hate doing it this way, but React Router does not provide a better way.
const removePrefix = (self: string, prefix: string) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@ export const WorkspaceNotifications: FC<WorkspaceNotificationsProps> = ({
(n) => n.severity === "warning",
);

// We have to avoid rendering out a div at all if there is no content so
// that we don't introduce additional gaps via the parent flex container
if (infoNotifications.length === 0 && warningNotifications.length === 0) {
return null;
}

return (
<div css={styles.notificationsGroup}>
{infoNotifications.length > 0 && (
Expand Down
11 changes: 7 additions & 4 deletions site/src/pages/WorkspacePage/WorkspaceScheduleControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ import {
} from "utils/schedule";
import { isWorkspaceOn } from "utils/workspace";

export interface WorkspaceScheduleContainerProps {
interface WorkspaceScheduleContainerProps {
children?: ReactNode;
onClickIcon?: () => void;
}

export const WorkspaceScheduleContainer: FC<
WorkspaceScheduleContainerProps
> = ({ children, onClickIcon }) => {
const WorkspaceScheduleContainer: FC<WorkspaceScheduleContainerProps> = ({
children,
onClickIcon,
}) => {
const icon = (
<TopbarIcon>
<ScheduleOutlined aria-label="Schedule" />
Expand All @@ -49,6 +50,7 @@ export const WorkspaceScheduleContainer: FC<
<Tooltip title="Schedule">
{onClickIcon ? (
<button
type="button"
data-testid="schedule-icon-button"
onClick={onClickIcon}
css={styles.scheduleIconButton}
Expand Down Expand Up @@ -294,6 +296,7 @@ const styles = {
padding: 0,
fontSize: "inherit",
lineHeight: "inherit",
cursor: "pointer",
},

scheduleValue: {
Expand Down
37 changes: 32 additions & 5 deletions site/src/pages/WorkspacePage/WorkspaceTopbar.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { Meta, StoryObj } from "@storybook/react";
import { expect, screen, userEvent, waitFor, within } from "@storybook/test";
import { getWorkspaceQuotaQueryKey } from "api/queries/workspaceQuota";
import type { Workspace, WorkspaceQuota } from "api/typesGenerated";
import { addHours, addMinutes } from "date-fns";
import {
MockOrganization,
MockTemplate,
MockTemplateVersion,
MockUser,
Expand All @@ -11,9 +13,12 @@ import {
import { withDashboardProvider } from "testHelpers/storybook";
import { WorkspaceTopbar } from "./WorkspaceTopbar";

// We want a workspace without a deadline to not pollute the screenshot
const baseWorkspace = {
// We want a workspace without a deadline to not pollute the screenshot. Also
// want to make sure that the workspace is synced to our other mock values
const baseWorkspace: Workspace = {
...MockWorkspace,
organization_name: MockOrganization.name,
organization_id: MockOrganization.id,
latest_build: {
...MockWorkspace.latest_build,
deadline: undefined,
Expand Down Expand Up @@ -262,15 +267,37 @@ export const WithFarAwayDeadlineRequiredByTemplate: Story = {
},
};

export const WithQuota: Story = {
export const WithQuotaNoOrgs: Story = {
parameters: {
showOrganizations: false,
queries: [
{
key: getWorkspaceQuotaQueryKey(MockUser.username),
key: getWorkspaceQuotaQueryKey(
MockOrganization.name,
MockUser.username,
),
data: {
credits_consumed: 2,
budget: 40,
},
} satisfies WorkspaceQuota,
},
],
},
};

export const WithQuotaWithOrgs: Story = {
parameters: {
showOrganizations: true,
queries: [
{
key: getWorkspaceQuotaQueryKey(
MockOrganization.name,
MockUser.username,
),
data: {
credits_consumed: 2,
budget: 40,
} satisfies WorkspaceQuota,
},
],
},
Expand Down
Loading
Loading