Skip to content
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

refact: use hooks in more places + eliminate projects double-fetch #434

Merged
merged 10 commits into from
Sep 11, 2024
9 changes: 5 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"ajv": "^8.13.0",
"ansi_up": "^6.0.2",
"antd": "^5.16.0",
"bento-auth-js": "^5.1.1",
"bento-auth-js": "^6.0.1",
"bento-charts": "~2.6.8",
"cross-fetch": "^4.0.0",
"dayjs": "^1.11.11",
Expand Down
16 changes: 7 additions & 9 deletions src/components/ServiceContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import ServiceList from "./ServiceList";
import { SITE_NAME } from "@/constants";
import { EM_DASH } from "@/constants";
import { BENTO_URL } from "@/config";
import { useProjects } from "@/modules/metadata/hooks";

const ServiceContent = () => {
useEffect(() => {
document.title = `${SITE_NAME}: Admin / Services`;
}, []);

const projects = useSelector((state) => state.projects.items);
const isFetchingProjects = useSelector((state) => state.user.isFetchingDependentData || state.projects.isFetching);
const { items: projects, isFetching: isFetchingProjects } = useProjects();
const isFetching = useSelector((state) => state.user.isFetchingDependentData) || isFetchingProjects;

return (
<>
Expand All @@ -28,16 +29,13 @@ const ServiceContent = () => {
<Statistic title="Node URL" value={BENTO_URL} />
</Col>
<Col md={12} lg={8} xl={3}>
<Spin spinning={isFetchingProjects}>
<Statistic title="Projects" value={isFetchingProjects ? EM_DASH : projects.length} />
<Spin spinning={isFetching}>
<Statistic title="Projects" value={isFetching ? EM_DASH : projects.length} />
</Spin>
</Col>
<Col md={12} lg={8} xl={3}>
<Spin spinning={isFetchingProjects}>
<Statistic
title="Datasets"
value={isFetchingProjects ? EM_DASH : projects.flatMap((p) => p.datasets).length}
/>
<Spin spinning={isFetching}>
<Statistic title="Datasets" value={isFetching ? EM_DASH : projects.flatMap((p) => p.datasets).length} />
</Spin>
</Col>
</Row>
Expand Down
13 changes: 10 additions & 3 deletions src/components/SiteHeader.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { memo, useCallback, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
import { viewNotifications, useIsAuthenticated, usePerformSignOut, usePerformAuth, useAuthState } from "bento-auth-js";
import {
viewNotifications,
useIsAuthenticated,
usePerformSignOut,
usePerformAuth,
useAuthState,
useOpenIdConfig,
} from "bento-auth-js";

import { Badge, Layout, Menu, Spin } from "antd";
import {
Expand Down Expand Up @@ -62,7 +69,7 @@ const SiteHeader = () => {
useCanQueryAtLeastOneProjectOrDataset();
const { permissions: managerPermissions, hasAttempted: hasAttemptedManagerPermissions } = useManagerPermissions();

const { isFetching: openIdConfigFetching } = useSelector((state) => state.openIdConfiguration);
const { isFetching: openIdConfigFetching } = useOpenIdConfig();

const { unreadItems: unreadNotifications } = useNotifications();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import PropTypes from "prop-types";

import { Form, Modal } from "antd";
Expand All @@ -8,16 +8,18 @@ import LinkedFieldSetForm from "./LinkedFieldSetForm";

import { FORM_MODE_ADD } from "@/constants";
import { addDatasetLinkedFieldSetIfPossible, saveDatasetLinkedFieldSetIfPossible } from "@/modules/metadata/actions";
import { useDataTypes } from "@/modules/services/hooks";
import { datasetPropTypesShape, linkedFieldSetPropTypesShape, propTypesFormMode } from "@/propTypes";
import { nop } from "@/utils/misc";
import { useProjects } from "@/modules/metadata/hooks";

const LinkedFieldSetModal = ({ dataset, linkedFieldSetIndex, linkedFieldSet, mode, open, onCancel, onSubmit }) => {
const dispatch = useDispatch();

const [form] = Form.useForm();

const dataTypes = useSelector((state) => state.serviceDataTypes.itemsByID);
const isSavingDataset = useSelector((state) => state.projects.isSavingDataset);
const { itemsByID: dataTypes } = useDataTypes();
const { isSavingDataset } = useProjects();

const addLinkedFieldSet = useCallback(
(newLinkedFieldSet, onSuccess) =>
Expand Down
10 changes: 6 additions & 4 deletions src/components/explorer/ExplorerSearchContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { Navigate, Route, Routes } from "react-router-dom";

import { Layout, Menu, Skeleton } from "antd";

import ExplorerDatasetSearch from "./ExplorerDatasetSearch";
import SitePageHeader from "../SitePageHeader";
import { useDatasetsArray, useProjectsArray } from "@/modules/metadata/hooks";
import { LAYOUT_CONTENT_STYLE } from "@/styles/layoutContent";
import { matchingMenuKeys, transformMenuItem } from "@/utils/menu";

import ExplorerDatasetSearch from "./ExplorerDatasetSearch";
import SitePageHeader from "../SitePageHeader";

const ExplorerSearchContent = () => {
const projects = useSelector((state) => state.projects.items);
const projects = useProjectsArray();
const isFetchingDependentData = useSelector((state) => state.user.isFetchingDependentData);

const menuItems = useMemo(
Expand All @@ -27,7 +29,7 @@ const ExplorerSearchContent = () => {
[projects],
);

const datasets = useMemo(() => projects.flatMap((p) => p.datasets), [projects]);
const datasets = useDatasetsArray();

return (
<>
Expand Down
4 changes: 3 additions & 1 deletion src/components/explorer/IndividualTracks.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { debounce } from "lodash";

import igv from "igv/dist/igv.esm";

import { useAccessToken } from "bento-auth-js";

import { Button, Divider, Empty, Modal, Table, Select, Skeleton, Switch, message } from "antd";
import { SettingOutlined } from "@ant-design/icons";

Expand Down Expand Up @@ -146,7 +148,7 @@ const IGV_JS_ANNOTATION_ALIASES = {
};

const IndividualTracks = ({ individual }) => {
const { accessToken } = useSelector((state) => state.auth);
const accessToken = useAccessToken();

const igvDivRef = useRef();
const igvBrowserRef = useRef(null);
Expand Down
5 changes: 2 additions & 3 deletions src/components/manager/DatasetTitleDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { useSelector } from "react-redux";
import { Link } from "react-router-dom";

import { EM_DASH } from "@/constants";
import ErrorText from "@/components/common/ErrorText";
import MonospaceText from "@/components/common/MonospaceText";
import { useProjects } from "@/modules/metadata/hooks";

export type DatasetTitleDisplayProps = {
datasetID: string;
link?: boolean;
};

const DatasetTitleDisplay = ({ datasetID, link = false }: DatasetTitleDisplayProps) => {
// @ts-expect-error We have not typed the state yet
const datasetsByID = useSelector((state) => state.projects.datasetsByID);
const { datasetsByID } = useProjects();

if (!datasetID) return EM_DASH;

Expand Down
4 changes: 2 additions & 2 deletions src/components/manager/DatasetTreeSelect.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { forwardRef, useCallback, useEffect, useMemo, useState } from "react";
import { useSelector } from "react-redux";
import PropTypes from "prop-types";

import { Spin, TreeSelect } from "antd";
import { useProjects } from "@/modules/metadata/hooks";
import { useServices } from "@/modules/services/hooks";

export const ID_FORMAT_PROJECT_DATASET = "project:dataset";
export const ID_FORMAT_DATASET = "dataset";

const DatasetTreeSelect = forwardRef(({ value, onChange, style, idFormat }, ref) => {
const { items: projectItems, isFetching: projectsFetching } = useProjects();
const servicesFetching = useSelector((state) => state.services.isFetchingAll);
const { isFetchingAll: servicesFetching } = useServices();

const [selected, setSelected] = useState(value ?? undefined);

Expand Down
4 changes: 2 additions & 2 deletions src/components/manager/ManagerDropBoxContent.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { RESOURCE_EVERYTHING, deleteDropBox, ingestDropBox, viewDropBox } from "bento-auth-js";

import PropTypes from "prop-types";
Expand Down Expand Up @@ -173,7 +173,7 @@ const FileUploadModal = ({ initialUploadFolder, initialUploadFiles, onCancel, op
const dispatch = useDispatch();
const [form] = Form.useForm();

const isPutting = useSelector((state) => state.dropBox.isPuttingFlow);
const { isPuttingFlow: isPutting } = useDropBox();

useEffect(() => {
if (open) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/manager/access/GrantForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const handleSubjectChange = (
const SubjectInput = ({ value, onChange }: SubjectInputProps) => {
const groups: StoredGroup[] = useGroups().data;

const homeIssuer = useOpenIdConfig()?.issuer ?? "";
const homeIssuer = useOpenIdConfig().data?.issuer ?? "";
davidlougheed marked this conversation as resolved.
Show resolved Hide resolved

const [subjectType, setSubjectType] = useState<SubjectType>(SUBJECT_TYPE_EVERYONE);
const [iss, setIss] = useState(homeIssuer);
Expand Down Expand Up @@ -583,7 +583,7 @@ const PermissionsInput = ({ id, value, onChange, currentResource, ...rest }: Per
};

const GrantForm = ({ form }: { form: FormInstance<Grant> }) => {
const homeIssuer = useOpenIdConfig()?.issuer ?? "";
const homeIssuer = useOpenIdConfig().data?.issuer ?? "";
const defaultSubject = useMemo<GrantSubject>(() => ({ iss: homeIssuer, sub: "" }), [homeIssuer]);

const currentResource = Form.useWatch("resource", form);
Expand Down
2 changes: 1 addition & 1 deletion src/components/manager/access/GroupForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ type MembershipInputProps = {
};

const MembershipInput = ({ value, onChange, ...rest }: MembershipInputProps) => {
const homeIssuer = useOpenIdConfig()?.issuer ?? "";
const homeIssuer = useOpenIdConfig().data?.issuer ?? "";

const [membershipType, setMembershipType] = useState<"expr" | "list">("list");

Expand Down
11 changes: 6 additions & 5 deletions src/components/manager/drs/ManagerDRSContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ import { DeleteOutlined } from "@ant-design/icons";
import { RESOURCE_EVERYTHING, deleteData, downloadData, queryData } from "bento-auth-js";

import { EM_DASH } from "@/constants";
import { LAYOUT_CONTENT_STYLE } from "@/styles/layoutContent";

import BooleanYesNo from "@/components/common/BooleanYesNo";
import DownloadButton from "@/components/common/DownloadButton";
import MonospaceText from "@/components/common/MonospaceText";
import ForbiddenContent from "@/components/ForbiddenContent";
import { useResourcePermissionsWrapper } from "@/hooks";
import { clearDRSObjectSearch, deleteDRSObject, performDRSObjectSearch } from "@/modules/drs/actions";
import { useProjects } from "@/modules/metadata/hooks";
import { useService } from "@/modules/services/hooks";
import { LAYOUT_CONTENT_STYLE } from "@/styles/layoutContent";

import DatasetTitleDisplay from "../DatasetTitleDisplay";
import ProjectTitleDisplay from "../ProjectTitleDisplay";

Expand Down Expand Up @@ -161,8 +163,7 @@ const DRS_TABLE_EXPANDABLE = {
const ManagerDRSContent = () => {
const dispatch = useDispatch();

const projectsByID = useSelector((state) => state.projects.itemsByID);
const datasetsByID = useSelector((state) => state.projects.datasetsByID);
const { itemsByID: projectsByID, datasetsByID } = useProjects();

// TODO: per-object permissions
// For now, use whole-node permissions for DRS object viewer
Expand All @@ -178,7 +179,7 @@ const ManagerDRSContent = () => {
const hasDownloadPermission = permissions.includes(downloadData);
const hasDeletePermission = permissions.includes(deleteData);

const drsURL = useSelector((state) => state.services.drsService?.url);
const drsURL = useService("drs")?.url;
const {
objectSearchResults: rawObjectResults,
objectSearchIsFetching,
Expand Down
Loading