mirror of https://github.com/coder/coder.git
chore: remove `useLocalStorage` hook (#11712)
This commit is contained in:
parent
fa99f6a200
commit
80eac73ed1
|
@ -327,7 +327,7 @@ func (c *DeviceAuth) AuthorizeDevice(ctx context.Context) (*codersdk.ExternalAut
|
|||
case http.StatusTooManyRequests:
|
||||
return nil, xerrors.New("rate limit hit, unable to authorize device. please try again later")
|
||||
default:
|
||||
return nil, fmt.Errorf("status_code=%d: %w", resp.StatusCode, err)
|
||||
return nil, xerrors.Errorf("status_code=%d: %w", resp.StatusCode, err)
|
||||
}
|
||||
}
|
||||
if r.ErrorDescription != "" {
|
||||
|
|
|
@ -1626,7 +1626,7 @@ func TestWorkspaceAgentExternalAuthListen(t *testing.T) {
|
|||
cancel()
|
||||
// We expect only 1
|
||||
// In a failed test, you will likely see 9, as the last one
|
||||
// gets cancelled.
|
||||
// gets canceled.
|
||||
require.Equal(t, 1, validateCalls, "validate calls duplicated on same token")
|
||||
})
|
||||
}
|
||||
|
|
|
@ -276,9 +276,9 @@ func (p *ProxyHealth) runOnce(ctx context.Context, now time.Time) (map[uuid.UUID
|
|||
case err == nil && resp.StatusCode == http.StatusOK:
|
||||
err := json.NewDecoder(resp.Body).Decode(&status.Report)
|
||||
if err != nil {
|
||||
isCoderErr := fmt.Errorf("proxy url %q is not a coder proxy instance, verify the url is correct", reqURL)
|
||||
isCoderErr := xerrors.Errorf("proxy url %q is not a coder proxy instance, verify the url is correct", reqURL)
|
||||
if resp.Header.Get(codersdk.BuildVersionHeader) != "" {
|
||||
isCoderErr = fmt.Errorf("proxy url %q is a coder instance, but unable to decode the response payload. Could this be a primary coderd and not a proxy?", reqURL)
|
||||
isCoderErr = xerrors.Errorf("proxy url %q is a coder instance, but unable to decode the response payload. Could this be a primary coderd and not a proxy?", reqURL)
|
||||
}
|
||||
|
||||
// If the response is not json, then the user likely input a bad url that returns status code 200.
|
||||
|
@ -286,7 +286,7 @@ func (p *ProxyHealth) runOnce(ctx context.Context, now time.Time) (map[uuid.UUID
|
|||
if notJSONErr := codersdk.ExpectJSONMime(resp); notJSONErr != nil {
|
||||
err = errors.Join(
|
||||
isCoderErr,
|
||||
fmt.Errorf("attempted to query health at %q but got back the incorrect content type: %w", reqURL, notJSONErr),
|
||||
xerrors.Errorf("attempted to query health at %q but got back the incorrect content type: %w", reqURL, notJSONErr),
|
||||
)
|
||||
|
||||
status.Report.Errors = []string{
|
||||
|
@ -300,7 +300,7 @@ func (p *ProxyHealth) runOnce(ctx context.Context, now time.Time) (map[uuid.UUID
|
|||
status.Report.Errors = []string{
|
||||
errors.Join(
|
||||
isCoderErr,
|
||||
fmt.Errorf("received a status code 200, but failed to decode health report body: %w", err),
|
||||
xerrors.Errorf("received a status code 200, but failed to decode health report body: %w", err),
|
||||
).Error(),
|
||||
}
|
||||
status.Status = Unhealthy
|
||||
|
|
|
@ -159,7 +159,7 @@ func New(ctx context.Context, opts *Options) (*Server, error) {
|
|||
info, err := client.SDKClient.BuildInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("buildinfo: %w", errors.Join(
|
||||
fmt.Errorf("unable to fetch build info from primary coderd. Are you sure %q is a coderd instance?", opts.DashboardURL),
|
||||
xerrors.Errorf("unable to fetch build info from primary coderd. Are you sure %q is a coderd instance?", opts.DashboardURL),
|
||||
err,
|
||||
))
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -1,12 +1,6 @@
|
|||
import { type PropsWithChildren } from "react";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { Abbr } from "./Abbr";
|
||||
|
||||
// Just here to make the abbreviated part more obvious in the component library
|
||||
const Underline = ({ children }: PropsWithChildren) => (
|
||||
<span css={{ textDecoration: "underline dotted" }}>{children}</span>
|
||||
);
|
||||
|
||||
const meta: Meta<typeof Abbr> = {
|
||||
title: "components/Abbr",
|
||||
component: Abbr,
|
||||
|
@ -34,9 +28,9 @@ export const InlinedShorthand: Story = {
|
|||
<p css={{ maxWidth: "40em" }}>
|
||||
The physical pain of getting bonked on the head with a cartoon mallet
|
||||
lasts precisely 593{" "}
|
||||
<Underline>
|
||||
<span css={styles.underlined}>
|
||||
<Story />
|
||||
</Underline>
|
||||
</span>
|
||||
. The emotional turmoil and complete embarrassment lasts forever.
|
||||
</p>
|
||||
),
|
||||
|
@ -51,9 +45,9 @@ export const Acronym: Story = {
|
|||
},
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<Underline>
|
||||
<span css={styles.underlined}>
|
||||
<Story />
|
||||
</Underline>
|
||||
</span>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
@ -66,9 +60,16 @@ export const Initialism: Story = {
|
|||
},
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<Underline>
|
||||
<span css={styles.underlined}>
|
||||
<Story />
|
||||
</Underline>
|
||||
</span>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
const styles = {
|
||||
// Just here to make the abbreviated part more obvious in the component library
|
||||
underlined: {
|
||||
textDecoration: "underline dotted",
|
||||
},
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ const createWrapper = (): FC<PropsWithChildren> => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
window.localStorage.clear();
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it("is dismissed when does not have permission to see it", () => {
|
||||
|
@ -57,7 +57,7 @@ it("is dismissed when it was dismissed previously", async () => {
|
|||
);
|
||||
}),
|
||||
);
|
||||
window.localStorage.setItem("dismissedVersion", MockUpdateCheck.version);
|
||||
localStorage.setItem("dismissedVersion", MockUpdateCheck.version);
|
||||
const { result } = renderHook(() => useUpdateCheck(true), {
|
||||
wrapper: createWrapper(),
|
||||
});
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import { FC, PropsWithChildren, useState, useRef } from "react";
|
||||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
||||
import ButtonGroup from "@mui/material/ButtonGroup";
|
||||
import Menu from "@mui/material/Menu";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import { type FC, useState, useRef } from "react";
|
||||
import { getApiKey } from "api/api";
|
||||
import { DisplayApp } from "api/typesGenerated";
|
||||
import { VSCodeIcon } from "components/Icons/VSCodeIcon";
|
||||
import { VSCodeInsidersIcon } from "components/Icons/VSCodeInsidersIcon";
|
||||
import { AgentButton } from "components/Resources/AgentButton";
|
||||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
||||
import ButtonGroup from "@mui/material/ButtonGroup";
|
||||
import { useLocalStorage } from "hooks";
|
||||
import Menu from "@mui/material/Menu";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import { DisplayApp } from "api/typesGenerated";
|
||||
import { DisplayAppNameMap } from "../AppLink/AppLink";
|
||||
|
||||
export interface VSCodeDesktopButtonProps {
|
||||
|
@ -23,12 +22,9 @@ type VSCodeVariant = "vscode" | "vscode-insiders";
|
|||
|
||||
const VARIANT_KEY = "vscode-variant";
|
||||
|
||||
export const VSCodeDesktopButton: FC<
|
||||
PropsWithChildren<VSCodeDesktopButtonProps>
|
||||
> = (props) => {
|
||||
export const VSCodeDesktopButton: FC<VSCodeDesktopButtonProps> = (props) => {
|
||||
const [isVariantMenuOpen, setIsVariantMenuOpen] = useState(false);
|
||||
const localStorage = useLocalStorage();
|
||||
const previousVariant = localStorage.getLocal(VARIANT_KEY);
|
||||
const previousVariant = localStorage.getItem(VARIANT_KEY);
|
||||
const [variant, setVariant] = useState<VSCodeVariant>(() => {
|
||||
if (!previousVariant) {
|
||||
return "vscode";
|
||||
|
@ -38,7 +34,7 @@ export const VSCodeDesktopButton: FC<
|
|||
const menuAnchorRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const selectVariant = (variant: VSCodeVariant) => {
|
||||
localStorage.saveLocal(VARIANT_KEY, variant);
|
||||
localStorage.setItem(VARIANT_KEY, variant);
|
||||
setVariant(variant);
|
||||
setIsVariantMenuOpen(false);
|
||||
};
|
||||
|
@ -109,12 +105,12 @@ export const VSCodeDesktopButton: FC<
|
|||
);
|
||||
};
|
||||
|
||||
const VSCodeButton = ({
|
||||
const VSCodeButton: FC<VSCodeDesktopButtonProps> = ({
|
||||
userName,
|
||||
workspaceName,
|
||||
agentName,
|
||||
folderPath,
|
||||
}: VSCodeDesktopButtonProps) => {
|
||||
}) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
return (
|
||||
|
@ -153,12 +149,12 @@ const VSCodeButton = ({
|
|||
);
|
||||
};
|
||||
|
||||
const VSCodeInsidersButton = ({
|
||||
const VSCodeInsidersButton: FC<VSCodeDesktopButtonProps> = ({
|
||||
userName,
|
||||
workspaceName,
|
||||
agentName,
|
||||
folderPath,
|
||||
}: VSCodeDesktopButtonProps) => {
|
||||
}) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
return (
|
||||
|
|
|
@ -19,7 +19,7 @@ import { screen } from "@testing-library/react";
|
|||
import { server } from "testHelpers/server";
|
||||
import { rest } from "msw";
|
||||
import { Region } from "api/typesGenerated";
|
||||
import "testHelpers/localstorage";
|
||||
import "testHelpers/localStorage";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
// Mock useProxyLatency to use a hard-coded latency. 'jest.mock' must be called
|
||||
|
@ -187,7 +187,7 @@ interface ProxyContextSelectionTest {
|
|||
|
||||
describe("ProxyContextSelection", () => {
|
||||
beforeEach(() => {
|
||||
window.localStorage.clear();
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
// A way to simulate a user clearing the proxy selection.
|
||||
|
|
|
@ -310,11 +310,11 @@ const computeUsableURLS = (proxy?: Region): PreferredProxy => {
|
|||
// Local storage functions
|
||||
|
||||
export const clearUserSelectedProxy = (): void => {
|
||||
window.localStorage.removeItem("user-selected-proxy");
|
||||
localStorage.removeItem("user-selected-proxy");
|
||||
};
|
||||
|
||||
export const saveUserSelectedProxy = (saved: Region): void => {
|
||||
window.localStorage.setItem("user-selected-proxy", JSON.stringify(saved));
|
||||
localStorage.setItem("user-selected-proxy", JSON.stringify(saved));
|
||||
};
|
||||
|
||||
export const loadUserSelectedProxy = (): Region | undefined => {
|
||||
|
|
|
@ -2,7 +2,6 @@ export * from "./useClickable";
|
|||
export * from "./useClickableTableRow";
|
||||
export * from "./useClipboard";
|
||||
export * from "./useFeatureVisibility";
|
||||
export * from "./useLocalStorage";
|
||||
export * from "./useMe";
|
||||
export * from "./useOrganizationId";
|
||||
export * from "./usePagination";
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
export const useLocalStorage = () => {
|
||||
return {
|
||||
saveLocal,
|
||||
getLocal,
|
||||
clearLocal,
|
||||
};
|
||||
};
|
||||
|
||||
const saveLocal = (itemKey: string, itemValue: string): void => {
|
||||
window.localStorage.setItem(itemKey, itemValue);
|
||||
};
|
||||
|
||||
const getLocal = (itemKey: string): string | undefined => {
|
||||
return localStorage.getItem(itemKey) ?? undefined;
|
||||
};
|
||||
|
||||
const clearLocal = (itemKey: string): void => {
|
||||
localStorage.removeItem(itemKey);
|
||||
};
|
|
@ -3,13 +3,13 @@ import { updateTemplateMeta } from "api/api";
|
|||
import { UpdateTemplateMeta } from "api/typesGenerated";
|
||||
import { useDashboard } from "components/Dashboard/DashboardProvider";
|
||||
import { displaySuccess } from "components/GlobalSnackbar/utils";
|
||||
import { FC } from "react";
|
||||
import { type FC } from "react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { pageTitle } from "utils/page";
|
||||
import { useTemplateSettings } from "../TemplateSettingsLayout";
|
||||
import { TemplateSchedulePageView } from "./TemplateSchedulePageView";
|
||||
import { useLocalStorage, useOrganizationId } from "hooks";
|
||||
import { useOrganizationId } from "hooks";
|
||||
import { templateByNameKey } from "api/queries/templates";
|
||||
|
||||
const TemplateSchedulePage: FC = () => {
|
||||
|
@ -21,7 +21,6 @@ const TemplateSchedulePage: FC = () => {
|
|||
const { entitlements } = useDashboard();
|
||||
const allowAdvancedScheduling =
|
||||
entitlements.features["advanced_template_scheduling"].enabled;
|
||||
const { clearLocal } = useLocalStorage();
|
||||
|
||||
const {
|
||||
mutate: updateTemplate,
|
||||
|
@ -36,8 +35,8 @@ const TemplateSchedulePage: FC = () => {
|
|||
);
|
||||
displaySuccess("Template updated successfully");
|
||||
// clear browser storage of workspaces impending deletion
|
||||
clearLocal("dismissedWorkspaceList"); // workspaces page
|
||||
clearLocal("dismissedWorkspace"); // workspace page
|
||||
localStorage.removeItem("dismissedWorkspaceList"); // workspaces page
|
||||
localStorage.removeItem("dismissedWorkspace"); // workspace page
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
|
@ -64,13 +64,13 @@ export interface TemplateVersionEditorProps {
|
|||
defaultFileTree: FileTree;
|
||||
buildLogs?: ProvisionerJobLog[];
|
||||
resources?: WorkspaceResource[];
|
||||
disablePreview: boolean;
|
||||
disableUpdate: boolean;
|
||||
disablePreview?: boolean;
|
||||
disableUpdate?: boolean;
|
||||
onPreview: (files: FileTree) => void;
|
||||
onPublish: () => void;
|
||||
onConfirmPublish: (data: PublishVersionData) => void;
|
||||
onCancelPublish: () => void;
|
||||
publishingError: unknown;
|
||||
publishingError?: unknown;
|
||||
publishedVersion?: TemplateVersion;
|
||||
onCreateWorkspace: () => void;
|
||||
isAskingPublishParameters: boolean;
|
||||
|
|
|
@ -317,7 +317,7 @@ describe("WorkspacePage", () => {
|
|||
});
|
||||
|
||||
it("restart the workspace with one time parameters when having the confirmation dialog", async () => {
|
||||
window.localStorage.removeItem(`${MockUser.id}_ignoredWarnings`);
|
||||
localStorage.removeItem(`${MockUser.id}_ignoredWarnings`);
|
||||
jest.spyOn(api, "getWorkspaceParameters").mockResolvedValue({
|
||||
templateVersionRichParameters: [
|
||||
{
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
export const localStorageMock = (): Storage => {
|
||||
const store = new Map<string, string>();
|
||||
|
||||
return {
|
||||
getItem: (key) => {
|
||||
return store.get(key) ?? null;
|
||||
},
|
||||
setItem: (key: string, value: string) => {
|
||||
store.set(key, value);
|
||||
},
|
||||
clear: () => {
|
||||
store.clear();
|
||||
},
|
||||
removeItem: (key: string) => {
|
||||
store.delete(key);
|
||||
},
|
||||
|
||||
get length() {
|
||||
return store.size;
|
||||
},
|
||||
|
||||
key: (index) => {
|
||||
const values = store.values();
|
||||
let value: IteratorResult<string, undefined> = values.next();
|
||||
for (let i = 1; i < index && !value.done; i++) {
|
||||
value = values.next();
|
||||
}
|
||||
|
||||
return value.value ?? null;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
Object.defineProperty(globalThis, "localStorage", {
|
||||
value: localStorageMock(),
|
||||
writable: false,
|
||||
});
|
|
@ -1,22 +0,0 @@
|
|||
export const localStorageMock = () => {
|
||||
const store = {} as Record<string, string>;
|
||||
|
||||
return {
|
||||
getItem: (key: string): string => {
|
||||
return store[key];
|
||||
},
|
||||
setItem: (key: string, value: string) => {
|
||||
store[key] = value;
|
||||
},
|
||||
clear: () => {
|
||||
Object.keys(store).forEach((key) => {
|
||||
delete store[key];
|
||||
});
|
||||
},
|
||||
removeItem: (key: string) => {
|
||||
delete store[key];
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
Object.defineProperty(window, "localStorage", { value: localStorageMock() });
|
Loading…
Reference in New Issue