coder/site/src/components/Dashboard/DashboardProvider.tsx

102 lines
3.0 KiB
TypeScript

import { useMachine } from "@xstate/react";
import {
AppearanceConfig,
BuildInfoResponse,
Entitlements,
Experiments,
} from "api/typesGenerated";
import { FullScreenLoader } from "components/Loader/FullScreenLoader";
import { createContext, FC, PropsWithChildren, useContext } from "react";
import { appearanceMachine } from "xServices/appearance/appearanceXService";
import { buildInfoMachine } from "xServices/buildInfo/buildInfoXService";
import { entitlementsMachine } from "xServices/entitlements/entitlementsXService";
import { experimentsMachine } from "xServices/experiments/experimentsMachine";
interface Appearance {
config: AppearanceConfig;
preview: boolean;
setPreview: (config: AppearanceConfig) => void;
save: (config: AppearanceConfig) => void;
}
interface DashboardProviderValue {
buildInfo: BuildInfoResponse;
entitlements: Entitlements;
appearance: Appearance;
experiments: Experiments;
}
export const DashboardProviderContext = createContext<
DashboardProviderValue | undefined
>(undefined);
export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
const [buildInfoState] = useMachine(buildInfoMachine);
const [entitlementsState] = useMachine(entitlementsMachine);
const [appearanceState, appearanceSend] = useMachine(appearanceMachine);
const [experimentsState] = useMachine(experimentsMachine);
const { buildInfo } = buildInfoState.context;
const { entitlements } = entitlementsState.context;
const { appearance, preview } = appearanceState.context;
const { experiments } = experimentsState.context;
const isLoading = !buildInfo || !entitlements || !appearance || !experiments;
const setAppearancePreview = (config: AppearanceConfig) => {
appearanceSend({
type: "SET_PREVIEW_APPEARANCE",
appearance: config,
});
};
const saveAppearance = (config: AppearanceConfig) => {
appearanceSend({
type: "SAVE_APPEARANCE",
appearance: config,
});
};
if (isLoading) {
return <FullScreenLoader />;
}
return (
<DashboardProviderContext.Provider
value={{
buildInfo,
entitlements,
experiments,
appearance: {
preview,
config: appearance,
setPreview: setAppearancePreview,
save: saveAppearance,
},
}}
>
{children}
</DashboardProviderContext.Provider>
);
};
export const useDashboard = (): DashboardProviderValue => {
const context = useContext(DashboardProviderContext);
if (!context) {
throw new Error(
"useDashboard only can be used inside of DashboardProvider",
);
}
return context;
};
export const useIsWorkspaceActionsEnabled = (): boolean => {
const { entitlements, experiments } = useDashboard();
const allowAdvancedScheduling =
entitlements.features["advanced_template_scheduling"].enabled;
// This check can be removed when https://github.com/coder/coder/milestone/19
// is merged up
const allowWorkspaceActions = experiments.includes("workspace_actions");
return allowWorkspaceActions && allowAdvancedScheduling;
};