Skip to content

chore: remove global organization id state #14135

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 12 commits into from
Aug 5, 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
37 changes: 26 additions & 11 deletions site/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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 },
Expand Down
33 changes: 25 additions & 8 deletions site/src/api/queries/templates.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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),
};
};

Expand Down Expand Up @@ -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),
};
};
Expand Down
27 changes: 20 additions & 7 deletions site/src/modules/dashboard/DashboardProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
Expand All @@ -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 />;
Expand All @@ -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}
Expand Down
11 changes: 8 additions & 3 deletions site/src/modules/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

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

If the deployment has multiple organizations. but the organization's feature is not enabled, should this return true? The use case I'm seeing is a deployment that had access to enterprise and does not have it anymore after the trial.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, that's the goal. We don't want swaths of the app to become unaccessible because they're in the final stages of renewing a contract with us.

? `/templates/${organizationName}/${templateName}`
: `/templates/${templateName}`;
};
4 changes: 2 additions & 2 deletions site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"
/>
Expand Down
5 changes: 2 additions & 3 deletions site/src/pages/CreateUserPage/CreateUserForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export interface CreateUserFormProps {
onCancel: () => void;
error?: unknown;
isLoading: boolean;
organizationId: string;
authMethods?: TypesGen.AuthMethods;
}

Expand All @@ -86,15 +85,15 @@ 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: {
email: "",
password: "",
username: "",
name: "",
organization_id: organizationId,
organization_id: "00000000-0000-0000-0000-000000000000",
disable_login: false,
login_type: "",
},
Expand Down
3 changes: 0 additions & 3 deletions site/src/pages/CreateUserPage/CreateUserPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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));
Expand All @@ -38,7 +36,6 @@ export const CreateUserPage: FC = () => {
navigate("..", { relative: "path" });
}}
isLoading={createUserMutation.isLoading}
organizationId={organizationId}
/>
</Margins>
);
Expand Down
23 changes: 13 additions & 10 deletions site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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,
Expand Down Expand Up @@ -110,7 +113,7 @@ const CreateWorkspacePage: FC = () => {

const autoCreationStartedRef = useRef(false);
const automateWorkspaceCreation = useEffectEvent(async () => {
if (autoCreationStartedRef.current) {
if (autoCreationStartedRef.current || !organizationId) {
return;
}

Expand Down
4 changes: 1 addition & 3 deletions site/src/pages/GroupsPage/GroupsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
Loading
Loading