Skip to content

chore: clean up usage of Object.keys #14484

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 2 commits into from
Aug 29, 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
16 changes: 6 additions & 10 deletions site/src/components/Timeline/Timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,12 @@ export const Timeline = <TData,>({

return (
<>
{Object.keys(itemsByDate).map((dateStr) => {
const items = itemsByDate[dateStr];

return (
<Fragment key={dateStr}>
<TimelineDateRow date={new Date(dateStr)} />
{items.map(row)}
</Fragment>
);
})}
{Object.entries(itemsByDate).map(([dateStr, items]) => (
<Fragment key={dateStr}>
<TimelineDateRow date={new Date(dateStr)} />
{items.map(row)}
</Fragment>
))}
</>
);
};
18 changes: 3 additions & 15 deletions site/src/contexts/ProxyContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,21 +233,9 @@ const selectByLatency = (
return undefined;
}

const proxyMap = proxies.reduce(
(acc, proxy) => {
acc[proxy.id] = proxy;
return acc;
},
{} as Record<string, Region>,
);

const best = Object.keys(latencies)
.map((proxyId) => {
return {
id: proxyId,
...latencies[proxyId],
};
})
const proxyMap = Object.fromEntries(proxies.map((it) => [it.id, it]));
const best = Object.entries(latencies)
.map(([proxyId, latency]) => ({ id: proxyId, ...latency }))
// If the proxy is not in our list, or it is unhealthy, ignore it.
.filter((latency) => proxyMap[latency.id]?.healthy)
.sort((a, b) => a.latencyMS - b.latencyMS)
Expand Down
13 changes: 7 additions & 6 deletions site/src/modules/dashboard/entitlements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ export const getFeatureVisibility = (
return {};
}

const permissionPairs = Object.keys(features).map((feature) => {
const { entitlement, limit, actual, enabled } = features[feature];
const entitled = ["entitled", "grace_period"].includes(entitlement);
const limitCompliant = limit && actual ? limit >= actual : true;
return [feature, entitled && limitCompliant && enabled];
});
const permissionPairs = Object.entries(features).map(
([feature, { entitlement, limit, actual, enabled }]) => {
const entitled = ["entitled", "grace_period"].includes(entitlement);
const limitCompliant = limit && actual ? limit >= actual : true;
return [feature, entitled && limitCompliant && enabled];
},
);
return Object.fromEntries(permissionPairs);
};

Expand Down
49 changes: 24 additions & 25 deletions site/src/modules/templates/TemplateFiles/TemplateFileTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@ import { DockerIcon } from "components/Icons/DockerIcon";
import { type CSSProperties, type ElementType, type FC, useState } from "react";
import type { FileTree } from "utils/filetree";

