mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
chore: remove global organization id state (#14135)
This commit is contained in:
committed by
GitHub
parent
f9b660e573
commit
efbd6257e4
@ -300,10 +300,20 @@ const BASE_CONTENT_TYPE_JSON = {
|
||||
"Content-Type": "application/json",
|
||||
} as const satisfies HeadersInit;
|
||||
|
||||
type TemplateOptions = Readonly<{
|
||||
export type GetTemplatesOptions = Readonly<{
|
||||
readonly deprecated?: boolean;
|
||||
}>;
|
||||
|
||||
function normalizeGetTemplatesOptions(
|
||||
options: GetTemplatesOptions = {},
|
||||
): Record<string, string> {
|
||||
const params: Record<string, string> = {};
|
||||
if (options.deprecated !== undefined) {
|
||||
params["deprecated"] = String(options.deprecated);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
type SearchParamOptions = TypesGen.Pagination & {
|
||||
q?: string;
|
||||
};
|
||||
@ -625,21 +635,26 @@ class ApiMethods {
|
||||
return response.data;
|
||||
};
|
||||
|
||||
getTemplates = async (
|
||||
options?: GetTemplatesOptions,
|
||||
): Promise<TypesGen.Template[]> => {
|
||||
const params = normalizeGetTemplatesOptions(options);
|
||||
const response = await this.axios.get<TypesGen.Template[]>(
|
||||
`/api/v2/templates`,
|
||||
{ params },
|
||||
);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param organization Can be the organization's ID or name
|
||||
*/
|
||||
getTemplates = async (
|
||||
getTemplatesByOrganization = async (
|
||||
organization: string,
|
||||
options?: TemplateOptions,
|
||||
options?: GetTemplatesOptions,
|
||||
): Promise<TypesGen.Template[]> => {
|
||||
const params: Record<string, string> = {};
|
||||
if (options?.deprecated !== undefined) {
|
||||
// Just want to check if it isn't undefined. If it has
|
||||
// a boolean value, convert it to a string and include
|
||||
// it as a param.
|
||||
params["deprecated"] = String(options.deprecated);
|
||||
}
|
||||
|
||||
const params = normalizeGetTemplatesOptions(options);
|
||||
const response = await this.axios.get<TypesGen.Template[]>(
|
||||
`/api/v2/organizations/${organization}/templates`,
|
||||
{ params },
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { MutationOptions, QueryClient, QueryOptions } from "react-query";
|
||||
import { API } from "api/api";
|
||||
import { API, type GetTemplatesOptions } from "api/api";
|
||||
import type {
|
||||
CreateTemplateRequest,
|
||||
CreateTemplateVersionRequest,
|
||||
@ -38,16 +38,30 @@ export const templateByName = (
|
||||
};
|
||||
};
|
||||
|
||||
const getTemplatesQueryKey = (organizationId: string, deprecated?: boolean) => [
|
||||
organizationId,
|
||||
const getTemplatesQueryKey = (options?: GetTemplatesOptions) => [
|
||||
"templates",
|
||||
deprecated,
|
||||
options?.deprecated,
|
||||
];
|
||||
|
||||
export const templates = (organizationId: string, deprecated?: boolean) => {
|
||||
export const templates = (options?: GetTemplatesOptions) => {
|
||||
return {
|
||||
queryKey: getTemplatesQueryKey(organizationId, deprecated),
|
||||
queryFn: () => API.getTemplates(organizationId, { deprecated }),
|
||||
queryKey: getTemplatesQueryKey(options),
|
||||
queryFn: () => API.getTemplates(options),
|
||||
};
|
||||
};
|
||||
|
||||
const getTemplatesByOrganizationQueryKey = (
|
||||
organization: string,
|
||||
options?: GetTemplatesOptions,
|
||||
) => [organization, "templates", options?.deprecated];
|
||||
|
||||
export const templatesByOrganization = (
|
||||
organization: string,
|
||||
options: GetTemplatesOptions = {},
|
||||
) => {
|
||||
return {
|
||||
queryKey: getTemplatesByOrganizationQueryKey(organization, options),
|
||||
queryFn: () => API.getTemplatesByOrganization(organization, options),
|
||||
};
|
||||
};
|
||||
|
||||
@ -100,7 +114,10 @@ export const setGroupRole = (
|
||||
|
||||
export const templateExamples = (organizationId: string) => {
|
||||
return {
|
||||
queryKey: [...getTemplatesQueryKey(organizationId), "examples"],
|
||||
queryKey: [
|
||||
...getTemplatesByOrganizationQueryKey(organizationId),
|
||||
"examples",
|
||||
],
|
||||
queryFn: () => API.getTemplateExamples(organizationId),
|
||||
};
|
||||
};
|
||||
|
@ -3,23 +3,22 @@ import { useQuery } from "react-query";
|
||||
import { appearance } from "api/queries/appearance";
|
||||
import { entitlements } from "api/queries/entitlements";
|
||||
import { experiments } from "api/queries/experiments";
|
||||
import { organizations } from "api/queries/organizations";
|
||||
import type {
|
||||
AppearanceConfig,
|
||||
Entitlements,
|
||||
Experiments,
|
||||
Organization,
|
||||
} from "api/typesGenerated";
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
|
||||
|
||||
export interface DashboardValue {
|
||||
/**
|
||||
* @deprecated Do not add new usage of this value. It is being removed as part
|
||||
* of the multi-org work.
|
||||
*/
|
||||
organizationId: string;
|
||||
entitlements: Entitlements;
|
||||
experiments: Experiments;
|
||||
appearance: AppearanceConfig;
|
||||
organizations: Organization[];
|
||||
}
|
||||
|
||||
export const DashboardContext = createContext<DashboardValue | undefined>(
|
||||
@ -31,9 +30,23 @@ export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||
const entitlementsQuery = useQuery(entitlements(metadata.entitlements));
|
||||
const experimentsQuery = useQuery(experiments(metadata.experiments));
|
||||
const appearanceQuery = useQuery(appearance(metadata.appearance));
|
||||
const organizationsQuery = useQuery(organizations());
|
||||
|
||||
const error =
|
||||
entitlementsQuery.error ||
|
||||
appearanceQuery.error ||
|
||||
experimentsQuery.error ||
|
||||
organizationsQuery.error;
|
||||
|
||||
if (error) {
|
||||
return <ErrorAlert error={error} />;
|
||||
}
|
||||
|
||||
const isLoading =
|
||||
!entitlementsQuery.data || !appearanceQuery.data || !experimentsQuery.data;
|
||||
!entitlementsQuery.data ||
|
||||
!appearanceQuery.data ||
|
||||
!experimentsQuery.data ||
|
||||
!organizationsQuery.data;
|
||||
|
||||
if (isLoading) {
|
||||
return <Loader fullscreen />;
|
||||
@ -42,10 +55,10 @@ export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||
return (
|
||||
<DashboardContext.Provider
|
||||
value={{
|
||||
organizationId: "00000000-0000-0000-0000-000000000000",
|
||||
entitlements: entitlementsQuery.data,
|
||||
experiments: experimentsQuery.data,
|
||||
appearance: appearanceQuery.data,
|
||||
organizations: organizationsQuery.data,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
@ -27,8 +27,13 @@ export const linkToUsers = withFilter("/users", "status:active");
|
||||
|
||||
export const linkToTemplate =
|
||||
(organizationName: string, templateName: string): LinkThunk =>
|
||||
(dashboard) =>
|
||||
dashboard.experiments.includes("multi-organization") &&
|
||||
selectFeatureVisibility(dashboard.entitlements).multiple_organizations
|
||||
(dashboard) => {
|
||||
const hasMultipleOrganizations = dashboard.organizations.length > 1;
|
||||
const organizationsEnabled =
|
||||
dashboard.experiments.includes("multi-organization") &&
|
||||
selectFeatureVisibility(dashboard.entitlements).multiple_organizations;
|
||||
|
||||
return hasMultipleOrganizations || organizationsEnabled
|
||||
? `/templates/${organizationName}/${templateName}`
|
||||
: `/templates/${templateName}`;
|
||||
};
|
||||
|
@ -233,13 +233,13 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = (props) => {
|
||||
|
||||
{showOrganizationPicker && (
|
||||
<OrganizationAutocomplete
|
||||
{...getFieldHelpers("organization_id")}
|
||||
{...getFieldHelpers("organization")}
|
||||
required
|
||||
label="Belongs to"
|
||||
value={selectedOrg}
|
||||
onChange={(newValue) => {
|
||||
setSelectedOrg(newValue);
|
||||
void form.setFieldValue("organization", newValue?.id || "");
|
||||
void form.setFieldValue("organization", newValue?.name || "");
|
||||
}}
|
||||
size="medium"
|
||||
/>
|
||||
|
@ -65,7 +65,6 @@ export interface CreateUserFormProps {
|
||||
onCancel: () => void;
|
||||
error?: unknown;
|
||||
isLoading: boolean;
|
||||
organizationId: string;
|
||||
authMethods?: TypesGen.AuthMethods;
|
||||
}
|
||||
|
||||
@ -86,7 +85,7 @@ const validationSchema = Yup.object({
|
||||
|
||||
export const CreateUserForm: FC<
|
||||
React.PropsWithChildren<CreateUserFormProps>
|
||||
> = ({ onSubmit, onCancel, error, isLoading, organizationId, authMethods }) => {
|
||||
> = ({ onSubmit, onCancel, error, isLoading, authMethods }) => {
|
||||
const form: FormikContextType<TypesGen.CreateUserRequest> =
|
||||
useFormik<TypesGen.CreateUserRequest>({
|
||||
initialValues: {
|
||||
@ -94,7 +93,7 @@ export const CreateUserForm: FC<
|
||||
password: "",
|
||||
username: "",
|
||||
name: "",
|
||||
organization_id: organizationId,
|
||||
organization_id: "00000000-0000-0000-0000-000000000000",
|
||||
disable_login: false,
|
||||
login_type: "",
|
||||
},
|
||||
|
@ -5,7 +5,6 @@ import { useNavigate } from "react-router-dom";
|
||||
import { authMethods, createUser } from "api/queries/users";
|
||||
import { displaySuccess } from "components/GlobalSnackbar/utils";
|
||||
import { Margins } from "components/Margins/Margins";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { CreateUserForm } from "./CreateUserForm";
|
||||
|
||||
@ -14,7 +13,6 @@ export const Language = {
|
||||
};
|
||||
|
||||
export const CreateUserPage: FC = () => {
|
||||
const { organizationId } = useDashboard();
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const createUserMutation = useMutation(createUser(queryClient));
|
||||
@ -38,7 +36,6 @@ export const CreateUserPage: FC = () => {
|
||||
navigate("..", { relative: "path" });
|
||||
}}
|
||||
isLoading={createUserMutation.isLoading}
|
||||
organizationId={organizationId}
|
||||
/>
|
||||
</Margins>
|
||||
);
|
||||
|
@ -33,13 +33,12 @@ export type CreateWorkspaceMode = (typeof createWorkspaceModes)[number];
|
||||
export type ExternalAuthPollingState = "idle" | "polling" | "abandoned";
|
||||
|
||||
const CreateWorkspacePage: FC = () => {
|
||||
const { template: templateName } = useParams() as {
|
||||
template: string;
|
||||
};
|
||||
const { organization: organizationName = "default", template: templateName } =
|
||||
useParams() as { organization?: string; template: string };
|
||||
const { user: me } = useAuthenticated();
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const { experiments, organizationId } = useDashboard();
|
||||
const { experiments } = useDashboard();
|
||||
|
||||
const customVersionId = searchParams.get("version") ?? undefined;
|
||||
const defaultName = searchParams.get("name");
|
||||
@ -54,15 +53,19 @@ const CreateWorkspacePage: FC = () => {
|
||||
);
|
||||
const createWorkspaceMutation = useMutation(createWorkspace(queryClient));
|
||||
|
||||
const templateQuery = useQuery(templateByName(organizationId, templateName));
|
||||
|
||||
const templateQuery = useQuery(
|
||||
templateByName(organizationName, templateName),
|
||||
);
|
||||
const permissionsQuery = useQuery(
|
||||
checkAuthorization({
|
||||
checks: createWorkspaceChecks(organizationId),
|
||||
}),
|
||||
templateQuery.data
|
||||
? checkAuthorization({
|
||||
checks: createWorkspaceChecks(templateQuery.data.organization_id),
|
||||
})
|
||||
: { enabled: false },
|
||||
);
|
||||
const realizedVersionId =
|
||||
customVersionId ?? templateQuery.data?.active_version_id;
|
||||
const organizationId = templateQuery.data?.organization_id;
|
||||
const richParametersQuery = useQuery({
|
||||
...richParameters(realizedVersionId ?? ""),
|
||||
enabled: realizedVersionId !== undefined,
|
||||
@ -110,7 +113,7 @@ const CreateWorkspacePage: FC = () => {
|
||||
|
||||
const autoCreationStartedRef = useRef(false);
|
||||
const automateWorkspaceCreation = useEffectEvent(async () => {
|
||||
if (autoCreationStartedRef.current) {
|
||||
if (autoCreationStartedRef.current || !organizationId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5,17 +5,15 @@ import { getErrorMessage } from "api/errors";
|
||||
import { groups } from "api/queries/groups";
|
||||
import { displayError } from "components/GlobalSnackbar/utils";
|
||||
import { useAuthenticated } from "contexts/auth/RequireAuth";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility";
|
||||
import { pageTitle } from "utils/page";
|
||||
import GroupsPageView from "./GroupsPageView";
|
||||
|
||||
export const GroupsPage: FC = () => {
|
||||
const { permissions } = useAuthenticated();
|
||||
const { organizationId } = useDashboard();
|
||||
const { createGroup: canCreateGroup } = permissions;
|
||||
const { template_rbac: isTemplateRBACEnabled } = useFeatureVisibility();
|
||||
const groupsQuery = useQuery(groups(organizationId));
|
||||
const groupsQuery = useQuery(groups("default"));
|
||||
|
||||
useEffect(() => {
|
||||
if (groupsQuery.error) {
|
||||
|
@ -51,7 +51,7 @@ import { pageTitle } from "utils/page";
|
||||
|
||||
export const GroupPage: FC = () => {
|
||||
const { organization = "default", groupName } = useParams() as {
|
||||
organization: string;
|
||||
organization?: string;
|
||||
groupName: string;
|
||||
};
|
||||
const queryClient = useQueryClient();
|
||||
|
@ -12,7 +12,7 @@ import GroupSettingsPageView from "./GroupSettingsPageView";
|
||||
|
||||
export const GroupSettingsPage: FC = () => {
|
||||
const { organization = "default", groupName } = useParams() as {
|
||||
organization: string;
|
||||
organization?: string;
|
||||
groupName: string;
|
||||
};
|
||||
const queryClient = useQueryClient();
|
||||
|
@ -30,7 +30,7 @@ export const GroupsPage: FC = () => {
|
||||
} = useFeatureVisibility();
|
||||
const { experiments } = useDashboard();
|
||||
const location = useLocation();
|
||||
const { organization = "default" } = useParams() as { organization: string };
|
||||
const { organization = "default" } = useParams() as { organization?: string };
|
||||
const groupsQuery = useQuery(groups(organization));
|
||||
const { organizations } = useOrganizationSettings();
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { createContext, type FC, Suspense, useContext } from "react";
|
||||
import { type FC, Suspense } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { Outlet } from "react-router-dom";
|
||||
import { deploymentConfig } from "api/queries/deployment";
|
||||
import { organizations } from "api/queries/organizations";
|
||||
import type { Organization } from "api/typesGenerated";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { Margins } from "components/Margins/Margins";
|
||||
@ -14,29 +13,17 @@ import NotFoundPage from "pages/404Page/404Page";
|
||||
import { DeploySettingsContext } from "../DeploySettingsPage/DeploySettingsLayout";
|
||||
import { Sidebar } from "./Sidebar";
|
||||
|
||||
type OrganizationSettingsContextValue = {
|
||||
organizations: Organization[];
|
||||
};
|
||||
type OrganizationSettingsValue = { organizations: Organization[] };
|
||||
|
||||
const OrganizationSettingsContext = createContext<
|
||||
OrganizationSettingsContextValue | undefined
|
||||
>(undefined);
|
||||
|
||||
export const useOrganizationSettings = (): OrganizationSettingsContextValue => {
|
||||
const context = useContext(OrganizationSettingsContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useOrganizationSettings should be used inside of OrganizationSettingsLayout",
|
||||
);
|
||||
}
|
||||
return context;
|
||||
export const useOrganizationSettings = (): OrganizationSettingsValue => {
|
||||
const { organizations } = useDashboard();
|
||||
return { organizations };
|
||||
};
|
||||
|
||||
export const ManagementSettingsLayout: FC = () => {
|
||||
const { permissions } = useAuthenticated();
|
||||
const { experiments } = useDashboard();
|
||||
const deploymentConfigQuery = useQuery(deploymentConfig());
|
||||
const organizationsQuery = useQuery(organizations());
|
||||
|
||||
const multiOrgExperimentEnabled = experiments.includes("multi-organization");
|
||||
|
||||
@ -48,30 +35,20 @@ export const ManagementSettingsLayout: FC = () => {
|
||||
<RequirePermission isFeatureVisible={permissions.viewDeploymentValues}>
|
||||
<Margins>
|
||||
<Stack css={{ padding: "48px 0" }} direction="row" spacing={6}>
|
||||
{organizationsQuery.data ? (
|
||||
<OrganizationSettingsContext.Provider
|
||||
value={{ organizations: organizationsQuery.data }}
|
||||
>
|
||||
<Sidebar />
|
||||
<main css={{ width: "100%" }}>
|
||||
{deploymentConfigQuery.data ? (
|
||||
<DeploySettingsContext.Provider
|
||||
value={{
|
||||
deploymentValues: deploymentConfigQuery.data,
|
||||
}}
|
||||
>
|
||||
<Suspense fallback={<Loader />}>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
</DeploySettingsContext.Provider>
|
||||
) : (
|
||||
<Loader />
|
||||
)}
|
||||
</main>
|
||||
</OrganizationSettingsContext.Provider>
|
||||
) : (
|
||||
<Loader />
|
||||
)}
|
||||
<Sidebar />
|
||||
<main css={{ width: "100%" }}>
|
||||
{deploymentConfigQuery.data ? (
|
||||
<DeploySettingsContext.Provider
|
||||
value={{ deploymentValues: deploymentConfigQuery.data }}
|
||||
>
|
||||
<Suspense fallback={<Loader />}>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
</DeploySettingsContext.Provider>
|
||||
) : (
|
||||
<Loader />
|
||||
)}
|
||||
</main>
|
||||
</Stack>
|
||||
</Margins>
|
||||
</RequirePermission>
|
||||
|
@ -9,15 +9,19 @@ import { useTemplateLayoutContext } from "pages/TemplatePage/TemplateLayout";
|
||||
import { getTemplatePageTitle } from "../utils";
|
||||
|
||||
const TemplateFilesPage: FC = () => {
|
||||
const { organization: organizationId = "default" } = useParams() as {
|
||||
organization: string;
|
||||
const { organization: organizationName = "default" } = useParams() as {
|
||||
organization?: string;
|
||||
};
|
||||
const { template, activeVersion } = useTemplateLayoutContext();
|
||||
const { data: currentFiles } = useQuery(
|
||||
templateFiles(activeVersion.job.file_id),
|
||||
);
|
||||
const previousVersionQuery = useQuery(
|
||||
previousTemplateVersion(organizationId, template.name, activeVersion.name),
|
||||
previousTemplateVersion(
|
||||
organizationName,
|
||||
template.name,
|
||||
activeVersion.name,
|
||||
),
|
||||
);
|
||||
const previousVersion = previousVersionQuery.data;
|
||||
const hasPreviousVersion =
|
||||
|
@ -71,14 +71,11 @@ export const TemplateLayout: FC<PropsWithChildren> = ({
|
||||
children = <Outlet />,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const { template: templateName, organization: organizationId = "default" } =
|
||||
useParams() as {
|
||||
template: string;
|
||||
organization: string;
|
||||
};
|
||||
const { organization: organizationName = "default", template: templateName } =
|
||||
useParams() as { organization?: string; template: string };
|
||||
const { data, error, isLoading } = useQuery({
|
||||
queryKey: ["template", templateName],
|
||||
queryFn: () => fetchTemplate(organizationId, templateName),
|
||||
queryFn: () => fetchTemplate(organizationName, templateName),
|
||||
});
|
||||
const location = useLocation();
|
||||
const paths = location.pathname.split("/");
|
||||
|
@ -7,19 +7,19 @@ import { templateByNameKey } from "api/queries/templates";
|
||||
import type { UpdateTemplateMeta } from "api/typesGenerated";
|
||||
import { displaySuccess } from "components/GlobalSnackbar/utils";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
import { linkToTemplate, useLinks } from "modules/navigation";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { useTemplateSettings } from "../TemplateSettingsLayout";
|
||||
import { TemplateSchedulePageView } from "./TemplateSchedulePageView";
|
||||
|
||||
const TemplateSchedulePage: FC = () => {
|
||||
const { template: templateName } = useParams() as { template: string };
|
||||
const getLink = useLinks();
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const { template } = useTemplateSettings();
|
||||
const { entitlements } = useDashboard();
|
||||
const { organization: organizationId = "default" } = useParams() as {
|
||||
organization: string;
|
||||
};
|
||||
const { organization: organizationName = "default", template: templateName } =
|
||||
useParams() as { organization?: string; template: string };
|
||||
const allowAdvancedScheduling =
|
||||
entitlements.features["advanced_template_scheduling"].enabled;
|
||||
|
||||
@ -32,7 +32,7 @@ const TemplateSchedulePage: FC = () => {
|
||||
{
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries(
|
||||
templateByNameKey(organizationId, templateName),
|
||||
templateByNameKey(organizationName, templateName),
|
||||
);
|
||||
displaySuccess("Template updated successfully");
|
||||
// clear browser storage of workspaces impending deletion
|
||||
@ -53,7 +53,7 @@ const TemplateSchedulePage: FC = () => {
|
||||
template={template}
|
||||
submitError={submitError}
|
||||
onCancel={() => {
|
||||
navigate(`/templates/${organizationId}/${templateName}`);
|
||||
navigate(getLink(linkToTemplate(organizationName, templateName)));
|
||||
}}
|
||||
onSubmit={(templateScheduleSettings) => {
|
||||
updateTemplate({
|
||||
|
@ -27,10 +27,7 @@ export function useTemplateSettings() {
|
||||
|
||||
export const TemplateSettingsLayout: FC = () => {
|
||||
const { organization: organizationName = "default", template: templateName } =
|
||||
useParams() as {
|
||||
organization: string;
|
||||
template: string;
|
||||
};
|
||||
useParams() as { organization?: string; template: string };
|
||||
const templateQuery = useQuery(
|
||||
templateByName(organizationName, templateName),
|
||||
);
|
||||
|
@ -16,13 +16,15 @@ import type {
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { displaySuccess } from "components/GlobalSnackbar/utils";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { linkToTemplate, useLinks } from "modules/navigation";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { useTemplateSettings } from "../TemplateSettingsLayout";
|
||||
import { TemplateVariablesPageView } from "./TemplateVariablesPageView";
|
||||
|
||||
export const TemplateVariablesPage: FC = () => {
|
||||
const getLink = useLinks();
|
||||
const { organization = "default", template: templateName } = useParams() as {
|
||||
organization: string;
|
||||
organization?: string;
|
||||
template: string;
|
||||
};
|
||||
const { template } = useTemplateSettings();
|
||||
@ -97,7 +99,7 @@ export const TemplateVariablesPage: FC = () => {
|
||||
publishError,
|
||||
}}
|
||||
onCancel={() => {
|
||||
navigate(`/templates/${organization}/${templateName}`);
|
||||
navigate(getLink(linkToTemplate(organization, templateName)));
|
||||
}}
|
||||
onSubmit={async (formData) => {
|
||||
const request = filterEmptySensitiveVariables(formData, variables);
|
||||
|
@ -35,7 +35,7 @@ export const TemplateVersionEditorPage: FC = () => {
|
||||
template: templateName,
|
||||
version: versionName,
|
||||
} = useParams() as {
|
||||
organization: string;
|
||||
organization?: string;
|
||||
template: string;
|
||||
version: string;
|
||||
};
|
||||
@ -194,7 +194,9 @@ export const TemplateVersionEditorPage: FC = () => {
|
||||
params.set("version", publishedVersion.id);
|
||||
}
|
||||
navigate(
|
||||
`/templates/${organizationName}/${templateName}/workspace?${params.toString()}`,
|
||||
`${getLink(
|
||||
linkToTemplate(organizationName, templateName),
|
||||
)}/workspace?${params.toString()}`,
|
||||
);
|
||||
}}
|
||||
isBuilding={
|
||||
|
@ -9,16 +9,18 @@ import {
|
||||
templateVersionByName,
|
||||
} from "api/queries/templates";
|
||||
import { useAuthenticated } from "contexts/auth/RequireAuth";
|
||||
import { linkToTemplate, useLinks } from "modules/navigation";
|
||||
import { pageTitle } from "utils/page";
|
||||
import TemplateVersionPageView from "./TemplateVersionPageView";
|
||||
|
||||
export const TemplateVersionPage: FC = () => {
|
||||
const getLink = useLinks();
|
||||
const {
|
||||
organization: organizationName = "default",
|
||||
template: templateName,
|
||||
version: versionName,
|
||||
} = useParams() as {
|
||||
organization: string;
|
||||
organization?: string;
|
||||
template: string;
|
||||
version: string;
|
||||
};
|
||||
@ -51,10 +53,12 @@ export const TemplateVersionPage: FC = () => {
|
||||
const params = new URLSearchParams();
|
||||
if (versionId) {
|
||||
params.set("version", versionId);
|
||||
return `/templates/${organizationName}/${templateName}/workspace?${params.toString()}`;
|
||||
return `${getLink(
|
||||
linkToTemplate(organizationName, templateName),
|
||||
)}/workspace?${params.toString()}`;
|
||||
}
|
||||
return undefined;
|
||||
}, [templateName, versionId, organizationName]);
|
||||
}, [getLink, templateName, versionId, organizationName]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -3,15 +3,13 @@ import { Helmet } from "react-helmet-async";
|
||||
import { useQuery } from "react-query";
|
||||
import { templateExamples, templates } from "api/queries/templates";
|
||||
import { useAuthenticated } from "contexts/auth/RequireAuth";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { TemplatesPageView } from "./TemplatesPageView";
|
||||
|
||||
export const TemplatesPage: FC = () => {
|
||||
const { permissions } = useAuthenticated();
|
||||
const { organizationId } = useDashboard();
|
||||
|
||||
const templatesQuery = useQuery(templates(organizationId));
|
||||
const templatesQuery = useQuery(templates());
|
||||
const examplesQuery = useQuery({
|
||||
...templateExamples("default"),
|
||||
enabled: permissions.createTemplates,
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
MockAppearanceConfig,
|
||||
MockAuthMethodsAll,
|
||||
MockBuildInfo,
|
||||
MockDefaultOrganization,
|
||||
MockEntitlements,
|
||||
MockExperiments,
|
||||
MockUser,
|
||||
@ -70,6 +71,7 @@ const meta = {
|
||||
{ key: ["entitlements"], data: MockEntitlements },
|
||||
{ key: ["experiments"], data: MockExperiments },
|
||||
{ key: ["appearance"], data: MockAppearanceConfig },
|
||||
{ key: ["organizations"], data: [MockDefaultOrganization] },
|
||||
{
|
||||
key: getAuthorizationKey({ checks: permissionsToCheck }),
|
||||
data: { editWorkspaceProxies: true },
|
||||
|
@ -13,11 +13,12 @@ export const AccountPage: FC = () => {
|
||||
const { permissions, user: me } = useAuthenticated();
|
||||
const { updateProfile, updateProfileError, isUpdatingProfile } =
|
||||
useAuthContext();
|
||||
const { entitlements, organizationId } = useDashboard();
|
||||
const { entitlements } = useDashboard();
|
||||
|
||||
const hasGroupsFeature = entitlements.features.user_role_management.enabled;
|
||||
const groupsQuery = useQuery({
|
||||
...groupsForUser(organizationId, me.id),
|
||||
// TODO: This should probably list all groups, not just default org groups
|
||||
...groupsForUser("default", me.id),
|
||||
enabled: hasGroupsFeature,
|
||||
});
|
||||
|
||||
|
@ -40,11 +40,11 @@ const UsersPage: FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const searchParamsResult = useSearchParams();
|
||||
const { entitlements, experiments, organizationId } = useDashboard();
|
||||
const { entitlements, experiments } = useDashboard();
|
||||
const [searchParams] = searchParamsResult;
|
||||
const isMultiOrg = experiments.includes("multi-organization");
|
||||
|
||||
const groupsByUserIdQuery = useQuery(groupsByUserId(organizationId));
|
||||
const groupsByUserIdQuery = useQuery(groupsByUserId("default"));
|
||||
const authMethodsQuery = useQuery(authMethods());
|
||||
|
||||
const { permissions, user: me } = useAuthenticated();
|
||||
|
@ -3,7 +3,7 @@ import { useQuery, useQueryClient } from "react-query";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { watchWorkspace } from "api/api";
|
||||
import { checkAuthorization } from "api/queries/authCheck";
|
||||
import { templateByName } from "api/queries/templates";
|
||||
import { template as templateQueryOptions } from "api/queries/templates";
|
||||
import { workspaceBuildsKey } from "api/queries/workspaceBuilds";
|
||||
import { workspaceByOwnerAndName } from "api/queries/workspaces";
|
||||
import type { Workspace } from "api/typesGenerated";
|
||||
@ -13,7 +13,6 @@ import { Margins } from "components/Margins/Margins";
|
||||
import { useEffectEvent } from "hooks/hookPolyfills";
|
||||
import { AnnouncementBanners } from "modules/dashboard/AnnouncementBanners/AnnouncementBanners";
|
||||
import { Navbar } from "modules/dashboard/Navbar/Navbar";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
import { workspaceChecks, type WorkspacePermissions } from "./permissions";
|
||||
import { WorkspaceReadyPage } from "./WorkspaceReadyPage";
|
||||
|
||||
@ -25,7 +24,6 @@ export const WorkspacePage: FC = () => {
|
||||
};
|
||||
const workspaceName = params.workspace;
|
||||
const username = params.username.replace("@", "");
|
||||
const { organizationId } = useDashboard();
|
||||
|
||||
// Workspace
|
||||
const workspaceQueryOptions = workspaceByOwnerAndName(
|
||||
@ -36,10 +34,11 @@ export const WorkspacePage: FC = () => {
|
||||
const workspace = workspaceQuery.data;
|
||||
|
||||
// Template
|
||||
const templateQuery = useQuery({
|
||||
...templateByName(organizationId, workspace?.template_name ?? ""),
|
||||
enabled: workspace !== undefined,
|
||||
});
|
||||
const templateQuery = useQuery(
|
||||
workspace
|
||||
? templateQueryOptions(workspace.template_id)
|
||||
: { enabled: false },
|
||||
);
|
||||
const template = templateQuery.data;
|
||||
|
||||
// Permissions
|
||||
|
@ -39,13 +39,12 @@ const WorkspacesPage: FC = () => {
|
||||
const searchParamsResult = useSafeSearchParams();
|
||||
const pagination = usePagination({ searchParamsResult });
|
||||
const { permissions } = useAuthenticated();
|
||||
const { entitlements, organizationId } = useDashboard();
|
||||
const { entitlements } = useDashboard();
|
||||
|
||||
const templatesQuery = useQuery(templates(organizationId, false));
|
||||
const templatesQuery = useQuery(templates());
|
||||
|
||||
const filterProps = useWorkspacesFilter({
|
||||
searchParamsResult,
|
||||
organizationId,
|
||||
onFilterChange: () => pagination.goToPage(1),
|
||||
});
|
||||
|
||||
@ -142,13 +141,11 @@ export default WorkspacesPage;
|
||||
type UseWorkspacesFilterOptions = {
|
||||
searchParamsResult: ReturnType<typeof useSearchParams>;
|
||||
onFilterChange: () => void;
|
||||
organizationId: string;
|
||||
};
|
||||
|
||||
const useWorkspacesFilter = ({
|
||||
searchParamsResult,
|
||||
onFilterChange,
|
||||
organizationId,
|
||||
}: UseWorkspacesFilterOptions) => {
|
||||
const filter = useFilter({
|
||||
fallbackFilter: "owner:me",
|
||||
@ -166,7 +163,6 @@ const useWorkspacesFilter = ({
|
||||
});
|
||||
|
||||
const templateMenu = useTemplateFilterMenu({
|
||||
organizationId,
|
||||
value: filter.values.template,
|
||||
onChange: (option) =>
|
||||
filter.update({ ...filter.values, template: option?.value }),
|
||||
|
@ -16,18 +16,14 @@ import { getDisplayWorkspaceStatus } from "utils/workspace";
|
||||
export const useTemplateFilterMenu = ({
|
||||
value,
|
||||
onChange,
|
||||
organizationId,
|
||||
}: { organizationId: string } & Pick<
|
||||
UseFilterMenuOptions<SelectFilterOption>,
|
||||
"value" | "onChange"
|
||||
>) => {
|
||||
}: Pick<UseFilterMenuOptions<SelectFilterOption>, "value" | "onChange">) => {
|
||||
return useFilterMenu({
|
||||
onChange,
|
||||
value,
|
||||
id: "template",
|
||||
getSelectedOption: async () => {
|
||||
// Show all templates including deprecated
|
||||
const templates = await API.getTemplates(organizationId);
|
||||
const templates = await API.getTemplates();
|
||||
const template = templates.find((template) => template.name === value);
|
||||
if (template) {
|
||||
return {
|
||||
@ -40,7 +36,7 @@ export const useTemplateFilterMenu = ({
|
||||
},
|
||||
getOptions: async (query) => {
|
||||
// Show all templates including deprecated
|
||||
const templates = await API.getTemplates(organizationId);
|
||||
const templates = await API.getTemplates();
|
||||
const filteredTemplates = templates.filter(
|
||||
(template) =>
|
||||
template.name.toLowerCase().includes(query.toLowerCase()) ||
|
||||
|
@ -42,7 +42,7 @@ export const handlers = [
|
||||
|
||||
// organizations
|
||||
http.get("/api/v2/organizations", () => {
|
||||
return HttpResponse.json([M.MockDefaultOrganization, M.MockOrganization2]);
|
||||
return HttpResponse.json([M.MockDefaultOrganization]);
|
||||
}),
|
||||
http.get("/api/v2/organizations/:organizationId", () => {
|
||||
return HttpResponse.json(M.MockOrganization);
|
||||
|
@ -3,7 +3,11 @@ import type { FC } from "react";
|
||||
import { withDefaultFeatures } from "api/api";
|
||||
import type { Entitlements } from "api/typesGenerated";
|
||||
import { DashboardContext } from "modules/dashboard/DashboardProvider";
|
||||
import { MockAppearanceConfig, MockEntitlements } from "./entities";
|
||||
import {
|
||||
MockAppearanceConfig,
|
||||
MockDefaultOrganization,
|
||||
MockEntitlements,
|
||||
} from "./entities";
|
||||
|
||||
export const withDashboardProvider = (
|
||||
Story: FC,
|
||||
@ -26,10 +30,10 @@ export const withDashboardProvider = (
|
||||
return (
|
||||
<DashboardContext.Provider
|
||||
value={{
|
||||
organizationId: "",
|
||||
entitlements,
|
||||
experiments,
|
||||
appearance: MockAppearanceConfig,
|
||||
organizations: [MockDefaultOrganization],
|
||||
}}
|
||||
>
|
||||
<Story />
|
||||
|
Reference in New Issue
Block a user