refactor/hooks #7
@ -2,18 +2,22 @@ export interface ExpressionSetCardProps {
|
|||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
expression_count: number;
|
expression_count: number;
|
||||||
|
expression_count_loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ExpressionSetCard({
|
export function ExpressionSetCard({
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
expression_count,
|
expression_count,
|
||||||
|
expression_count_loading,
|
||||||
}: ExpressionSetCardProps) {
|
}: ExpressionSetCardProps) {
|
||||||
return (
|
return (
|
||||||
<article className="content-card">
|
<article className="content-card">
|
||||||
<h2 className="content-row text-title margin-small">{name}</h2>
|
<h2 className="content-row text-title margin-small">{name}</h2>
|
||||||
<span className="content-row text-meta margin-small">
|
<span className="content-row text-meta margin-small">
|
||||||
{expression_count} expressions(s)
|
{expression_count_loading
|
||||||
|
? "loading"
|
||||||
|
: `${expression_count} expressions(s)`}
|
||||||
</span>
|
</span>
|
||||||
<p className="content-row text-details margin-paragraph">{description}</p>
|
<p className="content-row text-details margin-paragraph">{description}</p>
|
||||||
</article>
|
</article>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
export * from "./useExpressionCategories";
|
export * from "./useAllExpressions";
|
||||||
|
export * from "./useAllExpressionSets";
|
||||||
|
export * from "./useCategoriesByExpressionId";
|
||||||
export * from "./useExpressionById";
|
export * from "./useExpressionById";
|
||||||
export * from "./useExpressionFilterQueryIds";
|
export * from "./useExpressionsByExpressionSetId";
|
||||||
export * from "./useExpressionQueryId";
|
export * from "./useExpressionSetById";
|
||||||
export * from "./useExpressions";
|
export * from "./useQueryExpressionId";
|
||||||
export * from "./useExpressionSet";
|
export * from "./useQueryExpressionIdFilters";
|
||||||
export * from "./useExpressionSetQueryId";
|
export * from "./useQueryExpressionSetId";
|
||||||
export * from "./useExpressionSets";
|
|
||||||
export * from "./useExpressionsInSet";
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useLiveQuery } from "dexie-react-hooks";
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
import { database } from "../model";
|
import { database } from "../model";
|
||||||
|
|
||||||
export function useExpressionSets() {
|
export function useAllExpressionSets() {
|
||||||
return useLiveQuery(() => database.expression_sets.toArray());
|
return useLiveQuery(() => database.expression_sets.toArray());
|
||||||
}
|
}
|
6
src/hooks/useAllExpressions.ts
Normal file
6
src/hooks/useAllExpressions.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
|
import { database } from "../model";
|
||||||
|
|
||||||
|
export function useAllExpressions() {
|
||||||
|
return useLiveQuery(() => database.expressions.toArray());
|
||||||
|
}
|
@ -1,7 +1,10 @@
|
|||||||
import { useLiveQuery } from "dexie-react-hooks";
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
import { database } from "../model";
|
import { database } from "../model";
|
||||||
|
|
||||||
export function useExpressionCategories(expression_id: number) {
|
// TODO there may be a case here for reporting errors where relations exist
|
||||||
|
// but some referenced item does not exist in its table, maybe the
|
||||||
|
// return value should be { entries[], errors[] }
|
||||||
|
export function useCategoriesByExpressionId(expression_id: number) {
|
||||||
return useLiveQuery(() => {
|
return useLiveQuery(() => {
|
||||||
return database.expression_to_category
|
return database.expression_to_category
|
||||||
.where({ expression_id })
|
.where({ expression_id })
|
@ -1,9 +1,16 @@
|
|||||||
import { useLiveQuery } from "dexie-react-hooks";
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
import { database, IndexedExpression } from "../model";
|
import { database, ItemNotFoundError } from "../model";
|
||||||
|
|
||||||
export function useExpressionById(id?: number): IndexedExpression | undefined {
|
export function useExpressionById(expression_id: number) {
|
||||||
return useLiveQuery(() => {
|
return useLiveQuery(
|
||||||
if (id === undefined) return undefined;
|
() =>
|
||||||
return database.expressions.where({ id }).first();
|
database.expressions
|
||||||
}, [id]);
|
.where({ id: expression_id })
|
||||||
|
.toArray()
|
||||||
|
.then((result) => {
|
||||||
|
if (result.length === 0) return ItemNotFoundError;
|
||||||
|
return result[0];
|
||||||
|
}),
|
||||||
|
[expression_id]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
import { useLiveQuery } from "dexie-react-hooks";
|
|
||||||
import { database } from "../model";
|
|
||||||
|
|
||||||
export function useExpressionSet(id: number) {
|
|
||||||
return useLiveQuery(
|
|
||||||
() => database.expression_sets.where({ id }).first(),
|
|
||||||
[id]
|
|
||||||
);
|
|
||||||
}
|
|
16
src/hooks/useExpressionSetById.ts
Normal file
16
src/hooks/useExpressionSetById.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
|
import { database, ItemNotFoundError } from "../model";
|
||||||
|
|
||||||
|
export function useExpressionSetById(expression_set_id: number) {
|
||||||
|
return useLiveQuery(
|
||||||
|
() =>
|
||||||
|
database.expression_sets
|
||||||
|
.where({ id: expression_set_id })
|
||||||
|
.toArray()
|
||||||
|
.then((result) => {
|
||||||
|
if (result.length === 0) return ItemNotFoundError;
|
||||||
|
return result[0];
|
||||||
|
}),
|
||||||
|
[expression_set_id]
|
||||||
|
);
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
import { useLiveQuery } from "dexie-react-hooks";
|
|
||||||
import { database } from "../model";
|
|
||||||
|
|
||||||
export function useExpressions() {
|
|
||||||
return useLiveQuery(
|
|
||||||
() => database.expressions.toArray(),
|
|
||||||
[database.expressions]
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,7 +1,10 @@
|
|||||||
import { useLiveQuery } from "dexie-react-hooks";
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
import { database } from "../model";
|
import { database } from "../model";
|
||||||
|
|
||||||
export function useExpressionsInSet(expression_set_id: number) {
|
// TODO there may be a case here for reporting errors where relations exist
|
||||||
|
// but some referenced item does not exist in its table, maybe the
|
||||||
|
// return value should be { entries[], errors[] }
|
||||||
|
export function useExpressionsByExpressionSetId(expression_set_id: number) {
|
||||||
return useLiveQuery(() => {
|
return useLiveQuery(() => {
|
||||||
return database.expression_to_expression_set
|
return database.expression_to_expression_set
|
||||||
.where({ expression_set_id })
|
.where({ expression_set_id })
|
@ -1,7 +1,7 @@
|
|||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import { AppRouting } from "../model/routing";
|
import { AppRouting } from "../model/routing";
|
||||||
|
|
||||||
export function useExpressionQueryId(): number | undefined {
|
export function useQueryExpressionId() {
|
||||||
const { route } = useContext(AppRouting);
|
const { route } = useContext(AppRouting);
|
||||||
return route.options?.expression_card_id;
|
return route.options?.expression_id || 0;
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import { AppRouting } from "../model/routing";
|
import { AppRouting } from "../model/routing";
|
||||||
|
|
||||||
export function useExpressionFilterQueryIds(): number[] {
|
export function useQueryExpressionIdFilters() {
|
||||||
const { route } = useContext(AppRouting);
|
const { route } = useContext(AppRouting);
|
||||||
return route.options?.expression_id_filters || [];
|
return route.options?.expression_id_filters || ([] as number[]);
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import { AppRouting } from "../model/routing";
|
import { AppRouting } from "../model/routing";
|
||||||
|
|
||||||
export function useExpressionSetQueryId(): number {
|
export function useQueryExpressionSetId() {
|
||||||
const { route } = useContext(AppRouting);
|
const { route } = useContext(AppRouting);
|
||||||
return route.options?.expression_set_id || 0;
|
return route.options?.expression_set_id || 0;
|
||||||
}
|
}
|
@ -14,6 +14,8 @@ export type IndexedExpression = WithId<Expression>;
|
|||||||
export type IndexedExpressionSet = WithId<ExpressionSet>;
|
export type IndexedExpressionSet = WithId<ExpressionSet>;
|
||||||
export type IndexedCategory = WithId<Category>;
|
export type IndexedCategory = WithId<Category>;
|
||||||
|
|
||||||
|
export const ItemNotFoundError = Symbol();
|
||||||
|
|
||||||
class Database extends Dexie {
|
class Database extends Dexie {
|
||||||
expressions!: Table<IndexedExpression, number>;
|
expressions!: Table<IndexedExpression, number>;
|
||||||
expression_sets!: Table<IndexedExpressionSet, number>;
|
expression_sets!: Table<IndexedExpressionSet, number>;
|
||||||
|
@ -14,7 +14,7 @@ export enum AppPath {
|
|||||||
|
|
||||||
export interface RouteOptions {
|
export interface RouteOptions {
|
||||||
// Used in cards view
|
// Used in cards view
|
||||||
expression_card_id?: number;
|
expression_id?: number;
|
||||||
|
|
||||||
// Used in practice view
|
// Used in practice view
|
||||||
expression_set_id?: number;
|
expression_set_id?: number;
|
||||||
|
@ -17,6 +17,8 @@ export function AddExpressionView() {
|
|||||||
useState<string | undefined>(undefined);
|
useState<string | undefined>(undefined);
|
||||||
const [error, setError] = useState<any>(undefined);
|
const [error, setError] = useState<any>(undefined);
|
||||||
|
|
||||||
|
// TODO waiting fetch completion elements
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="page-with-bottom-navigation">
|
<form className="page-with-bottom-navigation">
|
||||||
<section className="padding-small scroll">
|
<section className="padding-small scroll">
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { useContext, useMemo } from "react";
|
import { useContext, useMemo } from "react";
|
||||||
import { ExpressionCard } from "../../components";
|
import { ExpressionCard } from "../../components";
|
||||||
import { useExpressions } from "../../hooks";
|
import { useAllExpressions } from "../../hooks";
|
||||||
import { IndexedExpression } from "../../model";
|
import { IndexedExpression } from "../../model";
|
||||||
import { AppPath, AppRouting } from "../../model/routing";
|
import { AppPath, AppRouting } from "../../model/routing";
|
||||||
import { ErrorView } from "../ErrorView";
|
import { ErrorView } from "../ErrorView";
|
||||||
|
|
||||||
export function ExpressionCardListView() {
|
export function ExpressionCardListView() {
|
||||||
const { setRoute } = useContext(AppRouting);
|
const { setRoute } = useContext(AppRouting);
|
||||||
const expressions = useExpressions();
|
const expressions = useAllExpressions();
|
||||||
const expression_list = useMemo(
|
const expression_list = useMemo(
|
||||||
() => (expressions || []).concat().sort(sort_function),
|
() => (expressions || []).concat().sort(sort_function),
|
||||||
[expressions]
|
[expressions]
|
||||||
@ -27,7 +27,7 @@ export function ExpressionCardListView() {
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
setRoute({
|
setRoute({
|
||||||
path: AppPath.CardView,
|
path: AppPath.CardView,
|
||||||
options: { expression_card_id: id },
|
options: { expression_id: id },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
import { ExpressionCard } from "../../components";
|
import { ExpressionCard } from "../../components";
|
||||||
import { ExpressionDescription } from "../../components/ExpressionDescription";
|
import { ExpressionDescription } from "../../components/ExpressionDescription";
|
||||||
import { useExpressionById, useExpressionQueryId } from "../../hooks";
|
import { useExpressionById, useQueryExpressionId } from "../../hooks";
|
||||||
|
import { ItemNotFoundError } from "../../model";
|
||||||
import { ErrorView } from "../ErrorView";
|
import { ErrorView } from "../ErrorView";
|
||||||
|
|
||||||
export function ExpressionCardView() {
|
export function ExpressionCardView() {
|
||||||
const expression_id = useExpressionQueryId();
|
const expression_id = useQueryExpressionId();
|
||||||
const expression = useExpressionById(expression_id);
|
const expression = useExpressionById(expression_id);
|
||||||
if (!expression) return <ErrorView message="No valid card selected" />;
|
|
||||||
|
if (expression === undefined) return null; // LOADING
|
||||||
|
if (expression === ItemNotFoundError)
|
||||||
|
return <ErrorView message="Expression card not found" />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page-with-padding content-list scroll">
|
<div className="page-with-padding content-list scroll">
|
||||||
<ExpressionCard
|
<ExpressionCard
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { useCallback, useContext } from "react";
|
import { useCallback, useContext } from "react";
|
||||||
import {
|
import {
|
||||||
useExpressionFilterQueryIds,
|
useQueryExpressionIdFilters,
|
||||||
useExpressionSetQueryId,
|
useQueryExpressionSetId,
|
||||||
} from "../../hooks";
|
} from "../../hooks";
|
||||||
import { assignExpressionToSet } from "../../model";
|
import { assignExpressionToSet } from "../../model";
|
||||||
import { AppRouting } from "../../model/routing";
|
import { AppRouting } from "../../model/routing";
|
||||||
|
|
||||||
// TODO fix promotion algorithm so it uses a destination expression_set_id
|
// TODO ensure that the destination expression set exists
|
||||||
|
|
||||||
export interface DemoteExpressionButtonProps {
|
export interface DemoteExpressionButtonProps {
|
||||||
expression_id: number;
|
expression_id: number;
|
||||||
@ -16,8 +16,8 @@ export function DemoteExpressionButton({
|
|||||||
expression_id,
|
expression_id,
|
||||||
}: DemoteExpressionButtonProps) {
|
}: DemoteExpressionButtonProps) {
|
||||||
const { route, setRoute } = useContext(AppRouting);
|
const { route, setRoute } = useContext(AppRouting);
|
||||||
const expression_set_id = useExpressionSetQueryId();
|
const expression_set_id = useQueryExpressionSetId();
|
||||||
const expression_id_filters = useExpressionFilterQueryIds();
|
const expression_id_filters = useQueryExpressionIdFilters();
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
if (expression_set_id === 1) {
|
if (expression_set_id === 1) {
|
||||||
setRoute({
|
setRoute({
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import {
|
import {
|
||||||
useExpressionCategories,
|
useCategoriesByExpressionId,
|
||||||
useExpressionFilterQueryIds,
|
useQueryExpressionIdFilters,
|
||||||
useExpressionSetQueryId,
|
useQueryExpressionSetId,
|
||||||
useExpressionsInSet,
|
useExpressionsByExpressionSetId,
|
||||||
} from "../../hooks";
|
} from "../../hooks";
|
||||||
import { IndexedExpression } from "../../model";
|
import { IndexedExpression } from "../../model";
|
||||||
import { sample } from "../../util";
|
import { sample } from "../../util";
|
||||||
@ -11,18 +11,13 @@ import { ErrorView } from "../ErrorView";
|
|||||||
import { ExpressionPracticeCardView } from "./ExpressionPracticeCardView";
|
import { ExpressionPracticeCardView } from "./ExpressionPracticeCardView";
|
||||||
|
|
||||||
export function ExpressionPracticeView() {
|
export function ExpressionPracticeView() {
|
||||||
const expression_set_id = useExpressionSetQueryId();
|
const expression_set_id = useQueryExpressionSetId();
|
||||||
const filter_ids = useExpressionFilterQueryIds();
|
const filter_ids = useQueryExpressionIdFilters();
|
||||||
const expressions = useExpressionsInSet(expression_set_id);
|
const expressions = useExpressionsByExpressionSetId(expression_set_id);
|
||||||
|
// TODO handle errors
|
||||||
|
|
||||||
// Fallback rendering for content not yet fetched
|
if (!expressions) return null; // LOADING
|
||||||
if (!expressions) return null;
|
|
||||||
if (!filter_ids) return null;
|
|
||||||
|
|
||||||
// Fallback views for expression set content not found
|
|
||||||
if (!expression_set_id) {
|
|
||||||
return <ErrorView message="Expression set not found" />;
|
|
||||||
}
|
|
||||||
const filtered_expressions = expressions.filter(
|
const filtered_expressions = expressions.filter(
|
||||||
(expression) => !filter_ids.includes(expression.id!)
|
(expression) => !filter_ids.includes(expression.id!)
|
||||||
);
|
);
|
||||||
@ -45,7 +40,7 @@ function ExpressionPracticeViewImpl({
|
|||||||
select_from_expressions: expressions,
|
select_from_expressions: expressions,
|
||||||
}: ExpressionPracticeViewImplProps) {
|
}: ExpressionPracticeViewImplProps) {
|
||||||
const expression = useMemo(() => sample(expressions), [expressions]);
|
const expression = useMemo(() => sample(expressions), [expressions]);
|
||||||
const categories = useExpressionCategories(expression.id!);
|
const categories = useCategoriesByExpressionId(expression.id!);
|
||||||
if (!categories) return null; // Loading
|
if (!categories) return null; // Loading
|
||||||
|
|
||||||
// Delegate internal interaction state to next component so it resets
|
// Delegate internal interaction state to next component so it resets
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { useExpressionSetQueryId } from "../../hooks";
|
import { useQueryExpressionSetId } from "../../hooks";
|
||||||
import { assignExpressionToSet, database, removeExpression } from "../../model";
|
import { assignExpressionToSet, database, removeExpression } from "../../model";
|
||||||
|
|
||||||
export interface PromoteExpressionButtonProps {
|
export interface PromoteExpressionButtonProps {
|
||||||
@ -12,7 +12,7 @@ export interface PromoteExpressionButtonProps {
|
|||||||
export function PromoteExpressionButton({
|
export function PromoteExpressionButton({
|
||||||
expression_id,
|
expression_id,
|
||||||
}: PromoteExpressionButtonProps) {
|
}: PromoteExpressionButtonProps) {
|
||||||
const expression_set_id = useExpressionSetQueryId();
|
const expression_set_id = useQueryExpressionSetId();
|
||||||
const handleClick = useCallback(async () => {
|
const handleClick = useCallback(async () => {
|
||||||
const existing_next_level = await database.expression_sets
|
const existing_next_level = await database.expression_sets
|
||||||
.where({ id: expression_set_id + 1 })
|
.where({ id: expression_set_id + 1 })
|
||||||
|
@ -1,26 +1,24 @@
|
|||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import { ExpressionSetInfo } from "../../components";
|
import { ExpressionSetInfo } from "../../components";
|
||||||
import {
|
import {
|
||||||
useExpressionSet,
|
useExpressionSetById,
|
||||||
useExpressionSetQueryId,
|
useQueryExpressionSetId,
|
||||||
useExpressionsInSet,
|
useExpressionsByExpressionSetId,
|
||||||
} from "../../hooks";
|
} from "../../hooks";
|
||||||
import { IndexedExpressionSet } from "../../model";
|
import { IndexedExpressionSet, ItemNotFoundError } from "../../model";
|
||||||
import { AppPath, AppRouting } from "../../model/routing";
|
import { AppPath, AppRouting } from "../../model/routing";
|
||||||
import { ErrorView } from "../ErrorView";
|
import { ErrorView } from "../ErrorView";
|
||||||
|
|
||||||
export function ExpressionSetDetailsView() {
|
export function ExpressionSetDetailsView() {
|
||||||
const expression_set_id = useExpressionSetQueryId();
|
const expression_set_id = useQueryExpressionSetId();
|
||||||
const expression_set = useExpressionSet(expression_set_id);
|
const expression_set = useExpressionSetById(expression_set_id);
|
||||||
const expressions = useExpressionsInSet(expression_set_id);
|
const expressions = useExpressionsByExpressionSetId(expression_set_id);
|
||||||
|
|
||||||
// Fallback for expression set not found
|
if (!expression_set || !expressions) return null; // LOADING
|
||||||
if (!expressions) return null;
|
if (expression_set === ItemNotFoundError) {
|
||||||
if (!expression_set) {
|
|
||||||
return <ErrorView message="Expression set not found" />;
|
return <ErrorView message="Expression set not found" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback for expression set empty
|
|
||||||
return (
|
return (
|
||||||
<ExpressionSetDetailsViewImpl
|
<ExpressionSetDetailsViewImpl
|
||||||
expression_set={expression_set}
|
expression_set={expression_set}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import { ExpressionSetCard } from "../../components";
|
import { ExpressionSetCard } from "../../components";
|
||||||
import { useExpressionsInSet } from "../../hooks";
|
import { useExpressionsByExpressionSetId } from "../../hooks";
|
||||||
import { IndexedExpressionSet } from "../../model";
|
import { IndexedExpressionSet } from "../../model";
|
||||||
import { AppPath, AppRouting } from "../../model/routing";
|
import { AppPath, AppRouting } from "../../model/routing";
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ export function ExpressionSetLink({
|
|||||||
name,
|
name,
|
||||||
}: IndexedExpressionSet) {
|
}: IndexedExpressionSet) {
|
||||||
const { setRoute } = useContext(AppRouting);
|
const { setRoute } = useContext(AppRouting);
|
||||||
const expressions = useExpressionsInSet(id!) || [];
|
const expressions = useExpressionsByExpressionSetId(id!);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -24,7 +24,8 @@ export function ExpressionSetLink({
|
|||||||
<ExpressionSetCard
|
<ExpressionSetCard
|
||||||
name={name}
|
name={name}
|
||||||
description={description}
|
description={description}
|
||||||
expression_count={expressions.length}
|
expression_count={expressions?.length || 0}
|
||||||
|
expression_count_loading={expressions === undefined}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { useExpressionSets } from "../../hooks";
|
import { useAllExpressionSets } from "../../hooks";
|
||||||
import { ErrorView } from "../ErrorView";
|
import { ErrorView } from "../ErrorView";
|
||||||
import { ExpressionSetLink } from "./ExpressionSetLink";
|
import { ExpressionSetLink } from "./ExpressionSetLink";
|
||||||
|
|
||||||
export function ExpressionSetListView() {
|
export function ExpressionSetListView() {
|
||||||
const expression_sets = useExpressionSets();
|
const expression_sets = useAllExpressionSets();
|
||||||
|
|
||||||
if (!expression_sets) return null; // LOADING
|
if (!expression_sets) return null; // LOADING
|
||||||
if (!expression_sets.length) {
|
if (!expression_sets.length) {
|
||||||
return <ErrorView message="No expression sets found" />;
|
return <ErrorView message="No expression sets found" />;
|
||||||
|
Loading…
Reference in New Issue
Block a user