const sortFileTree = (fileTree: FileTree) => (a: string, b: string) => {
const contentA = fileTree[a];
const contentB = fileTree[b];
if (typeof contentA === "object") {
return -1;
}
if (typeof contentB === "object") {
return 1;
const isFolder = (content?: FileTree | string): content is FileTree =>
typeof content === "object";

type FileTreeEntry = [key: string, content: FileTree | string];
function compareFileTreeEntries(
[keyA, contentA]: FileTreeEntry,
[keyB, contentB]: FileTreeEntry,
) {
// A and B are either both files or both folders, so they should be sorted
// lexically.
if (isFolder(contentA) === isFolder(contentB)) {
Copy link
Member

Choose a reason for hiding this comment

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

wonderful 👌

return keyA.localeCompare(keyB);
}
return a.localeCompare(b);
};
// Either A or B is a folder, and the other is a file. Put whichever one is a
// folder first.
return isFolder(contentA) ? -1 : 1;
}

type ContextMenu = {
path: string;
Expand Down Expand Up @@ -51,9 +57,6 @@ export const TemplateFileTree: FC<TemplateFilesTreeProps> = ({
}) => {
const [contextMenu, setContextMenu] = useState<ContextMenu | undefined>();

const isFolder = (content?: FileTree | string): content is FileTree =>
typeof content === "object";

const buildTreeItems = (
label: string,
filename: string,
Expand Down Expand Up @@ -181,12 +184,11 @@ export const TemplateFileTree: FC<TemplateFilesTreeProps> = ({
}
>
{isFolder(content) &&
Object.keys(content)
.sort(sortFileTree(content))
.map((filename) => {
const child = content[filename];
return buildTreeItems(filename, filename, child, currentPath);
})}
Object.entries(content)
.sort(compareFileTreeEntries)
.map(([filename, child]) =>
buildTreeItems(filename, filename, child, currentPath),
)}
</TreeItem>
);
};
Expand All @@ -198,12 +200,9 @@ export const TemplateFileTree: FC<TemplateFilesTreeProps> = ({
defaultExpandedItems={activePath ? expandablePaths(activePath) : []}
defaultSelectedItems={activePath}
>
{Object.keys(fileTree)
.sort(sortFileTree(fileTree))
.map((filename) => {
const child = fileTree[filename];
return buildTreeItems(filename, filename, child);
})}
{Object.entries(fileTree)
.sort(compareFileTreeEntries)
.map(([filename, child]) => buildTreeItems(filename, filename, child))}

<Menu
onClose={() => setContextMenu(undefined)}
Expand Down
14 changes: 6 additions & 8 deletions site/src/modules/templates/TemplateFiles/TemplateFiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { type Interpolation, type Theme, useTheme } from "@emotion/react";
import EditOutlined from "@mui/icons-material/EditOutlined";
import RadioButtonCheckedOutlined from "@mui/icons-material/RadioButtonCheckedOutlined";
import { SyntaxHighlighter } from "components/SyntaxHighlighter/SyntaxHighlighter";
import set from "lodash/fp/set";
import set from "lodash/set";
import { linkToTemplate, useLinks } from "modules/navigation";
import { type FC, useCallback, useMemo } from "react";
import { Link } from "react-router-dom";
Expand Down Expand Up @@ -31,8 +31,6 @@ export const TemplateFiles: FC<TemplateFilesProps> = ({
const getLink = useLinks();
const theme = useTheme();

const filenames = Object.keys(currentFiles);

const fileInfo = useCallback(
(filename: string) => {
const value = currentFiles[filename].trim();
Expand All @@ -49,13 +47,13 @@ export const TemplateFiles: FC<TemplateFilesProps> = ({
);

const fileTree: FileTree = useMemo(() => {
let tree: FileTree = {};
for (const filename of filenames) {
const tree: FileTree = {};
for (const filename of Object.keys(currentFiles)) {
const info = fileInfo(filename);
tree = set(filename.split("/"), info.value, tree);
set(tree, filename.split("/"), info.value);
}
return tree;
}, [fileInfo, filenames]);
}, [fileInfo, currentFiles]);

const versionLink = `${getLink(
linkToTemplate(organizationName, templateName),
Expand Down Expand Up @@ -88,7 +86,7 @@ export const TemplateFiles: FC<TemplateFilesProps> = ({
</div>

<div css={styles.files} data-testid="template-files-content">
{[...filenames]
{Object.keys(currentFiles)
.sort((a, b) => a.localeCompare(b))
.map((filename) => {
const info = fileInfo(filename);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export const WorkspaceBuildLogs: FC<WorkspaceBuildLogsProps> = ({
}) => {
const theme = useTheme();
const groupedLogsByStage = groupLogsByStage(logs);
const stages = Object.keys(groupedLogsByStage);

return (
<div
Expand All @@ -62,8 +61,7 @@ export const WorkspaceBuildLogs: FC<WorkspaceBuildLogsProps> = ({
}}
{...attrs}
>
{stages.map((stage) => {
const logs = groupedLogsByStage[stage];
{Object.entries(groupedLogsByStage).map(([stage, logs]) => {
const isEmpty = logs.every((log) => log.output === "");
const lines = logs.map((log) => ({
time: log.created_at,
Expand Down
6 changes: 2 additions & 4 deletions site/src/pages/HealthPage/HealthLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,9 @@ export const HealthLayout: FC = () => {
</div>

<nav css={{ display: "flex", flexDirection: "column", gap: 1 }}>
{Object.keys(visibleSections)
{Object.entries(visibleSections)
.sort()
.map((key) => {
const label =
visibleSections[key as keyof typeof visibleSections];
.map(([key, label]) => {
const healthSection =
healthStatus[key as keyof typeof visibleSections];

Expand Down
49 changes: 21 additions & 28 deletions site/src/pages/HealthPage/ProvisionerDaemonsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,10 @@ export const ProvisionerDaemonsPage: FC = () => {
const daemonScope = daemon.tags.scope || "organization";
const iconScope =
daemonScope === "organization" ? <Business /> : <Person />;
const extraTags = Object.keys(daemon.tags)
.filter((key) => key !== "scope" && key !== "owner")
.reduce(
(acc, key) => {
acc[key] = daemon.tags[key];
return acc;
},
{} as Record<string, string>,
);

const extraTags = Object.entries(daemon.tags).filter(
([key]) => key !== "scope" && key !== "owner",
);
const isWarning = warnings.length > 0;
return (
<div
Expand Down Expand Up @@ -131,8 +126,8 @@ export const ProvisionerDaemonsPage: FC = () => {
</span>
</Pill>
</Tooltip>
{Object.keys(extraTags).map((k) => (
<ProvisionerTag key={k} k={k} v={extraTags[k]} />
{extraTags.map(([key, value]) => (
<ProvisionerTag key={key} tagName={key} tagValue={value} />
))}
</div>
</header>
Expand All @@ -150,8 +145,8 @@ export const ProvisionerDaemonsPage: FC = () => {
>
{warnings.length > 0 ? (
<div css={{ display: "flex", flexDirection: "column" }}>
{warnings.map((warning, i) => (
<span key={i}>{warning.message}</span>
{warnings.map((warning) => (
<span key={warning.code}>{warning.message}</span>
))}
</div>
) : (
Expand Down Expand Up @@ -191,32 +186,30 @@ const parseBool = (s: string): { valid: boolean; value: boolean } => {
};

interface ProvisionerTagProps {
k: string;
v: string;
onDelete?: (key: string) => void;
tagName: string;
tagValue: string;
onDelete?: (tagName: string) => void;
}

export const ProvisionerTag: FC<ProvisionerTagProps> = ({ k, v, onDelete }) => {
const { valid, value: boolValue } = parseBool(v);
const kv = `${k}: ${v}`;
export const ProvisionerTag: FC<ProvisionerTagProps> = ({
tagName,
tagValue,
onDelete,
}) => {
const { valid, value: boolValue } = parseBool(tagValue);
const kv = `${tagName}: ${tagValue}`;
const content = onDelete ? (
<>
{kv}
<IconButton
aria-label={`delete-${k}`}
aria-label={`delete-${tagName}`}
size="small"
color="secondary"
onClick={() => {
onDelete(k);
onDelete(tagName);
}}
>
<CloseIcon
fontSize="inherit"
css={{
width: 14,
height: 14,
}}
/>
<CloseIcon fontSize="inherit" css={{ width: 14, height: 14 }} />
</IconButton>
</>
) : (
Expand Down
22 changes: 12 additions & 10 deletions site/src/pages/TemplateVersionEditorPage/ProvisionerTagsPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,19 @@ export const ProvisionerTagsPopover: FC<ProvisionerTagsPopoverProps> = ({
}
/>
<Stack direction="row" spacing={1} wrap="wrap">
{Object.keys(tags)
.filter((key) => {
// filter out owner since you cannot override it
return key !== "owner";
})
.map((k) => (
<Fragment key={k}>
{k === "scope" ? (
<ProvisionerTag k={k} v={tags[k]} />
{Object.entries(tags)
// filter out owner since you cannot override it
.filter(([key]) => key !== "owner")
.map(([key, value]) => (
<Fragment key={key}>
{key === "scope" ? (
<ProvisionerTag tagName={key} tagValue={value} />
) : (
<ProvisionerTag k={k} v={tags[k]} onDelete={onDelete} />
<ProvisionerTag
tagName={key}
tagValue={value}
onDelete={onDelete}
/>
)}
</Fragment>
))}
Expand Down
3 changes: 1 addition & 2 deletions site/src/utils/filetree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,8 @@ export const traverse = (
) => void,
parent?: string,
) => {
for (const filename of Object.keys(fileTree)) {
for (const [filename, content] of Object.entries(fileTree)) {
const fullPath = parent ? `${parent}/${filename}` : filename;
const content = fileTree[filename];
callback(content, filename, fullPath);
if (typeof content === "object") {
traverse(content, callback, fullPath);
Expand Down
Loading