chore: clean up usage of Object.keys (#14484)

This commit is contained in:
Kayla Washburn-Love
2024-08-29 17:21:29 -06:00
committed by GitHub
parent d2a22c538b
commit 4672849d05
10 changed files with 83 additions and 111 deletions
+6 -10
View File
@@ -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>
))}
</>
);
};
+3 -15
View File
@@ -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)
+7 -6
View File
@@ -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);
};
@@ -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;
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)) {
return keyA.localeCompare(keyB);
}
if (typeof contentB === "object") {
return 1;
}
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;
@@ -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,
@@ -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>
);
};
@@ -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)}
@@ -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";
@@ -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();
@@ -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),
@@ -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);
@@ -51,7 +51,6 @@ export const WorkspaceBuildLogs: FC<WorkspaceBuildLogsProps> = ({
}) => {
const theme = useTheme();
const groupedLogsByStage = groupLogsByStage(logs);
const stages = Object.keys(groupedLogsByStage);
return (
<div
@@ -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,
+2 -4
View File
@@ -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];
@@ -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
@@ -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>
@@ -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>
) : (
@@ -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>
</>
) : (
@@ -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>
))}
+1 -2
View File
@@ -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);