Merge pull request #1405 from rowyio/develop

Develop
This commit is contained in:
Shams
2023-09-07 19:36:24 -07:00
committed by GitHub
41 changed files with 1600 additions and 707 deletions

View File

@@ -10,6 +10,7 @@
"dependencies": {
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
"@json2csv/plainjs": "^7.0.1",
"@mdi/js": "^6.6.96",
"@monaco-editor/react": "^4.4.4",
@@ -40,7 +41,7 @@
"match-sorter": "^6.3.1",
"material-ui-popup-state": "^4.0.1",
"mdi-material-ui": "^7.3.0",
"monaco-editor-auto-typings": "^0.4.0",
"monaco-editor-auto-typings": "^0.4.3",
"notistack": "^2.0.4",
"path-browserify": "^1.0.1",
"pb-util": "^1.0.3",

View File

@@ -16,6 +16,7 @@ import {
BulkWriteFunction,
} from "@src/types/table";
import { updateRowData } from "@src/utils/table";
import { Table } from "@tanstack/react-table";
/** Root atom from which others are derived */
export const tableIdAtom = atom("");
@@ -47,6 +48,8 @@ export const tableColumnsOrderedAtom = atom<ColumnConfig[]>((get) => {
["desc", "asc"]
);
});
/** Store the table */
export const reactTableAtom = atom<Table<TableRow> | null>(null);
/** Reducer function to convert from array of columns to columns object */
export const tableColumnsReducer = (
a: Record<string, ColumnConfig>,
@@ -59,6 +62,8 @@ export const tableColumnsReducer = (
/** Filters applied to the local view */
export const tableFiltersAtom = atom<TableFilter[]>([]);
/** Join operator applied to mulitple filters */
export const tableFiltersJoinAtom = atom<"AND" | "OR">("AND");
/** Sorts applied to the local view */
export const tableSortsAtom = atom<TableSort[]>([]);

View File

@@ -41,7 +41,7 @@ export const columnMenuAtom = atom<{
* ```
*/
export const columnModalAtom = atomWithHash<{
type: "new" | "name" | "type" | "config";
type: "new" | "name" | "type" | "config" | "setColumnWidth";
columnKey?: string;
index?: number;
} | null>("columnModal", null, { replaceState: true });

View File

@@ -14,6 +14,7 @@ import FullScreenButton from "@src/components/FullScreenButton";
import { spreadSx } from "@src/utils/ui";
import githubLightTheme from "@src/components/CodeEditor/github-light-default.json";
import githubDarkTheme from "@src/components/CodeEditor/github-dark-default.json";
import { AutoTypings, LocalStorageCache } from "monaco-editor-auto-typings";
export interface ICodeEditorProps
extends Partial<EditorProps>,
@@ -47,7 +48,7 @@ export default function CodeEditor({
extraLibs,
diagnosticsOptions,
onUnmount,
defaultLanguage = "javascript",
defaultLanguage = "typescript",
...props
}: ICodeEditorProps) {
const theme = useTheme();
@@ -131,11 +132,22 @@ export default function CodeEditor({
});
});
}}
onMount={(editor) => {
{...props}
onMount={async (editor, monaco) => {
if (props.onMount) {
props.onMount(editor, monaco);
}
if (onFocus) editor.onDidFocusEditorWidget(onFocus);
if (onBlur) editor.onDidBlurEditorWidget(onBlur);
const autoTypings = await AutoTypings.create(editor, {
monaco: monaco,
sourceCache: new LocalStorageCache(),
debounceDuration: 500, // ms
onError: (e) => {
console.log("Auto typing error", e);
},
});
}}
{...props}
onValidate={onValidate_}
theme={`github-${theme.palette.mode}`}
options={{
@@ -149,6 +161,7 @@ export default function CodeEditor({
fixedOverflowWidgets: true,
tabSize: 2,
...props.options,
language: "typescript",
}}
/>

View File

@@ -1,5 +1,6 @@
import { useEffect } from "react";
import { useAtom } from "jotai";
import { matchSorter } from "match-sorter";
import {
tableScope,
@@ -64,26 +65,26 @@ export default function useMonacoCustomizations({
if (!monaco) return;
try {
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
moduleResolution:
monaco.languages.typescript.ModuleResolutionKind.NodeJs,
module: monaco.languages.typescript.ModuleKind.CommonJS,
target: monaco.languages.typescript.ScriptTarget.ES2020,
allowNonTsExtensions: true,
typeRoots: ["node_modules/@types"],
});
monaco.languages.typescript.javascriptDefaults.addExtraLib(firestoreDefs);
monaco.languages.typescript.javascriptDefaults.addExtraLib(
monaco.languages.typescript.typescriptDefaults.addExtraLib(firestoreDefs);
monaco.languages.typescript.typescriptDefaults.addExtraLib(
firebaseAuthDefs
);
monaco.languages.typescript.javascriptDefaults.addExtraLib(
monaco.languages.typescript.typescriptDefaults.addExtraLib(
firebaseStorageDefs
);
monaco.languages.typescript.javascriptDefaults.addExtraLib(
monaco.languages.typescript.typescriptDefaults.addExtraLib(
utilsDefs,
"ts:filename/utils.d.ts"
);
monaco.languages.typescript.javascriptDefaults.addExtraLib(rowyUtilsDefs);
setLoggingReplacementActions();
monaco.languages.typescript.typescriptDefaults.addExtraLib(rowyUtilsDefs);
} catch (error) {
console.error(
"An error occurred during initialization of Monaco: ",
@@ -97,7 +98,7 @@ export default function useMonacoCustomizations({
if (!monaco) return;
if (!extraLibs) return;
try {
monaco.languages.typescript.javascriptDefaults.addExtraLib(
monaco.languages.typescript.typescriptDefaults.addExtraLib(
extraLibs.join("\n"),
"ts:filename/extraLibs.d.ts"
);
@@ -112,7 +113,7 @@ export default function useMonacoCustomizations({
if (!monaco) return;
try {
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
...JSON.parse(stringifiedDiagnosticsOptions),
diagnosticCodesToIgnore: [
1323, // remove dynamic import error
@@ -124,13 +125,13 @@ export default function useMonacoCustomizations({
}
}, [monaco, stringifiedDiagnosticsOptions]);
const setLoggingReplacementActions = () => {
const setReplacementActions = () => {
if (!monaco) return;
const { dispose } = monaco.languages.registerCodeActionProvider(
"javascript",
{
provideCodeActions: (model, range, context, token) => {
const actions = context.markers
const consoleLogReplacements = context.markers
.filter((error) => {
return error.message.includes("Rowy Cloud Logging");
})
@@ -156,8 +157,63 @@ export default function useMonacoCustomizations({
isPreferred: true,
};
});
const secretNameReplacements = context.markers
.filter((error) => {
return error.message.includes(
"is not assignable to parameter of type 'SecretNames'"
);
})
.map((error) => {
const typoSecretName = model
.getLineContent(error.startLineNumber)
.slice(error.startColumn, error.endColumn - 2);
const similarSecretNames =
matchSorter(secretNames.secretNames ?? [], typoSecretName) ??
[];
const otherSecretNames =
secretNames.secretNames?.filter(
(secretName) => !similarSecretNames.includes(secretName)
) ?? [];
return [
...similarSecretNames.map((secretName) => ({
title: `Replace with "${secretName}"`,
diagnostics: [error],
kind: "quickfix",
edit: {
edits: [
{
resource: model.uri,
edit: {
range: error,
text: `"${secretName}"`,
},
},
],
},
isPreferred: true,
})),
...otherSecretNames.map((secretName) => ({
title: `Replace with "${secretName}"`,
diagnostics: [error],
kind: "quickfix",
edit: {
edits: [
{
resource: model.uri,
edit: {
range: error,
text: `"${secretName}"`,
},
},
],
},
isPreferred: false,
})),
];
})
.flat();
return {
actions: actions,
actions: [...consoleLogReplacements, ...secretNameReplacements],
dispose: () => {},
};
},
@@ -169,7 +225,6 @@ export default function useMonacoCustomizations({
dispose();
});
};
const addJsonFieldDefinition = async (
columnKey: string,
interfaceName: string
@@ -178,11 +233,11 @@ export default function useMonacoCustomizations({
.map((row) => row[columnKey])
.filter((entry) => entry !== undefined)
.map((entry) => JSON.stringify(entry));
monaco?.languages.typescript.javascriptDefaults.addExtraLib(
monaco?.languages.typescript.typescriptDefaults.addExtraLib(
`type ${interfaceName} = any;`
);
// if (!samples || samples.length === 0) {
// monaco?.languages.typescript.javascriptDefaults.addExtraLib(
// monaco?.languages.typescript.typescriptDefaults.addExtraLib(
// `type ${interfaceName} = any;`
// );
// return;
@@ -200,7 +255,7 @@ export default function useMonacoCustomizations({
// rendererOptions: { "just-types": "true" },
// });
// const newLib = result.lines.join("\n").replaceAll("export ", "");
// monaco?.languages.typescript.javascriptDefaults.addExtraLib(newLib);
// monaco?.languages.typescript.typescriptDefaults.addExtraLib(newLib);
//}
};
@@ -223,13 +278,13 @@ export default function useMonacoCustomizations({
.map((key) => `"${key}"`)
.join("|\n");
monaco?.languages.typescript.javascriptDefaults.addExtraLib(
monaco?.languages.typescript.typescriptDefaults.addExtraLib(
["/**", " * extensions type configuration", " */", extensionsDefs].join(
"\n"
),
"ts:filename/extensions.d.ts"
);
monaco?.languages.typescript.javascriptDefaults.addExtraLib(
monaco?.languages.typescript.typescriptDefaults.addExtraLib(
[
"// basic types that are used in all places",
"declare var require: any;",
@@ -261,14 +316,16 @@ export default function useMonacoCustomizations({
if (!secretNames.secretNames) return;
const secretsDef = `type SecretNames = ${secretNames.secretNames
.map((secret: string) => `"${secret}"`)
.join(" | ")}
.join(" | ")} \n
enum secrets {
${secretNames.secretNames
.map((secret: string) => `${secret} = "${secret}"`)
.map((secret: string) => `"${secret}" = "${secret}"`)
.join("\n")}
}
`;
monaco?.languages.typescript.javascriptDefaults.addExtraLib(secretsDef);
setReplacementActions();
}, [monaco, secretNames]);
let boxSx: SystemStyleObject<Theme> = {

View File

@@ -24,6 +24,7 @@ import {
} from "@src/assets/icons";
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
import StraightenIcon from "@mui/icons-material/Straighten";
import EditIcon from "@mui/icons-material/EditOutlined";
import SettingsIcon from "@mui/icons-material/SettingsOutlined";
import EvalIcon from "@mui/icons-material/PlayCircleOutline";
@@ -59,6 +60,7 @@ import { getFieldProp } from "@src/components/fields";
import { analytics, logEvent } from "@src/analytics";
import {
formatSubTableName,
generateId,
getTableBuildFunctionPathname,
getTableSchemaPath,
} from "@src/utils/table";
@@ -251,6 +253,7 @@ export default function ColumnMenu({
: column.type
)!.operators[0]?.value || "==",
value: "",
id: generateId(),
},
});
handleClose();
@@ -263,6 +266,16 @@ export default function ColumnMenu({
: column.type
),
},
{
key: "setColumnWidth",
label: "Set Column Width",
icon: <StraightenIcon />,
onClick: () => {
openColumnModal({ type: "setColumnWidth", columnKey: column.key });
handleClose();
},
disabled: column.resizable === false,
},
];
const configActions: IMenuContentsProps["menuItems"] = [

View File

@@ -5,6 +5,7 @@ import NewColumnModal from "./NewColumnModal";
import NameChangeModal from "./NameChangeModal";
import TypeChangeModal from "./TypeChangeModal";
import ColumnConfigModal from "./ColumnConfigModal";
import SetColumnWidthModal from "./SetColumnWidthModal";
import {
tableScope,
@@ -40,5 +41,8 @@ export default function ColumnModals() {
if (columnModal.type === "config")
return <ColumnConfigModal onClose={onClose} column={column} />;
if (columnModal.type === "setColumnWidth")
return <SetColumnWidthModal onClose={onClose} column={column} />;
return null;
}

View File

@@ -0,0 +1,70 @@
import { useEffect, useState } from "react";
import { IColumnModalProps } from ".";
import { reactTableAtom } from "@src/atoms/tableScope";
import { tableScope } from "@src/atoms/tableScope";
import { useAtom } from "jotai";
import { TextField } from "@mui/material";
import Modal from "@src/components/Modal";
export default function SetColumnWidthModal({
onClose,
column,
}: IColumnModalProps) {
const [reactTable] = useAtom(reactTableAtom, tableScope);
const [newWidth, setWidth] = useState<number>(0);
useEffect(() => {
// Set the initial width to the current column width once the table is fetched.
setWidth(reactTable?.getAllColumns()[column.index].getSize() || 0);
}, [reactTable, column]);
const handleUpdate = () => {
reactTable?.setColumnSizing((old) => {
const newSizing = { ...old };
// Set the new width for the column.
newSizing[column.fieldName] = newWidth;
return newSizing;
});
onClose();
};
return (
<Modal
onClose={onClose}
title="Set Column Width"
maxWidth="xs"
children={
<form
id="column-width-modal"
onSubmit={(e) => {
e.preventDefault();
handleUpdate();
}}
>
<TextField
value={newWidth}
autoFocus
variant="filled"
id="name"
label="Width"
type="number"
fullWidth
onChange={(e) => setWidth(Number(e.target.value))}
/>
</form>
}
actions={{
primary: {
children: "Update",
type: "submit",
form: "column-width-modal",
},
secondary: {
onClick: onClose,
children: "Cancel",
},
}}
/>
);
}

View File

@@ -39,6 +39,7 @@ import {
} from "@src/atoms/tableScope";
import { FieldType } from "@src/constants/fields";
import { TableRow } from "@src/types/table";
import { generateId } from "@src/utils/table";
interface IMenuContentsProps {
onClose: () => void;
@@ -281,6 +282,7 @@ export default function MenuContents({ onClose }: IMenuContentsProps) {
key: selectedColumn.fieldName,
operator: columnFilters!.operators[0]?.value || "==",
value: cellValue,
id: generateId(),
},
];

View File

@@ -3,6 +3,7 @@ import { useMemo, useRef, useState, useEffect, useCallback } from "react";
import { useAtom, useSetAtom } from "jotai";
import { useThrottledCallback } from "use-debounce";
import {
RowSelectionState,
createColumnHelper,
getCoreRowModel,
useReactTable,
@@ -25,6 +26,7 @@ import EmptyState from "@src/components/EmptyState";
import {
tableScope,
tableSchemaAtom,
reactTableAtom,
tableColumnsOrderedAtom,
tableRowsAtom,
tableNextPageAtom,
@@ -33,6 +35,7 @@ import {
selectedCellAtom,
tableSortsAtom,
tableIdAtom,
serverDocCountAtom,
} from "@src/atoms/tableScope";
import { projectScope, userSettingsAtom } from "@src/atoms/projectScope";
import { getFieldType, getFieldProp } from "@src/components/fields";
@@ -42,6 +45,7 @@ import { useSaveColumnSizing } from "./useSaveColumnSizing";
import useHotKeys from "./useHotKey";
import type { TableRow, ColumnConfig } from "@src/types/table";
import useStateWithRef from "./useStateWithRef"; // testing with useStateWithRef
import { Checkbox, FormControlLabel } from "@mui/material";
export const DEFAULT_ROW_HEIGHT = 41;
export const DEFAULT_COL_WIDTH = 150;
@@ -75,6 +79,20 @@ export interface ITableProps {
* Loading state handled by Suspense in parent component.
*/
emptyState?: React.ReactNode;
/**
* If defined, it will show a checkbox to select rows. The
* state is to be maintained by the parent component.
*
* Usage:
*
* const [selectedRows, setSelectedRows] = useState<RowSelectionState>({});
* const selectedRowsProp = useMemo(() => ({state: selectedRows, setState: setSelectedRows}), [selectedRows, setSelectedRows])
* <Table selectedRows={selectedRowsProp} />
*/
selectedRows?: {
state: RowSelectionState;
setState: React.Dispatch<React.SetStateAction<{}>>;
};
}
/**
@@ -93,12 +111,15 @@ export default function Table({
canEditCells,
hiddenColumns,
emptyState,
selectedRows,
}: ITableProps) {
const [tableSchema] = useAtom(tableSchemaAtom, tableScope);
const [serverDocCount] = useAtom(serverDocCountAtom, tableScope);
const [tableColumnsOrdered] = useAtom(tableColumnsOrderedAtom, tableScope);
const [tableRows] = useAtom(tableRowsAtom, tableScope);
const [tableNextPage] = useAtom(tableNextPageAtom, tableScope);
const [tablePage, setTablePage] = useAtom(tablePageAtom, tableScope);
const setReactTable = useSetAtom(reactTableAtom, tableScope);
const updateColumn = useSetAtom(updateColumnAtom, tableScope);
@@ -143,7 +164,57 @@ export default function Table({
}
return _columns;
}, [tableColumnsOrdered, canAddColumns, canEditCells]);
}, [tableColumnsOrdered, canAddColumns, canEditCells, selectedRows]);
columns.unshift(
...useMemo(() => {
if (!selectedRows) return [];
return [
columnHelper.display({
id: "_rowy_select",
size: 41.8, // TODO: We shouldn't have to change this often
header: ({ table }) => {
const checked =
Object.keys(selectedRows.state).length >= serverDocCount!;
const indeterminate = Object.keys(selectedRows.state).length > 0;
return (
<FormControlLabel
sx={{ margin: 0 }}
label=""
control={
<Checkbox
checked={checked}
indeterminate={indeterminate && !checked}
onChange={() => {
table.toggleAllRowsSelected(
!table.getIsAllRowsSelected()
);
}}
/>
}
/>
);
},
cell: ({ row }) => {
return (
<FormControlLabel
label=""
sx={{ margin: 0 }}
control={
<Checkbox
checked={row.getIsSelected()}
disabled={!row.getCanSelect()}
onChange={row.getToggleSelectedHandler()}
/>
}
/>
);
},
}),
];
}, [selectedRows])
);
// Get users hidden columns from props and memoize into a `VisibilityState`
const columnVisibility: VisibilityState = useMemo(() => {
@@ -151,14 +222,16 @@ export default function Table({
return hiddenColumns.reduce((a, c) => ({ ...a, [c]: false }), {});
}, [hiddenColumns]);
// Get frozen columns and memoize into a `ColumnPinningState`
const columnPinning: ColumnPinningState = useMemo(
() => ({
left: columns
.filter(
(c) => c.meta?.fixed && c.id && columnVisibility[c.id] !== false
)
.map((c) => c.id!),
left: [
...(selectedRows ? ["_rowy_select"] : []),
...columns
.filter(
(c) => c.meta?.fixed && c.id && columnVisibility[c.id] !== false
)
.map((c) => c.id!),
],
}),
[columns, columnVisibility]
);
@@ -172,6 +245,14 @@ export default function Table({
getCoreRowModel: getCoreRowModel(),
getRowId,
columnResizeMode: "onChange",
...(selectedRows && {
enableRowSelection: true,
enableMultiRowSelection: true,
state: {
rowSelection: selectedRows.state,
},
onRowSelectionChange: selectedRows.setState,
}),
});
// Store local `columnSizing` state so we can save it to table schema
@@ -185,6 +266,10 @@ export default function Table({
state: { ...prev.state, columnVisibility, columnPinning, columnSizing },
onColumnSizingChange: setColumnSizing,
}));
// Update the reactTable atom when table state changes.
useMemo(() => {
setReactTable(table);
}, [table, setReactTable]);
// Get rows and columns for virtualization
const { rows } = table.getRowModel();
const leafColumns = table.getVisibleLeafColumns();
@@ -213,11 +298,13 @@ export default function Table({
updateColumn({
key: result.draggableId,
index: result.destination.index,
index: selectedRows
? result.destination.index - 1
: result.destination.index,
config: {},
});
},
[updateColumn]
[updateColumn, selectedRows]
);
const fetchMoreOnBottomReached = useThrottledCallback(
@@ -235,12 +322,7 @@ export default function Table({
// for large screen heights
useEffect(() => {
fetchMoreOnBottomReached(containerRef.current);
}, [
fetchMoreOnBottomReached,
tablePage,
tableNextPage.loading,
containerRef,
]);
}, [fetchMoreOnBottomReached, tableNextPage.loading, containerRef]);
// apply user default sort on first render
const [applySort, setApplySort] = useState(true);

View File

@@ -1,6 +1,11 @@
import { memo } from "react";
import { useAtom } from "jotai";
import type { Column, Row, ColumnSizingState } from "@tanstack/react-table";
import {
Column,
Row,
ColumnSizingState,
flexRender,
} from "@tanstack/react-table";
import StyledRow from "./Styled/StyledRow";
import OutOfOrderIndicator from "./OutOfOrderIndicator";
@@ -18,6 +23,7 @@ import { getFieldProp } from "@src/components/fields";
import type { TableRow } from "@src/types/table";
import useVirtualization from "./useVirtualization";
import { DEFAULT_ROW_HEIGHT, OUT_OF_ORDER_MARGIN } from "./Table";
import StyledCell from "./Styled/StyledCell";
export interface ITableBodyProps {
/**
@@ -114,6 +120,14 @@ export const TableBody = memo(function TableBody({
const isReadOnlyCell =
fieldTypeGroup === "Auditing" || fieldTypeGroup === "Metadata";
if (cell.id.includes("_rowy_select")) {
return (
<StyledCell key={cell.id} role="gridcell">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</StyledCell>
);
}
return (
<TableCell
key={cell.id}

View File

@@ -2,7 +2,11 @@ import { memo, Fragment } from "react";
import { useAtom } from "jotai";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import type { DropResult } from "react-beautiful-dnd";
import type { ColumnSizingState, HeaderGroup } from "@tanstack/react-table";
import {
ColumnSizingState,
HeaderGroup,
flexRender,
} from "@tanstack/react-table";
import type { TableRow } from "@src/types/table";
import StyledRow from "./Styled/StyledRow";
@@ -11,6 +15,7 @@ import FinalColumnHeader from "./FinalColumn/FinalColumnHeader";
import { tableScope, selectedCellAtom } from "@src/atoms/tableScope";
import { DEFAULT_ROW_HEIGHT } from "@src/components/Table";
import StyledColumnHeader from "./Styled/StyledColumnHeader";
export interface ITableHeaderProps {
/** Headers with context from TanStack Table state */
@@ -69,6 +74,20 @@ export const TableHeader = memo(function TableHeader({
const isLastHeader = i === headerGroup.headers.length - 1;
if (header.id === "_rowy_select")
return (
<StyledColumnHeader
key={header.id}
role="columnheader"
style={{ padding: 0 }}
>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</StyledColumnHeader>
);
// Render later, after the drag & drop placeholder
if (header.id === "_rowy_column_actions")
return (

View File

@@ -61,6 +61,7 @@ export const SUPPORTED_TYPES_COPY = new Set([
FieldType.updatedAt,
// CONNECTION
FieldType.reference,
FieldType.id,
]);
export const SUPPORTED_TYPES_PASTE = new Set([
@@ -98,7 +99,16 @@ export function useMenuAction(
const handleCopy = useCallback(async () => {
try {
if (cellValue !== undefined && cellValue !== null && cellValue !== "") {
if (selectedCol?.type === FieldType.id && selectedCell?.path) {
await navigator.clipboard.writeText(
selectedCell?.path.split("/").pop() || ""
);
enqueueSnackbar("Copied");
} else if (
cellValue !== undefined &&
cellValue !== null &&
cellValue !== ""
) {
const value = getValue(cellValue);
await navigator.clipboard.writeText(value);
enqueueSnackbar("Copied");

View File

@@ -71,7 +71,8 @@ export function useVirtualization(
const definedWidth = localWidth || schemaWidth;
if (definedWidth === undefined) return DEFAULT_COL_WIDTH;
if (definedWidth < MIN_COL_WIDTH) return MIN_COL_WIDTH;
if (definedWidth < MIN_COL_WIDTH && columnDef.id !== "_rowy_select")
return MIN_COL_WIDTH;
return definedWidth;
},
[leafColumns, columnSizing]

View File

@@ -150,6 +150,7 @@ export default function BuildLogsSnack({
timeRange: { type: "days", value: 7 },
buildLogExpanded: 0,
});
setExpanded(false);
}}
style={{ color: "white" }}
>

View File

@@ -10,6 +10,7 @@ import {
Typography,
TextField,
InputLabel,
IconButton,
} from "@mui/material";
import ColumnSelect from "@src/components/Table/ColumnSelect";
@@ -17,11 +18,28 @@ import FieldSkeleton from "@src/components/SideDrawer/FieldSkeleton";
import IdFilterInput from "./IdFilterInput";
import { InlineErrorFallback } from "@src/components/ErrorFallback";
import type { useFilterInputs } from "./useFilterInputs";
import { getFieldType, getFieldProp } from "@src/components/fields";
import type { IFieldConfig } from "@src/components/fields/types";
export interface IFilterInputsProps extends ReturnType<typeof useFilterInputs> {
import { TableFilter } from "@src/types/table";
import DeleteIcon from "@mui/icons-material/Delete";
import DragIndicatorOutlinedIcon from "@mui/icons-material/DragIndicatorOutlined";
import { useFilterInputs } from "./useFilterInputs";
export interface IFilterInputsProps {
filterColumns: ReturnType<typeof useFilterInputs>["filterColumns"];
selectedColumn: ReturnType<typeof useFilterInputs>["filterColumns"][0];
availableFilters: IFieldConfig["filter"];
disabled?: boolean;
query: TableFilter;
setQuery: (query: TableFilter) => void;
handleDelete: () => void;
index: number;
noOfQueries: number;
handleChangeColumn: (column: string) => void;
joinOperator: "AND" | "OR";
setJoinOperator: (operator: "AND" | "OR") => void;
}
export default function FilterInputs({
@@ -32,6 +50,11 @@ export default function FilterInputs({
query,
setQuery,
disabled,
joinOperator,
setJoinOperator,
handleDelete,
index,
noOfQueries,
}: IFilterInputsProps) {
const columnType = selectedColumn ? getFieldType(selectedColumn) : null;
@@ -76,18 +99,18 @@ export default function FilterInputs({
return (
<Grid container spacing={2} sx={{ mb: 3 }}>
<Grid item xs={4}>
<Grid item xs={3.5}>
<ColumnSelect
multiple={false}
label="Column"
options={filterColumns}
value={query.key}
onChange={handleChangeColumn}
onChange={(newKey: string | null) => handleChangeColumn(newKey ?? "")}
disabled={disabled}
/>
</Grid>
<Grid item xs={4}>
<Grid item xs={3.5}>
<TextField
label="Operator"
select
@@ -98,13 +121,17 @@ export default function FilterInputs({
disabled || !query.key || availableFilters?.operators?.length === 0
}
onChange={(e) => {
setQuery((query) => ({
const newQuery = {
...query,
operator: e.target.value as string,
}));
operator: e.target.value as TableFilter["operator"],
};
setQuery(newQuery);
}}
SelectProps={{ displayEmpty: true }}
sx={{ "& .MuiSelect-select": { display: "flex" } }}
sx={{
"& .MuiSelect-select": { display: "flex" },
}}
>
<MenuItem disabled value="" style={{ display: "none" }}>
Select operator
@@ -113,39 +140,107 @@ export default function FilterInputs({
</TextField>
</Grid>
<Grid item xs={4} key={query.key + query.operator}>
{query.key && query.operator && (
<ErrorBoundary FallbackComponent={InlineErrorFallback}>
<InputLabel
variant="filled"
id={`filters-label-${query.key}`}
htmlFor={`sidedrawer-field-${query.key}`}
>
Value
</InputLabel>
<Grid item xs={3.5} key={query.key + query.operator}>
{query.key &&
query.operator &&
query.operator !== "is-empty" &&
query.operator != "is-not-empty" && (
<ErrorBoundary FallbackComponent={InlineErrorFallback}>
<InputLabel
variant="filled"
id={`filters-label-${query.key}`}
htmlFor={`sidedrawer-field-${query.key}`}
>
Value
</InputLabel>
<Suspense fallback={<FieldSkeleton />}>
{columnType &&
createElement(
query.key === "_rowy_ref.id"
? IdFilterInput
: getFieldProp("filter.customInput" as any, columnType) ||
getFieldProp("SideDrawerField", columnType),
{
column: selectedColumn,
_rowy_ref: {},
value: query.value,
onChange: (value: any) => {
setQuery((query) => ({ ...query, value }));
},
disabled,
operator: query.operator,
}
)}
</Suspense>
</ErrorBoundary>
)}
<Suspense fallback={<FieldSkeleton />}>
{columnType &&
createElement(
query.key === "_rowy_ref.id"
? IdFilterInput
: getFieldProp("filter.customInput" as any, columnType) ||
getFieldProp("SideDrawerField", columnType),
{
column: selectedColumn,
_rowy_ref: {},
value: query.value,
onChange: (value: any) => {
const newQuery = {
...query,
value,
};
setQuery(newQuery);
},
disabled,
operator: query.operator,
}
)}
</Suspense>
</ErrorBoundary>
)}
</Grid>
<Grid
item
xs={1.5}
sx={{
display: "flex",
alignItems: "flex-end",
paddingBottom: "5px",
justifyContent: "space-between",
}}
>
<IconButton
aria-label="Remove"
sx={{ padding: 0 }}
onClick={handleDelete}
>
{<DeleteIcon />}
</IconButton>
<DragIndicatorOutlinedIcon
color="disabled"
sx={[
{
marginRight: "6px",
},
]}
/>
</Grid>
{noOfQueries > 1 &&
index !== noOfQueries - 1 &&
(index === 0 ? (
<Grid item xs={12}>
<Grid container>
<Grid item xs={3.5}>
<TextField
select
variant="filled"
fullWidth
value={joinOperator}
onChange={(e) =>
setJoinOperator(e.target.value === "AND" ? "AND" : "OR")
}
sx={{
"& .MuiSelect-select": {
display: "flex",
},
}}
>
<MenuItem value="AND">And</MenuItem>
<MenuItem value="OR">Or</MenuItem>
</TextField>
</Grid>
</Grid>
</Grid>
) : (
<Grid item xs={12}>
<Typography paddingLeft={1}>
{joinOperator === "AND" ? "And" : "Or"}
</Typography>
</Grid>
))}
</Grid>
);
}

View File

@@ -0,0 +1,128 @@
import FilterInputs from "./FilterInputs";
import { Button } from "@mui/material";
import type { useFilterInputs } from "./useFilterInputs";
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
import AddIcon from "@mui/icons-material/Add";
import { find } from "lodash-es";
import { TableFilter } from "@src/types/table";
import { generateId } from "@src/utils/table";
export interface IFilterInputsCollectionProps
extends ReturnType<typeof useFilterInputs> {
disabled?: boolean;
}
export default function FilterInputsCollection({
filterColumns,
selectedColumns,
handleColumnChange,
availableFiltersForEachSelectedColumn,
queries,
setQueries,
disabled,
joinOperator,
setJoinOperator,
}: IFilterInputsCollectionProps) {
const onDragEnd = (result: any) => {
if (!result.destination) return;
setQueries((prevQueries) => {
const newQueries = [...prevQueries];
const [reorderedItem] = newQueries.splice(result.source.index, 1);
newQueries.splice(result.destination.index, 0, reorderedItem);
return newQueries;
});
};
return (
<>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="items">
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{queries.map((query, index) => {
return (
<Draggable
key={query.id}
draggableId={query.id.toString()}
index={index}
>
{(provided) => (
<div
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
<FilterInputs
filterColumns={filterColumns}
selectedColumn={selectedColumns[index]}
handleChangeColumn={(key: string) => {
handleColumnChange(query.id, key);
}}
availableFilters={
availableFiltersForEachSelectedColumn[index]
}
query={query}
setQuery={(newQuery: TableFilter) => {
setQueries((prevQueries) => {
const newQueries = [...prevQueries];
newQueries[index] = newQuery;
return newQueries;
});
}}
disabled={disabled}
joinOperator={joinOperator}
setJoinOperator={setJoinOperator}
handleDelete={() => {
setQueries((prevQueries) => {
const newQueries = [...prevQueries];
newQueries.splice(index, 1);
return newQueries;
});
}}
index={index}
noOfQueries={queries.length}
/>
</div>
)}
</Draggable>
);
})}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
<Button
variant="outlined"
color="primary"
onClick={() => {
const column = find(filterColumns, (column) => {
return !find(selectedColumns, { key: column.key });
});
const id = generateId();
setQueries((prevQueries) => [
...prevQueries,
{
key: "",
operator: "is-not-empty",
value: "",
id,
},
]);
handleColumnChange(id, column?.key ?? filterColumns[0].key);
}}
startIcon={<AddIcon />}
>
Add Filter
</Button>
</>
);
}

View File

@@ -1,10 +1,7 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { useState, useEffect } from "react";
import { useAtom } from "jotai";
import { useAtom, useSetAtom } from "jotai";
import useMemoValue from "use-memo-value";
import { isEmpty, isDate } from "lodash-es";
import { useSearchParams } from "react-router-dom";
import { useSnackbar } from "notistack";
import {
Tab,
@@ -21,8 +18,7 @@ import TabList from "@mui/lab/TabList";
import TabPanel from "@mui/lab/TabPanel";
import FiltersPopover from "./FiltersPopover";
import FilterInputs from "./FilterInputs";
import { changePageUrl, separateOperands } from "./utils";
import FilterInputsCollection from "./FilterInputsCollection";
import {
projectScope,
@@ -39,16 +35,31 @@ import {
tableSortsAtom,
updateTableSchemaAtom,
tableFiltersPopoverAtom,
tableFiltersJoinAtom,
} from "@src/atoms/tableScope";
import { useFilterInputs, INITIAL_QUERY } from "./useFilterInputs";
import { useFilterInputs } from "./useFilterInputs";
import { analytics, logEvent } from "@src/analytics";
import type { TableFilter } from "@src/types/table";
import { generateId } from "@src/utils/table";
import { useFilterUrl } from "./useFilterUrl";
const shouldDisableApplyButton = (value: any) =>
isEmpty(value) &&
!isDate(value) &&
typeof value !== "boolean" &&
typeof value !== "number";
const shouldDisableApplyButton = (queries: any) => {
for (let query of queries) {
if (query.operator === "is-empty" || query.operator === "is-not-empty") {
continue;
}
if (
isEmpty(query.value) &&
!isDate(query.value) &&
typeof query.value !== "boolean" &&
typeof query.value !== "number"
)
return true;
}
return false;
};
enum FilterType {
yourFilter = "local_filter",
@@ -66,17 +77,16 @@ export default function Filters() {
const [, setTableSorts] = useAtom(tableSortsAtom, tableScope);
const [updateTableSchema] = useAtom(updateTableSchemaAtom, tableScope);
const [{ defaultQuery }] = useAtom(tableFiltersPopoverAtom, tableScope);
const tableFilterInputs = useFilterInputs(tableColumnsOrdered);
const setTableQuery = tableFilterInputs.setQuery;
const setTableQueries = tableFilterInputs.setQueries;
const userFilterInputs = useFilterInputs(tableColumnsOrdered, defaultQuery);
const setUserQuery = userFilterInputs.setQuery;
const { availableFilters, filterColumns } = userFilterInputs;
const [searchParams] = useSearchParams();
const { enqueueSnackbar } = useSnackbar();
useEffect(() => {
let isFiltered = searchParams.get("filter");
if (isFiltered) updateUserFilter(isFiltered);
}, [searchParams]);
const setUserQueries = userFilterInputs.setQueries;
const { availableFiltersForEachSelectedColumn } = userFilterInputs;
const availableFiltersForFirstColumn =
availableFiltersForEachSelectedColumn[0];
const setTableFiltersJoin = useSetAtom(tableFiltersJoinAtom, tableScope);
// Get table filters & user filters from config documents
const tableFilters = useMemoValue(
@@ -91,58 +101,30 @@ export default function Filters() {
const hasTableFilters =
Array.isArray(tableFilters) && tableFilters.length > 0;
const hasUserFilters = Array.isArray(userFilters) && userFilters.length > 0;
function updateUserFilter(str: string) {
let { operators, operands = [] } = separateOperands(str);
if (!operators.length) return;
if (operators.length) {
let appliedFilter: TableFilter[] = [];
appliedFilter = [
{
key: operands[0],
operator: operators[0],
value: Number(operands[1]),
},
];
let isValidFilter = checkFilterValidation(appliedFilter[0]);
if (isValidFilter) {
setOverrideTableFilters(true);
setUserFilters(appliedFilter);
} else {
enqueueSnackbar("Oops, Invalid filter!!!", { variant: "error" });
setUserFilters([]);
setOverrideTableFilters(false);
userFilterInputs.resetQuery();
}
}
}
function checkFilterValidation(filter: TableFilter): boolean {
let isFilterableColumn = filterColumns?.filter(
(item) =>
item.key === filter.key ||
item.label === filter.key ||
item.type === filter.key
);
if (!isFilterableColumn?.length) return false;
filter.key = isFilterableColumn?.[0]?.value;
filter.operator = filter.operator === "-is-" ? "id-equal" : filter.operator;
filter.value =
filter.operator === "id-equal" ? filter.value.toString() : filter.value;
return true;
}
// Set the local table filter
useEffect(() => {
// Set local state for UI
setTableQuery(
Array.isArray(tableFilters) && tableFilters[0]
? tableFilters[0]
: INITIAL_QUERY
);
setUserQuery(
Array.isArray(userFilters) && userFilters[0]
? userFilters[0]
: INITIAL_QUERY
);
if (
Array.isArray(tableFilters) &&
tableFilters &&
tableFilters.length > 0
) {
// Older filters do not have ID. Migrating them here.
for (const filter of tableFilters) {
if (!filter.id) filter.id = generateId();
}
setTableQueries(tableFilters);
}
if (Array.isArray(userFilters) && userFilters && userFilters.length > 0) {
// Older filters do not have ID. Migrating them here.
for (const filter of userFilters) {
if (!filter.id) filter.id = generateId();
}
setUserQueries(userFilters);
}
setCanOverrideCheckbox(tableFiltersOverridable);
let filtersToApply: TableFilter[] = [];
@@ -156,7 +138,7 @@ export default function Filters() {
} else if (hasUserFilters) {
filtersToApply = userFilters;
}
updatePageURL(filtersToApply);
setLocalFilters(filtersToApply);
// Reset order so we dont have to make a new index
if (filtersToApply.length) {
@@ -167,9 +149,10 @@ export default function Filters() {
hasUserFilters,
setLocalFilters,
setTableSorts,
setTableQueries,
tableFilters,
tableFiltersOverridable,
setUserQuery,
setUserQueries,
userFilters,
userRoles,
]);
@@ -197,50 +180,104 @@ export default function Filters() {
// When defaultQuery (from atom) is updated, update the UI
useEffect(() => {
if (defaultQuery) {
setUserQuery(defaultQuery);
setUserQueries([defaultQuery]);
setTab("user");
}
}, [setUserQuery, defaultQuery]);
}, [setUserQueries, defaultQuery]);
const [overrideTableFilters, setOverrideTableFilters] = useState(
tableFiltersOverridden
);
useEffect(() => {
if (userSettings.tables?.[tableId]?.joinOperator) {
userFilterInputs.setJoinOperator(
userSettings.tables?.[tableId]?.joinOperator === "AND" ? "AND" : "OR"
);
}
if (tableSchema.joinOperator) {
tableFilterInputs.setJoinOperator(
tableSchema.joinOperator === "AND" ? "AND" : "OR"
);
}
}, [userSettings.tables?.[tableId]?.joinOperator, tableSchema.joinOperator]);
useEffect(() => {
if (tableFiltersOverridable && (hasUserFilters || userFilters === null)) {
setTableFiltersJoin(
userSettings.tables?.[tableId]?.joinOperator === "AND" ? "AND" : "OR"
);
} else if (hasTableFilters) {
setTableFiltersJoin(tableSchema.joinOperator === "AND" ? "AND" : "OR");
} else if (hasUserFilters) {
setTableFiltersJoin(
userSettings.tables?.[tableId]?.joinOperator === "AND" ? "AND" : "OR"
);
}
}, [
tableFiltersOverridable,
hasUserFilters,
hasTableFilters,
userFilters,
tableSchema.joinOperator,
userSettings.tables?.[tableId]?.joinOperator,
]);
// Save table filters to table schema document
const setTableFilters = (filters: TableFilter[]) => {
const setTableFilters = (
filters: TableFilter[],
op: "AND" | "OR" = "AND"
) => {
logEvent(analytics, FilterType.tableFilter);
if (updateTableSchema)
updateTableSchema({ filters, filtersOverridable: canOverrideCheckbox });
updateTableSchema({
filters,
filtersOverridable: canOverrideCheckbox,
joinOperator: op,
});
};
// Save user filters to user document
// null overrides table filters
const setUserFilters = (filters: TableFilter[] | null) => {
const setUserFilters = (
filters: TableFilter[] | null,
op: "AND" | "OR" = "AND"
) => {
logEvent(analytics, FilterType.yourFilter);
if (updateUserSettings && filters)
updateUserSettings({ tables: { [`${tableId}`]: { filters } } });
updateUserSettings({
tables: { [`${tableId}`]: { filters, joinOperator: op } },
});
};
function updatePageURL(filters: TableFilter[]) {
if (!filters.length) {
changePageUrl();
} else {
const [filter] = filters;
const fieldName = filter.key === "_rowy_ref.id" ? "ID" : filter.key;
const operator =
filter.operator === "id-equal" ? "-is-" : filter.operator;
const formattedValue = availableFilters?.valueFormatter
? availableFilters.valueFormatter(filter.value, filter.operator)
: filter.value.toString();
const queryParams = `?filter=${fieldName}${operator}${formattedValue}`;
changePageUrl(queryParams);
const { filtersUrl, updateFilterQueryParam } = useFilterUrl();
// If the filter in URL is not the same as currently applied local filter
// then update the user filter.
useEffect(() => {
if (
filtersUrl &&
JSON.stringify(filtersUrl) !== JSON.stringify(appliedFilters)
) {
setUserFilters(filtersUrl);
setOverrideTableFilters(true);
}
}
}, [filtersUrl]);
// Update queyy param if the locally applied filter changes
useEffect(() => {
if (appliedFilters) {
updateFilterQueryParam(appliedFilters);
}
}, [appliedFilters]);
return (
<FiltersPopover
appliedFilters={appliedFilters}
hasAppliedFilters={hasAppliedFilters}
hasTableFilters={hasTableFilters}
tableFiltersOverridden={tableFiltersOverridden}
availableFilters={availableFilters}
availableFilters={availableFiltersForFirstColumn}
setUserFilters={setUserFilters}
>
{({ handleClose }) => {
@@ -305,7 +342,7 @@ export default function Filters() {
<Divider style={{ marginTop: -1 }} />
<TabPanel value="user" className="content">
<FilterInputs {...userFilterInputs} />
<FilterInputsCollection {...userFilterInputs} />
{hasTableFilters && (
<FormControlLabel
@@ -330,31 +367,29 @@ export default function Filters() {
>
<Button
disabled={
!overrideTableFilters &&
!tableFiltersOverridden &&
userFilterInputs.query.key === ""
(!overrideTableFilters && hasTableFilters) ||
userFilterInputs.queries.length === 0
}
onClick={() => {
setUserFilters(overrideTableFilters ? null : []);
setUserFilters([]);
userFilterInputs.resetQuery();
}}
>
Clear
{hasTableFilters &&
(overrideTableFilters
? " (ignore table filter)"
: " (use table filter)")}
Clear All
</Button>
<Button
disabled={
(!overrideTableFilters && hasTableFilters) ||
shouldDisableApplyButton(userFilterInputs.query.value)
shouldDisableApplyButton(userFilterInputs.queries)
}
color="primary"
variant="contained"
onClick={() => {
setUserFilters([userFilterInputs.query as TableFilter]);
setUserFilters(
userFilterInputs.queries as TableFilter[],
userFilterInputs.joinOperator
);
handleClose();
}}
>
@@ -364,7 +399,7 @@ export default function Filters() {
</TabPanel>
<TabPanel value="table" className="content">
<FilterInputs {...tableFilterInputs} />
<FilterInputsCollection {...tableFilterInputs} />
<FormControlLabel
control={
@@ -402,23 +437,26 @@ export default function Filters() {
spacing={1}
>
<Button
disabled={tableFilterInputs.query.key === ""}
disabled={tableFilterInputs.queries.length === 0}
onClick={() => {
setTableFilters([]);
tableFilterInputs.resetQuery();
}}
>
Clear
Clear All
</Button>
<Button
disabled={shouldDisableApplyButton(
tableFilterInputs.query.value
tableFilterInputs.queries
)}
color="primary"
variant="contained"
onClick={() => {
setTableFilters([tableFilterInputs.query as TableFilter]);
setTableFilters(
tableFilterInputs.queries as TableFilter[],
tableFilterInputs.joinOperator
);
handleClose();
}}
>
@@ -434,7 +472,7 @@ export default function Filters() {
if (hasTableFilters && !tableFiltersOverridable) {
return (
<div className="content">
<FilterInputs {...tableFilterInputs} disabled />
<FilterInputsCollection {...tableFilterInputs} disabled />
<Alert severity="info" style={{ width: "auto" }}>
An ADMIN user has set the filter for this table
@@ -447,7 +485,7 @@ export default function Filters() {
if (hasTableFilters && tableFiltersOverridable) {
return (
<div className="content">
<FilterInputs {...userFilterInputs} />
<FilterInputsCollection {...userFilterInputs} />
<FormControlLabel
control={
@@ -470,28 +508,28 @@ export default function Filters() {
disabled={
!overrideTableFilters &&
!tableFiltersOverridden &&
userFilterInputs.query.key === ""
userFilterInputs.queries.length === 0
}
onClick={() => {
setUserFilters(overrideTableFilters ? null : []);
setUserFilters([]);
userFilterInputs.resetQuery();
}}
>
Clear
{overrideTableFilters
? " (ignore table filter)"
: " (use table filter)"}
Clear All
</Button>
<Button
disabled={
(!overrideTableFilters && hasTableFilters) ||
shouldDisableApplyButton(userFilterInputs.query.value)
shouldDisableApplyButton(userFilterInputs.queries)
}
color="primary"
variant="contained"
onClick={() => {
setUserFilters([userFilterInputs.query as TableFilter]);
setUserFilters(
userFilterInputs.queries as TableFilter[],
userFilterInputs.joinOperator
);
handleClose();
}}
>
@@ -505,7 +543,7 @@ export default function Filters() {
// Non-ADMIN, no table filters
return (
<div className="content">
<FilterInputs {...userFilterInputs} />
<FilterInputsCollection {...userFilterInputs} />
<Stack
direction="row"
@@ -514,23 +552,24 @@ export default function Filters() {
spacing={1}
>
<Button
disabled={userFilterInputs.query.key === ""}
disabled={userFilterInputs.queries.length === 0}
onClick={() => {
setUserFilters([]);
userFilterInputs.resetQuery();
}}
>
Clear
Clear All
</Button>
<Button
disabled={shouldDisableApplyButton(
userFilterInputs.query.value
)}
disabled={shouldDisableApplyButton(userFilterInputs.queries)}
color="primary"
variant="contained"
onClick={() => {
setUserFilters([userFilterInputs.query as TableFilter]);
setUserFilters(
userFilterInputs.queries as TableFilter[],
userFilterInputs.joinOperator
);
handleClose();
}}
>

View File

@@ -15,7 +15,9 @@ export interface IFiltersPopoverProps {
hasAppliedFilters: boolean;
hasTableFilters: boolean;
tableFiltersOverridden: boolean;
availableFilters: ReturnType<typeof useFilterInputs>["availableFilters"];
availableFilters: ReturnType<
typeof useFilterInputs
>["availableFiltersForEachSelectedColumn"][0];
setUserFilters: (filters: TableFilter[]) => void;
children: (props: { handleClose: () => void }) => React.ReactNode;
@@ -50,7 +52,7 @@ export default function FiltersPopover({
startIcon={<FilterIcon />}
active={hasAppliedFilters}
style={
hasAppliedFilters
appliedFilters.length === 1
? {
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
@@ -61,60 +63,61 @@ export default function FiltersPopover({
}
aria-describedby={popoverId}
>
{hasAppliedFilters ? "Filtered" : "Filter"}
{hasAppliedFilters ? `Filtered: ${appliedFilters.length}` : "Filter"}
</ButtonWithStatus>
{appliedFilters.map((filter) => {
const fieldName = filter.key === "_rowy_ref.id" ? "ID" : filter.key;
const operator = (availableFilters?.operators ?? []).find(
(f) => f.value === filter.operator
);
const operatorLabel = (operator?.label ?? filter.operator).replace(
"id-equal",
"is"
);
{appliedFilters.length === 1 &&
appliedFilters.map((filter) => {
const fieldName = filter.key === "_rowy_ref.id" ? "ID" : filter.key;
const operator = (availableFilters?.operators ?? []).find(
(f) => f.value === filter.operator
);
const operatorLabel = (operator?.label ?? filter.operator).replace(
"id-equal",
"is"
);
const formattedValue = availableFilters?.valueFormatter
? availableFilters.valueFormatter(filter.value, filter.operator)
: filter.value.toString();
const formattedValue = availableFilters?.valueFormatter
? availableFilters.valueFormatter(filter.value, filter.operator)
: filter.value.toString();
return (
<Chip
key={filter.key}
label={
<Typography variant="inherit" component="span">
{fieldName}{" "}
<Typography
variant="inherit"
display="inline"
color="text.secondary"
fontWeight="normal"
>
{operatorLabel}
</Typography>{" "}
{formattedValue}
</Typography>
}
onDelete={
hasTableFilters && !tableFiltersOverridden
? undefined
: () => setUserFilters([])
}
sx={{
borderRadius: 1,
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
borderLeft: "none",
return (
<Chip
key={filter.key}
label={
<Typography variant="inherit" component="span">
{fieldName}{" "}
<Typography
variant="inherit"
display="inline"
color="text.secondary"
fontWeight="normal"
>
{operatorLabel}
</Typography>{" "}
{formattedValue}
</Typography>
}
onDelete={
hasTableFilters && !tableFiltersOverridden
? undefined
: () => setUserFilters([])
}
sx={{
borderRadius: 1,
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
borderLeft: "none",
backgroundColor: "background.paper",
height: 32,
backgroundColor: "background.paper",
height: 32,
"& .MuiChip-label": { px: 1.5 },
}}
variant="outlined"
/>
);
})}
"& .MuiChip-label": { px: 1.5 },
}}
variant="outlined"
/>
);
})}
</Stack>
<Popover

View File

@@ -5,8 +5,7 @@ import { getFieldType, getFieldProp } from "@src/components/fields";
import { FieldType } from "@src/constants/fields";
import type { ColumnConfig, TableFilter } from "@src/types/table";
import type { IFieldConfig } from "@src/components/fields/types";
export const INITIAL_QUERY = { key: "", operator: "", value: "" };
import { generateId } from "@src/utils/table";
export const useFilterInputs = (
columns: ColumnConfig[],
@@ -34,50 +33,112 @@ export const useFilterInputs = (
config: {},
});
const INITIAL_QUERY: TableFilter[] =
filterColumns && filterColumns.length > 0
? [
{
key: filterColumns[0].key,
operator:
filterColumns[0].key === "_rowy_ref.id"
? "id-equal"
: getFieldProp("filter", getFieldType(filterColumns[0]))
.operators[0].value,
value:
filterColumns[0].key === "_rowy_ref.id"
? ""
: getFieldProp("filter", getFieldType(filterColumns[0]))
.defaultValue ?? "",
id: generateId(),
},
]
: [];
// State for filter inputs
const [query, setQuery] = useState<TableFilter | typeof INITIAL_QUERY>(
defaultQuery || INITIAL_QUERY
const [queries, setQueries] = useState<TableFilter[]>(
defaultQuery ? [{ ...defaultQuery, id: generateId() }] : INITIAL_QUERY
);
const resetQuery = () => setQuery(INITIAL_QUERY);
const resetQuery = () => setQueries([]);
// State for filter inputs joined by AND/OR
const [joinOperator, setJoinOperator] = useState<"AND" | "OR">("AND");
// When the user sets a new column, automatically set the operator and value
const handleChangeColumn = (value: string | null) => {
if (value === "_rowy_ref.id") {
setQuery({ key: "_rowy_ref.id", operator: "id-equal", value: "" });
const handleColumnChange = (oldId: string, newKey: string) => {
if (newKey === "_rowy_ref.id") {
setQueries((prevQueries) => {
return prevQueries.map((q) => {
if (q.id === oldId)
return {
key: newKey,
operator: "id-equal",
value: "",
id: q.id,
};
return q;
});
});
return;
}
const column = find(filterColumns, ["key", value]);
const column = find(filterColumns, ["key", newKey]);
if (column) {
const filter = getFieldProp("filter", getFieldType(column));
setQuery({
key: column.key,
operator: filter.operators[0].value,
value: filter.defaultValue ?? "",
setQueries((prevQueries) => {
return prevQueries.map((q) => {
if (q.id === oldId)
return {
key: newKey,
operator: filter.operators[0].value,
value: filter.defaultValue ?? "",
id: q.id,
};
return q;
});
});
} else {
setQuery(INITIAL_QUERY);
setQueries((prevQueries) => {
return prevQueries.map((q) => {
if (q.id === oldId)
return {
key: newKey,
operator: "is-not-empty",
value: "",
id: q.id,
};
return q;
});
});
}
};
// Get the column config
const selectedColumn = find(filterColumns, ["key", query?.key]);
// Get available filters from selected column type
const availableFilters: IFieldConfig["filter"] =
query?.key === "_rowy_ref.id"
? { operators: [{ value: "id-equal", label: "is" }] }
: selectedColumn
? getFieldProp("filter", getFieldType(selectedColumn))
: undefined;
const selectedColumns = [];
for (const query of queries) {
const column = find(filterColumns, ["key", query.key]);
if (column) selectedColumns.push(column);
}
const availableFiltersForEachSelectedColumn: IFieldConfig["filter"][] =
selectedColumns.map((column) => {
if (column.key === "_rowy_ref.id") {
return { operators: [{ value: "id-equal", label: "is" }] };
}
return getFieldProp("filter", getFieldType(column));
});
return {
filterColumns,
selectedColumn,
handleChangeColumn,
availableFilters,
query,
setQuery,
selectedColumns,
handleColumnChange,
availableFiltersForEachSelectedColumn,
queries,
setQueries,
resetQuery,
joinOperator,
setJoinOperator,
} as const;
};

View File

@@ -0,0 +1,64 @@
import { TableFilter } from "@src/types/table";
import { useSnackbar } from "notistack";
import { useEffect, useState } from "react";
import { useSearchParams } from "react-router-dom";
function isTableFilter(filter: any): filter is TableFilter {
if (typeof filter !== "object") return false;
if ("key" in filter === false) return false;
if ("id" in filter === false) return false;
if ("value" in filter === false) return false;
if ("operator" in filter === false) return false;
return true;
}
/** Hook to manage filter as a query parameter */
export function useFilterUrl() {
const [searchParams, setSearchParams] = useSearchParams();
const { enqueueSnackbar } = useSnackbar();
const [filters, setFilters] = useState<TableFilter[] | null>(null);
// Fetch filter from URL and update user filter
useEffect(() => {
const filterParam = searchParams.get("filter");
if (filterParam) {
try {
const _filters = JSON.parse(decodeURIComponent(filterParam));
if (!Array.isArray(_filters))
throw new Error("Filter should be an array");
for (const _filter of _filters) {
if (!isTableFilter(_filter)) throw new Error("Invalid Filter");
}
setFilters(_filters);
} catch (err) {
enqueueSnackbar("Oops, filter in URL is incorrect!!!", {
variant: "error",
});
}
}
}, [searchParams]);
const updateFilterQueryParam = (filter: TableFilter[]) => {
const searchParams = new URLSearchParams(window.location.search);
if (filter.length === 0) {
searchParams.delete("filter");
} else {
// Due to the nature of searchParams, filter is being encoded twice. Once by
// encodeURIComponent and then by searchParams. We can't remove encodeURIComponent
// because searchParams uses application/x-www-form-urlencoded which is not URL safe.
searchParams.set("filter", encodeURIComponent(JSON.stringify(filter)));
}
setSearchParams(searchParams, { replace: true });
};
return {
/** Table filter present as a query param in the URL */
filtersUrl: filters,
/** Use this function to update the filter query param */
updateFilterQueryParam,
};
}

View File

@@ -1,27 +0,0 @@
export const URL =
window.location.protocol +
"//" +
window.location.host +
window.location.pathname;
export function separateOperands(str: string): {
operators: any[];
operands: string[];
} {
const operators = findOperators(str);
const operands = str.split(
new RegExp(operators.map((op) => `\\${op}`).join("|"), "g")
);
return { operators, operands };
}
export function changePageUrl(newURL: string | undefined = URL) {
if (newURL !== URL) {
newURL = URL + newURL;
}
window.history.pushState({ path: newURL }, "", newURL);
}
function findOperators(str: string) {
const operators = [">=", "<=", ">", "<", "==", "!=", "=", "-is-"];
const regex = new RegExp(operators.map((op) => `\\${op}`).join("|"), "g");
return str.match(regex) || [];
}

View File

@@ -1,7 +1,7 @@
import { lazy, Suspense } from "react";
import { useAtom, useSetAtom } from "jotai";
import { Button, Stack } from "@mui/material";
import { Button, Stack, Tooltip, Typography } from "@mui/material";
import WebhookIcon from "@mui/icons-material/Webhook";
import {
Export as ExportIcon,
@@ -33,10 +33,14 @@ import {
tableSchemaAtom,
tableModalAtom,
tableSortsAtom,
serverDocCountAtom,
deleteRowAtom,
} from "@src/atoms/tableScope";
import { FieldType } from "@src/constants/fields";
import { TableToolsType } from "@src/types/table";
import FilterIcon from "@mui/icons-material/FilterList";
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
import { RowSelectionState } from "@tanstack/react-table";
// prettier-ignore
const Sort = lazy(() => import("./Sort" /* webpackChunkName: "Filters" */));
@@ -51,10 +55,75 @@ const ReExecute = lazy(() => import("./ReExecute" /* webpackChunkName: "ReExecut
export const TABLE_TOOLBAR_HEIGHT = 44;
const StyledStack = ({ children }: React.PropsWithChildren) => (
<Stack
direction="row"
alignItems="center"
spacing={1}
sx={{
pl: (theme) => `max(env(safe-area-inset-left), ${theme.spacing(2)})`,
pb: 1.5,
height: TABLE_TOOLBAR_HEIGHT,
scrollbarWidth: "thin",
overflowX: "auto",
"&": { overflowX: "overlay" },
overflowY: "hidden",
"& > *": { flexShrink: 0 },
"& > .end-spacer": {
width: (theme) =>
`max(env(safe-area-inset-right), ${theme.spacing(2)})`,
height: "100%",
ml: 0,
},
}}
>
{children}
</Stack>
);
function RowSelectedToolBar({
selectedRows,
resetSelectedRows,
}: {
selectedRows: RowSelectionState;
resetSelectedRows: () => void;
}) {
const [serverDocCount] = useAtom(serverDocCountAtom, tableScope);
const deleteRow = useSetAtom(deleteRowAtom, tableScope);
const handleDelete = async () => {
await deleteRow({ path: Object.keys(selectedRows) });
resetSelectedRows();
};
return (
<StyledStack>
<Typography>
{Object.values(selectedRows).length} of {serverDocCount} rows selected
</Typography>
<Tooltip title="Delete row">
<Button
variant="outlined"
startIcon={<DeleteIcon fontSize="small" />}
color="error"
onClick={handleDelete}
>
Delete
</Button>
</Tooltip>
</StyledStack>
);
}
export default function TableToolbar({
disabledTools,
selectedRows,
resetSelectedRows,
}: {
disabledTools?: TableToolsType[];
selectedRows?: RowSelectionState;
resetSelectedRows?: () => void;
}) {
const [projectSettings] = useAtom(projectSettingsAtom, projectScope);
const [userRoles] = useAtom(userRolesAtom, projectScope);
@@ -77,29 +146,17 @@ export default function TableToolbar({
tableSchema.compiledExtension.replace(/\W/g, "")?.length > 0;
disabledTools = disabledTools ?? [];
return (
<Stack
direction="row"
alignItems="center"
spacing={1}
sx={{
pl: (theme) => `max(env(safe-area-inset-left), ${theme.spacing(2)})`,
pb: 1.5,
height: TABLE_TOOLBAR_HEIGHT,
scrollbarWidth: "thin",
overflowX: "auto",
"&": { overflowX: "overlay" },
overflowY: "hidden",
"& > *": { flexShrink: 0 },
"& > .end-spacer": {
width: (theme) =>
`max(env(safe-area-inset-right), ${theme.spacing(2)})`,
height: "100%",
ml: 0,
},
}}
>
if (selectedRows && Object.keys(selectedRows).length > 0 && resetSelectedRows)
return (
<RowSelectedToolBar
selectedRows={selectedRows}
resetSelectedRows={resetSelectedRows}
/>
);
return (
<StyledStack>
{tableSettings.isCollection === false ? (
<AddRowArraySubTable />
) : (
@@ -202,6 +259,6 @@ export default function TableToolbar({
)}
<TableInformation />
<div className="end-spacer" />
</Stack>
</StyledStack>
);
}

View File

@@ -0,0 +1,20 @@
import { IFilterOperator } from "@src/components/fields/types";
export const operators: IFilterOperator[] = [
{
label: "equals",
value: "==",
},
{
label: "not equals",
value: "!=",
},
{
label: "contains the following",
value: "array-contains",
},
{
label: "contains atleast one of the following",
value: "array-contains-any",
},
];

View File

@@ -120,7 +120,7 @@ export default function ArraySideDrawerField({
}: ISideDrawerFieldProps) {
const handleAddNew = (fieldType: ArraySupportedFiledTypes) => {
onChange([...(value || []), SupportedTypes[fieldType].initialValue]);
onDirty(true);
if (onDirty) onDirty(true);
};
const handleChange = (newValue_: any, indexUpdated: number) => {
onChange(
@@ -137,13 +137,13 @@ export default function ArraySideDrawerField({
const handleRemove = (index: number) => {
value.splice(index, 1);
onChange([...value]);
onDirty(true);
if (onDirty) onDirty(true);
onSubmit();
};
const handleClearField = () => {
onChange([]);
onSubmit();
if (onSubmit) onSubmit();
};
function handleOnDragEnd(result: DropResult) {
@@ -157,7 +157,7 @@ export default function ArraySideDrawerField({
const [removed] = list.splice(result.source.index, 1);
list.splice(result.destination.index, 0, removed);
onChange(list);
onSubmit();
if (onSubmit) onSubmit();
}
if (value === undefined || Array.isArray(value)) {
@@ -166,7 +166,11 @@ export default function ArraySideDrawerField({
<DragDropContext onDragEnd={handleOnDragEnd}>
<Droppable droppableId="columns_manager" direction="vertical">
{(provided) => (
<List {...provided.droppableProps} ref={provided.innerRef}>
<List
sx={{ padding: 0 }}
{...provided.droppableProps}
ref={provided.innerRef}
>
{(value || []).map((v: any, index: number) => (
<ArrayFieldInput
key={`index-${index}-value`}
@@ -185,7 +189,15 @@ export default function ArraySideDrawerField({
)}
</Droppable>
</DragDropContext>
<AddButton handleAddNew={handleAddNew} />
{props.operator === "array-contains" ? (
value?.length < 1 ? (
<AddButton handleAddNew={handleAddNew} />
) : (
<></>
)
) : (
<AddButton handleAddNew={handleAddNew} />
)}
</>
);
}

View File

@@ -5,6 +5,7 @@ import { IFieldConfig, FieldType } from "@src/components/fields/types";
import withRenderTableCell from "@src/components/Table/TableCell/withRenderTableCell";
import DisplayCell from "./DisplayCell";
import { operators } from "./Filter";
import BasicContextMenuActions from "@src/components/Table/ContextMenu/BasicCellContextMenuActions";
@@ -27,6 +28,7 @@ export const config: IFieldConfig = {
popoverProps: { PaperProps: { sx: { p: 1, minWidth: "200px" } } },
}),
SideDrawerField,
filter: { operators, defaultValue: [] },
requireConfiguration: false,
contextMenuActions: BasicContextMenuActions,
};

View File

@@ -9,4 +9,12 @@ export const filterOperators: IFilterOperator[] = [
label: "not equals",
value: "!=",
},
{
label: "is empty",
value: "is-empty",
},
{
label: "is not empty",
value: "is-not-empty",
},
];

View File

@@ -9,4 +9,12 @@ export const filterOperators: IFilterOperator[] = [
label: "not equals",
value: "!=",
},
{
label: "is empty",
value: "is-empty",
},
{
label: "is not empty",
value: "is-not-empty",
},
];

View File

@@ -94,6 +94,8 @@ export interface ISideDrawerFieldProps<T = any> {
disabled: boolean;
row: TableRow;
operator?: TableFilter["operator"];
}
export interface ISettingsProps {

View File

@@ -19,11 +19,12 @@ import {
deleteField,
CollectionReference,
Query,
QueryConstraint,
WhereFilterOp,
documentId,
getCountFromServer,
DocumentData,
or,
QueryFieldFilterConstraint,
} from "firebase/firestore";
import { useErrorHandler } from "react-error-boundary";
@@ -66,6 +67,8 @@ interface IUseFirestoreCollectionWithAtomOptions<T> {
nextPageAtom?: PrimitiveAtom<NextPageState>;
/** Set this atom's value to the number of docs in the collection on each new snapshot */
serverDocCountAtom?: PrimitiveAtom<number | undefined>;
joinOperator?: "AND" | "OR";
}
/**
@@ -100,6 +103,7 @@ export function useFirestoreCollectionWithAtom<
deleteDocAtom,
nextPageAtom,
serverDocCountAtom,
joinOperator,
} = options || {};
const [firebaseDb] = useAtom(firebaseDbAtom, projectScope);
@@ -140,6 +144,7 @@ export function useFirestoreCollectionWithAtom<
page,
pageSize,
filters,
joinOperator,
sorts,
onError
),
@@ -152,6 +157,9 @@ export function useFirestoreCollectionWithAtom<
)
return false;
// If joinOperator is not equal, update the query
if (next?.joinOperator !== prev?.joinOperator) return false;
// If sorts are not equal, update the query
// Overrides isLastPage check
if (JSON.stringify(next?.sorts) !== JSON.stringify(prev?.sorts))
@@ -309,6 +317,7 @@ const getQuery = <T>(
page: number,
pageSize: number,
filters: IUseFirestoreCollectionWithAtomOptions<T>["filters"],
joinOperator: "AND" | "OR" | undefined,
sorts: IUseFirestoreCollectionWithAtomOptions<T>["sorts"],
onError: IUseFirestoreCollectionWithAtomOptions<T>["onError"]
) => {
@@ -335,19 +344,37 @@ const getQuery = <T>(
const limit = (page + 1) * pageSize;
const firestoreFilters = tableFiltersToFirestoreFilters(filters || []);
return {
query: query<T>(
collectionRef,
queryLimit(limit),
...firestoreFilters,
...(sorts?.map((order) => orderBy(order.key, order.direction)) || [])
),
page,
limit,
firestoreFilters,
sorts,
unlimitedQuery: query<T>(collectionRef, ...firestoreFilters),
};
return joinOperator === "OR"
? {
query: query<T>(
collectionRef,
or(...firestoreFilters),
queryLimit(limit),
...(sorts?.map((order) => orderBy(order.key, order.direction)) ||
[])
),
page,
limit,
firestoreFilters,
sorts,
unlimitedQuery: query<T>(collectionRef, ...firestoreFilters),
joinOperator,
}
: {
query: query<T>(
collectionRef,
queryLimit(limit),
...firestoreFilters,
...(sorts?.map((order) => orderBy(order.key, order.direction)) ||
[])
),
page,
limit,
firestoreFilters,
sorts,
unlimitedQuery: query<T>(collectionRef, ...firestoreFilters),
joinOperator,
};
} catch (e) {
if (onError) onError(e as FirestoreError);
return null;
@@ -361,7 +388,7 @@ const getQuery = <T>(
* @returns Array of Firestore query `where` constraints
*/
export const tableFiltersToFirestoreFilters = (filters: TableFilter[]) => {
const firestoreFilters: QueryConstraint[] = [];
const firestoreFilters: QueryFieldFilterConstraint[] = [];
for (const filter of filters) {
if (filter.operator.startsWith("date-")) {
@@ -405,7 +432,20 @@ export const tableFiltersToFirestoreFilters = (filters: TableFilter[]) => {
where(filter.key.concat(".hex"), "!=", filter.value.hex.toString())
);
continue;
} else if (filter.operator === "is-empty") {
firestoreFilters.push(where(filter.key, "==", ""));
continue;
} else if (filter.operator === "is-not-empty") {
firestoreFilters.push(where(filter.key, "!=", ""));
} else if (filter.operator === "array-contains") {
if (!filter.value || !filter.value.length) continue;
// make the value as a singular string
firestoreFilters.push(
where(filter.key, filter.operator as WhereFilterOp, filter.value[0])
);
continue;
}
firestoreFilters.push(
where(filter.key, filter.operator as WhereFilterOp, filter.value)
);

View File

@@ -139,6 +139,7 @@ export default function ProvidedArraySubTablePage() {
<DebugAtoms scope={tableScope} />
<ArraySubTableSourceFirestore />
<TablePage
enableRowSelection={false}
disabledTools={[
"import",
"export",

View File

@@ -137,7 +137,7 @@ export default function ProvidedSubTablePage() {
>
<DebugAtoms scope={tableScope} />
<TableSourceFirestore />
<TablePage />
<TablePage enableRowSelection />
</Provider>
</Suspense>
</ErrorBoundary>

View File

@@ -141,7 +141,7 @@ export default function ProvidedTablePage() {
}
>
<main>
<TablePage disableModals={Boolean(outlet)} />
<TablePage enableRowSelection disableModals={Boolean(outlet)} />
</main>
</Suspense>
<Suspense fallback={null}>{outlet}</Suspense>

View File

@@ -1,4 +1,4 @@
import { Suspense, lazy } from "react";
import { Suspense, lazy, useMemo, useState } from "react";
import { useAtom } from "jotai";
import { ErrorBoundary } from "react-error-boundary";
import { isEmpty, intersection } from "lodash-es";
@@ -33,7 +33,6 @@ import {
tableSchemaAtom,
columnModalAtom,
tableModalAtom,
tableSortsAtom,
} from "@src/atoms/tableScope";
import useBeforeUnload from "@src/hooks/useBeforeUnload";
import ActionParamsProvider from "@src/components/fields/Action/FormDialog/Provider";
@@ -43,6 +42,7 @@ import { TABLE_TOOLBAR_HEIGHT } from "@src/components/TableToolbar";
import { DRAWER_COLLAPSED_WIDTH } from "@src/components/SideDrawer";
import { formatSubTableName } from "@src/utils/table";
import { TableToolsType } from "@src/types/table";
import { RowSelectionState } from "@tanstack/react-table";
// prettier-ignore
const BuildLogsSnack = lazy(() => import("@src/components/TableModals/CloudLogsModal/BuildLogs/BuildLogsSnack" /* webpackChunkName: "TableModals-BuildLogsSnack" */));
@@ -57,6 +57,8 @@ export interface ITablePageProps {
disableSideDrawer?: boolean;
/** list of table tools to be disabled */
disabledTools?: TableToolsType;
/** If true shows checkbox to select rows */
enableRowSelection?: boolean;
}
/**
@@ -76,6 +78,7 @@ export default function TablePage({
disableModals,
disableSideDrawer,
disabledTools,
enableRowSelection = false,
}: ITablePageProps) {
const [userRoles] = useAtom(userRolesAtom, projectScope);
const [userSettings] = useAtom(userSettingsAtom, projectScope);
@@ -101,6 +104,21 @@ export default function TablePage({
useBeforeUnload(columnModalAtom, tableScope);
useBeforeUnload(tableModalAtom, tableScope);
const [selectedRows, setSelectedRows] = useState<RowSelectionState>({});
// Without useMemo we'll be stuck in an infinite loop
const selectedRowsProp = useMemo(
() => ({
state: selectedRows,
setState: setSelectedRows,
}),
[selectedRows, setSelectedRows]
);
const resetSelectedRows = () => {
setSelectedRows({});
};
if (!(tableSchema as any)._rowy_ref)
return (
<>
@@ -132,7 +150,11 @@ export default function TablePage({
<ActionParamsProvider>
<ErrorBoundary FallbackComponent={InlineErrorFallback}>
<Suspense fallback={<TableToolbarSkeleton />}>
<TableToolbar disabledTools={disabledTools} />
<TableToolbar
disabledTools={disabledTools}
selectedRows={selectedRows}
resetSelectedRows={resetSelectedRows}
/>
</Suspense>
</ErrorBoundary>
@@ -160,6 +182,7 @@ export default function TablePage({
hiddenColumns={
userSettings.tables?.[formatSubTableName(tableId)]?.hiddenFields
}
selectedRows={enableRowSelection ? selectedRowsProp : undefined}
emptyState={
<EmptyState
Icon={AddRowIcon}

View File

@@ -21,6 +21,7 @@ import { firebaseDbAtom } from "@src/sources/ProjectSourceFirebase";
import { currentUserAtom, projectScope } from "@src/atoms/projectScope";
import { doc, setDoc, updateDoc } from "firebase/firestore";
import { TABLE_SCHEMAS } from "@src/config/dbPaths";
import { generateId } from "@src/utils/table";
function TableTestPage() {
const [tableId] = useAtom(tableIdAtom, tableScope);
@@ -78,7 +79,14 @@ function TableTestPage() {
<button
onClick={() =>
setTableFilters([{ key: "signedUp", operator: "==", value: true }])
setTableFilters([
{
key: "signedUp",
operator: "==",
value: true,
id: generateId(),
},
])
}
>
Set table filters

View File

@@ -24,6 +24,7 @@ import {
_deleteRowDbAtom,
tableNextPageAtom,
serverDocCountAtom,
tableFiltersJoinAtom,
} from "@src/atoms/tableScope";
import useFirestoreDocWithAtom, {
@@ -112,6 +113,8 @@ export const TableSourceFirestore = memo(function TableSourceFirestore() {
}
);
const [joinOperator] = useAtom(tableFiltersJoinAtom, tableScope);
// Get table filters and sorts
const [filters] = useAtom(tableFiltersAtom, tableScope);
const [sorts] = useAtom(tableSortsAtom, tableScope);
@@ -130,6 +133,7 @@ export const TableSourceFirestore = memo(function TableSourceFirestore() {
tableSettings.collection,
{
filters,
joinOperator,
sorts,
page,
collectionGroup: isCollectionGroup,

View File

@@ -47,7 +47,7 @@ export default function CheckboxIndeterminateIcon() {
boxShadow: 1,
},
".Mui-checked &, [aria-selected='true'] &": {
".MuiCheckbox-indeterminate &, [aria-selected='true'] &": {
backgroundColor: "currentColor",
borderColor: "currentColor",

View File

@@ -57,6 +57,7 @@ export type UserSettings = Partial<{
filters: TableFilter[];
hiddenFields: string[];
sorts: TableSort[];
joinOperator: "AND" | "OR";
}>
>;

View File

@@ -123,6 +123,8 @@ export type TableSchema = {
subTables?: SubTablesSchema;
/** @deprecated Migrate to Extensions */
sparks?: string;
joinOperator?: "AND" | "OR";
};
export type SubTablesSchema = {
@@ -194,8 +196,10 @@ export type TableFilter = {
| "id-equal"
| "color-equal"
| "color-not-equal"
| "-is-";
| "is-empty"
| "is-not-empty";
value: any;
id: string;
};
export const TableTools = [

View File

@@ -9,6 +9,9 @@ export default defineConfig({
// Explicitly setting mainFields to default value. For some reason, Vitest isn't
// respecting the 'module' field in package.json without specifying it explicitly
mainFields: ["module", "jsnext:main", "jsnext"],
alias: {
path: "rollup-plugin-node-polyfills/polyfills/path",
},
},
plugins: [
react({

721
yarn.lock
View File

@@ -3,9 +3,9 @@
"@adobe/css-tools@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.0.1.tgz#b38b444ad3aa5fedbb15f2f746dcd934226a12dd"
integrity sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==
version "4.3.1"
resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.1.tgz#abfccb8ca78075a2b6187345c26243c1a0842f28"
integrity sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==
"@algolia/cache-browser-local-storage@4.14.2":
version "4.14.2"
@@ -1525,6 +1525,14 @@
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb"
integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==
"@esbuild-plugins/node-modules-polyfill@^0.2.2":
version "0.2.2"
resolved "https://registry.yarnpkg.com/@esbuild-plugins/node-modules-polyfill/-/node-modules-polyfill-0.2.2.tgz#cefa3dc0bd1c16277a8338b52833420c94987327"
integrity sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==
dependencies:
escape-string-regexp "^4.0.0"
rollup-plugin-node-polyfills "^0.2.1"
"@esbuild/android-arm64@0.17.19":
version "0.17.19"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
@@ -1650,176 +1658,174 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@firebase/analytics-compat@0.1.17":
version "0.1.17"
resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.1.17.tgz#7be65327b3fe8a4dceab636562fc10032064280f"
integrity sha512-36ByEDsH6/3YNuD6yig30s2A/+E1pt333r8SJirUE8+aHYl/DGX0PXplKvJWDGamYYjMwet3Kt4XRrB1NY8mLg==
"@firebase/analytics-compat@0.2.6":
version "0.2.6"
resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.2.6.tgz#50063978c42f13eb800e037e96ac4b17236841f4"
integrity sha512-4MqpVLFkGK7NJf/5wPEEP7ePBJatwYpyjgJ+wQHQGHfzaCDgntOnl9rL2vbVGGKCnRqWtZDIWhctB86UWXaX2Q==
dependencies:
"@firebase/analytics" "0.8.4"
"@firebase/analytics-types" "0.7.1"
"@firebase/component" "0.5.21"
"@firebase/util" "1.7.3"
"@firebase/analytics" "0.10.0"
"@firebase/analytics-types" "0.8.0"
"@firebase/component" "0.6.4"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/analytics-types@0.7.1":
version "0.7.1"
resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.7.1.tgz#21556098e83aa14f192ce84051c81d794b2eb150"
integrity sha512-a1INLjelc1Mqrt2CbGmGdlNBj0zsvwBv0K5q5C6Fje8GSXBMc3+iQQQjzYe/4KkK6nL54UP7ZMeI/Q3VEW72FA==
"@firebase/analytics-types@0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.8.0.tgz#551e744a29adbc07f557306530a2ec86add6d410"
integrity sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw==
"@firebase/analytics@0.8.4":
version "0.8.4"
resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.8.4.tgz#596e79258605c8322ef25f47cd4e1ff94579dd90"
integrity sha512-Bgr2tMexv0YrL6kjrOF1xVRts8PM6WWmROpfRQjh0xFU4QSoofBJhkVn2NXDXkHWrr5slFfqB5yOnmgAIsHiMw==
"@firebase/analytics@0.10.0":
version "0.10.0"
resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.10.0.tgz#9c6986acd573c6c6189ffb52d0fd63c775db26d7"
integrity sha512-Locv8gAqx0e+GX/0SI3dzmBY5e9kjVDtD+3zCFLJ0tH2hJwuCAiL+5WkHuxKj92rqQj/rvkBUCfA1ewlX2hehg==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/installations" "0.5.16"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/installations" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/app-check-compat@0.2.17":
version "0.2.17"
resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.2.17.tgz#c949976e8353156d521a52664d3735d4aa3c4417"
integrity sha512-yhiAy6U4MuhbY+DCgvG5FcrXkAL+7YohRzqywycQKr31k/ftelbR5l9Zmo2WJMxdLxfubnnqeG/BYCRHlSvk7A==
"@firebase/app-check-compat@0.3.7":
version "0.3.7"
resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.3.7.tgz#e150f61d653a0f2043a34dcb995616a717161839"
integrity sha512-cW682AxsyP1G+Z0/P7pO/WT2CzYlNxoNe5QejVarW2o5ZxeWSSPAiVEwpEpQR/bUlUmdeWThYTMvBWaopdBsqw==
dependencies:
"@firebase/app-check" "0.5.17"
"@firebase/app-check-types" "0.4.1"
"@firebase/component" "0.5.21"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
"@firebase/app-check" "0.8.0"
"@firebase/app-check-types" "0.5.0"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/app-check-interop-types@0.1.1":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@firebase/app-check-interop-types/-/app-check-interop-types-0.1.1.tgz#7a6e01f4bc37195e58e62d7e4a2995e54b1957b8"
integrity sha512-QpYh5GmiLA9ob8NWAZpHbNNl9TzxxZI4NLevT6MYPRDXKG9BSmBI7FATRfm5uv2QQUVSQrESKog5CCmU16v+7Q==
"@firebase/app-check-interop-types@0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.0.tgz#b27ea1397cb80427f729e4bbf3a562f2052955c4"
integrity sha512-xAxHPZPIgFXnI+vb4sbBjZcde7ZluzPPaSK7Lx3/nmuVk4TjZvnL8ONnkd4ERQKL8WePQySU+pRcWkh8rDf5Sg==
"@firebase/app-check-types@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@firebase/app-check-types/-/app-check-types-0.4.1.tgz#7807e761b119d71562611a14c307ac8ca2981103"
integrity sha512-4X79w2X0H5i5qvaho3qkjZg5qdERnKR4gCfy/fxDmdMMP4QgNJHJ9IBk1E+c4cm5HlaZVcLq9K6z8xaRqjZhyw==
"@firebase/app-check-types@0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@firebase/app-check-types/-/app-check-types-0.5.0.tgz#1b02826213d7ce6a1cf773c329b46ea1c67064f4"
integrity sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ==
"@firebase/app-check@0.5.17":
version "0.5.17"
resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.5.17.tgz#d24aa73f9ac887711c79986c90f18b0f15cb2c14"
integrity sha512-P4bm0lbs+VgS7pns322GC0hyKuTDCqYk2X4FGBf133LZaw1NXJpzOteqPdCT0hBCaR0QSHk49gxx+bdnSdd5Fg==
"@firebase/app-check@0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.8.0.tgz#b531ec40900af9c3cf1ec63de9094a0ddd733d6a"
integrity sha512-dRDnhkcaC2FspMiRK/Vbp+PfsOAEP6ZElGm9iGFJ9fDqHoPs0HOPn7dwpJ51lCFi1+2/7n5pRPGhqF/F03I97g==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/app-compat@0.1.39":
version "0.1.39"
resolved "https://registry.yarnpkg.com/@firebase/app-compat/-/app-compat-0.1.39.tgz#3ea5465d07855fdb8357a0f63fd113da81468e50"
integrity sha512-F5O/N38dVGFzpe6zM//MslYT80rpX0V+MQNMvONPUlXhvDqS5T+8NMSCWOcZ++Z4Hkj8EvgTJk59AMnD8SdyFw==
"@firebase/app-compat@0.2.12":
version "0.2.12"
resolved "https://registry.yarnpkg.com/@firebase/app-compat/-/app-compat-0.2.12.tgz#90375027edccf2f3782af02014d0eb61ef7fde11"
integrity sha512-3EfputoACcXvgi2uN9RUQVDYSmRSR4R4TWJW9Wvs4hTib2I26ldvVhDHaheQq90IwGYrRa+TTWuzr4a5dCRkVQ==
dependencies:
"@firebase/app" "0.8.4"
"@firebase/component" "0.5.21"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
"@firebase/app" "0.9.12"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/app-types@0.8.1":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.8.1.tgz#4c7f916281aed570581fc667e3eb6cc730119a95"
integrity sha512-p75Ow3QhB82kpMzmOntv866wH9eZ3b4+QbUY+8/DA5Zzdf1c8Nsk8B7kbFpzJt4wwHMdy5LTF5YUnoTc1JiWkw==
"@firebase/app-types@0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.9.0.tgz#35b5c568341e9e263b29b3d2ba0e9cfc9ec7f01e"
integrity sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==
"@firebase/app@0.8.4":
version "0.8.4"
resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.8.4.tgz#e62b47f909e10627f7f377ecfb7b90b921303d21"
integrity sha512-gQntijd+sLaGWjcBQpk33giCEXNzGLB6489NMpypVgEXJwQXYQPSrtb9vUHXot1w1iy/j6xlNl4K8wwwNdRgDg==
"@firebase/app@0.9.12":
version "0.9.12"
resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.9.12.tgz#05f83181c54cdab88e054eb0a80d4ec551799b57"
integrity sha512-VsE/WHZU8M9BCnHMbOi3FqIVIsoG4FlEehjp+XCDNE0zxn4BGgnpLdBu6/r9Bg565b1ND7dm6LSVRtewmeRb3w==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
idb "7.0.1"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
idb "7.1.1"
tslib "^2.1.0"
"@firebase/auth-compat@0.2.24":
version "0.2.24"
resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.2.24.tgz#7ad914d412d467f181016c88b5a2b398b6e7fba3"
integrity sha512-IuZQScjtoOLkUHtmIUJ2F3E2OpDOyap6L/9HL/DX3nzEA1LrX7wlpeU6OF2jS9E0KLueWKIrSkIQOOsKoQj/sA==
"@firebase/auth-compat@0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.4.2.tgz#cb65edc2fbd5f72fff32310409f2fd702b5145e7"
integrity sha512-Q30e77DWXFmXEt5dg5JbqEDpjw9y3/PcP9LslDPR7fARmAOTIY9MM6HXzm9KC+dlrKH/+p6l8g9ifJiam9mc4A==
dependencies:
"@firebase/auth" "0.20.11"
"@firebase/auth-types" "0.11.1"
"@firebase/component" "0.5.21"
"@firebase/util" "1.7.3"
"@firebase/auth" "0.23.2"
"@firebase/auth-types" "0.12.0"
"@firebase/component" "0.6.4"
"@firebase/util" "1.9.3"
node-fetch "2.6.7"
selenium-webdriver "4.5.0"
tslib "^2.1.0"
"@firebase/auth-interop-types@0.1.7":
version "0.1.7"
resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.1.7.tgz#82c8d431779916224d2af5cef6cec2042d830f28"
integrity sha512-yA/dTveGGPcc85JP8ZE/KZqfGQyQTBCV10THdI8HTlP1GDvNrhr//J5jAt58MlsCOaO3XmC4DqScPBbtIsR/EA==
"@firebase/auth-interop-types@0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz#78884f24fa539e34a06c03612c75f222fcc33742"
integrity sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==
"@firebase/auth-types@0.11.1":
version "0.11.1"
resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.11.1.tgz#f5524891653dbe4e22fba7586ef00605f33ce61d"
integrity sha512-ud7T39VG9ptTrC2fOy/XlU+ubC+BVuBJPteuzsPZSa9l7gkntvWgVb3Z/3FxqqRPlkVUYiyvmsbRN3DE1He2ow==
"@firebase/auth-types@0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.12.0.tgz#f28e1b68ac3b208ad02a15854c585be6da3e8e79"
integrity sha512-pPwaZt+SPOshK8xNoiQlK5XIrS97kFYc3Rc7xmy373QsOJ9MmqXxLaYssP5Kcds4wd2qK//amx/c+A8O2fVeZA==
"@firebase/auth@0.20.11":
version "0.20.11"
resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.20.11.tgz#acf40fcf9c64af9d5f29ad9a8cfc2e99aed50237"
integrity sha512-cKy91l4URDG3yWfPK7tjUySh2wCLxtTilsR59jiqQJLReBrQsKP79eFDJ6jqWwbEh3+f1lmoH1nKswwbo9XdmA==
"@firebase/auth@0.23.2":
version "0.23.2"
resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.23.2.tgz#9e6d8dd550a28053c1825fb98c7dc9b37119254d"
integrity sha512-dM9iJ0R6tI1JczuGSxXmQbXAgtYie0K4WvKcuyuSTCu9V8eEDiz4tfa1sO3txsfvwg7nOY3AjoCyMYEdqZ8hdg==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
node-fetch "2.6.7"
selenium-webdriver "4.5.0"
tslib "^2.1.0"
"@firebase/component@0.5.21":
version "0.5.21"
resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.5.21.tgz#bb10add24fe2ee59a61163a469d4711d8da4002d"
integrity sha512-12MMQ/ulfygKpEJpseYMR0HunJdlsLrwx2XcEs40M18jocy2+spyzHHEwegN3x/2/BLFBjR5247Etmz0G97Qpg==
"@firebase/component@0.6.4":
version "0.6.4"
resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.6.4.tgz#8981a6818bd730a7554aa5e0516ffc9b1ae3f33d"
integrity sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==
dependencies:
"@firebase/util" "1.7.3"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/database-compat@0.2.10":
version "0.2.10"
resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-0.2.10.tgz#fa4440db9f41a9a05112642504c1e6557a75b8be"
integrity sha512-fK+IgUUqVKcWK/gltzDU+B1xauCOfY6vulO8lxoNTkcCGlSxuTtwsdqjGkFmgFRMYjXFWWJ6iFcJ/vXahzwCtA==
"@firebase/database-compat@0.3.4":
version "0.3.4"
resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-0.3.4.tgz#4e57932f7a5ba761cd5ac946ab6b6ab3f660522c"
integrity sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/database" "0.13.10"
"@firebase/database-types" "0.9.17"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/database" "0.14.4"
"@firebase/database-types" "0.10.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/database-types@0.9.17":
version "0.9.17"
resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.9.17.tgz#4c248052b0a9ae052ba940e4996a0bfab25dc257"
integrity sha512-YQm2tCZyxNtEnlS5qo5gd2PAYgKCy69tUKwioGhApCFThW+mIgZs7IeYeJo2M51i4LCixYUl+CvnOyAnb/c3XA==
"@firebase/database-types@0.10.4":
version "0.10.4"
resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.10.4.tgz#47ba81113512dab637abace61cfb65f63d645ca7"
integrity sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ==
dependencies:
"@firebase/app-types" "0.8.1"
"@firebase/util" "1.7.3"
"@firebase/app-types" "0.9.0"
"@firebase/util" "1.9.3"
"@firebase/database@0.13.10":
version "0.13.10"
resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.13.10.tgz#c24e0219490b9c1fabfb7b42cb45850e145fe56d"
integrity sha512-KRucuzZ7ZHQsRdGEmhxId5jyM2yKsjsQWF9yv0dIhlxYg0D8rCVDZc/waoPKA5oV3/SEIoptF8F7R1Vfe7BCQA==
"@firebase/database@0.14.4":
version "0.14.4"
resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.14.4.tgz#9e7435a16a540ddfdeb5d99d45618e6ede179aa6"
integrity sha512-+Ea/IKGwh42jwdjCyzTmeZeLM3oy1h0mFPsTy6OqCWzcu/KFqRAr5Tt1HRCOBlNOdbh84JPZC47WLU18n2VbxQ==
dependencies:
"@firebase/auth-interop-types" "0.1.7"
"@firebase/component" "0.5.21"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
"@firebase/auth-interop-types" "0.2.1"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
faye-websocket "0.11.4"
tslib "^2.1.0"
"@firebase/firestore-compat@0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.2.3.tgz#da2f4f9a1da8cdf0a83769ec771f64ad7866363c"
integrity sha512-FgJwGCA2K+lsGk6gbJo57qn4iocQSGfOlNi2s4QsEO/WOVIU00yYGm408fN7iAGpr9d5VKyulO4sYcic7cS51g==
"@firebase/firestore-compat@0.3.11":
version "0.3.11"
resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.3.11.tgz#010c78990c1a2a4b87d0eff68704baefd43f6f32"
integrity sha512-jPhySBBp6+Vt750WmeCK4it/NV9YHQEX+jJ7Va8wHOhVejy0zUhL5TsLF6Bz3hCjb4Dxn6XVgvuSqiuqY16yWw==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/firestore" "3.7.3"
"@firebase/component" "0.6.4"
"@firebase/firestore" "3.12.2"
"@firebase/firestore-types" "2.5.1"
"@firebase/util" "1.7.3"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/firestore-types@2.5.1":
@@ -1827,204 +1833,204 @@
resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-2.5.1.tgz#464b2ee057956599ca34de50eae957c30fdbabb7"
integrity sha512-xG0CA6EMfYo8YeUxC8FeDzf6W3FX1cLlcAGBYV6Cku12sZRI81oWcu61RSKM66K6kUENP+78Qm8mvroBcm1whw==
"@firebase/firestore@3.7.3":
version "3.7.3"
resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-3.7.3.tgz#c839d6983f81d2853daeac42fba316a86102e5e4"
integrity sha512-hnA8hljwJBpejv0SPlt0yiej1wz3VRcLzoNAZujTCI1wLoADkRNsqic5uN/Ge0M0vbmHliLXtet/PDqvEbB9Ww==
"@firebase/firestore@3.12.2":
version "3.12.2"
resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-3.12.2.tgz#8f1fbde355bd82b3164a1fac60049a501a1d3fdf"
integrity sha512-6EDIJ2V4hlUkPvAb1uH5DAz65ZvhStIM1oYGSUx6mt2UdEDu/0CAVS7xYBY6niTyM/+2r6XBW3hYG/1x1V27vg==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
"@firebase/webchannel-wrapper" "0.8.1"
"@grpc/grpc-js" "^1.3.2"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
"@firebase/webchannel-wrapper" "0.10.1"
"@grpc/grpc-js" "~1.7.0"
"@grpc/proto-loader" "^0.6.13"
node-fetch "2.6.7"
tslib "^2.1.0"
"@firebase/functions-compat@0.2.8":
version "0.2.8"
resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.2.8.tgz#e6f1c476cdd6c3657d3b6328aebe8a62ace0a7bb"
integrity sha512-5w668whT+bm6oVcFqIxfFbn9N77WycpNCfZNg1l0iC+5RLSt53RTVu43pqi43vh23Vp4ad+SRBgZiQGAMen5wA==
"@firebase/functions-compat@0.3.5":
version "0.3.5"
resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.3.5.tgz#7a532d3a9764c6d5fbc1ec5541a989a704326647"
integrity sha512-uD4jwgwVqdWf6uc3NRKF8cSZ0JwGqSlyhPgackyUPe+GAtnERpS4+Vr66g0b3Gge0ezG4iyHo/EXW/Hjx7QhHw==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/functions" "0.8.8"
"@firebase/functions-types" "0.5.1"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/functions" "0.10.0"
"@firebase/functions-types" "0.6.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/functions-types@0.5.1":
version "0.5.1"
resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.5.1.tgz#7633fd2ade99c1b8c0c5037fa369fc91849e3b15"
integrity sha512-olEJnTuULM/ws0pwhHA0Ze5oIdpFbZsdBGCaBhyL4pm1NUR4Moh0cyAsqr+VtqHCNMGquHU1GJ77qITkoonp0w==
"@firebase/functions-types@0.6.0":
version "0.6.0"
resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.6.0.tgz#ccd7000dc6fc668f5acb4e6a6a042a877a555ef2"
integrity sha512-hfEw5VJtgWXIRf92ImLkgENqpL6IWpYaXVYiRkFY1jJ9+6tIhWM7IzzwbevwIIud/jaxKVdRzD7QBWfPmkwCYw==
"@firebase/functions@0.8.8":
version "0.8.8"
resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.8.8.tgz#a193d5565670bfa9b0e64b00556fae7d183fc895"
integrity sha512-weNcDQJcH3/2YFaXd5dF5pUk3IQdZY60QNuWpq7yS+uaPlCRHjT0K989Q3ZcmYwXz7mHTfhlQamXdA4Yobgt+Q==
"@firebase/functions@0.10.0":
version "0.10.0"
resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.10.0.tgz#c630ddf12cdf941c25bc8d554e30c3226cd560f6"
integrity sha512-2U+fMNxTYhtwSpkkR6WbBcuNMOVaI7MaH3cZ6UAeNfj7AgEwHwMIFLPpC13YNZhno219F0lfxzTAA0N62ndWzA==
dependencies:
"@firebase/app-check-interop-types" "0.1.1"
"@firebase/auth-interop-types" "0.1.7"
"@firebase/component" "0.5.21"
"@firebase/messaging-interop-types" "0.1.1"
"@firebase/util" "1.7.3"
"@firebase/app-check-interop-types" "0.3.0"
"@firebase/auth-interop-types" "0.2.1"
"@firebase/component" "0.6.4"
"@firebase/messaging-interop-types" "0.2.0"
"@firebase/util" "1.9.3"
node-fetch "2.6.7"
tslib "^2.1.0"
"@firebase/installations-compat@0.1.16":
version "0.1.16"
resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.1.16.tgz#b54c2fefaffd49a9f16e84ab5260348197ea9e4e"
integrity sha512-Xp7s3iUMZ6/TN0a+g1kpHNEn7h59kSxi44/2I7bd3X6xwHnxMu0TqYB7U9WfqEhqiI9iKulL3g06wIZqaklElw==
"@firebase/installations-compat@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.4.tgz#b5557c897b4cd3635a59887a8bf69c3731aaa952"
integrity sha512-LI9dYjp0aT9Njkn9U4JRrDqQ6KXeAmFbRC0E7jI7+hxl5YmRWysq5qgQl22hcWpTk+cm3es66d/apoDU/A9n6Q==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/installations" "0.5.16"
"@firebase/installations-types" "0.4.1"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/installations" "0.6.4"
"@firebase/installations-types" "0.5.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/installations-types@0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.4.1.tgz#3aa99213e39a81a3bbac25b1627169082da289ad"
integrity sha512-ac906QcmipomZjSasGDYNS1LDy4JNGzQ4VXHpFtoOrI6U2QGFkRezZpI+5bzfU062JOD+doO6irYC6Uwnv/GnA==
"@firebase/installations-types@0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.5.0.tgz#2adad64755cd33648519b573ec7ec30f21fb5354"
integrity sha512-9DP+RGfzoI2jH7gY4SlzqvZ+hr7gYzPODrbzVD82Y12kScZ6ZpRg/i3j6rleto8vTFC8n6Len4560FnV1w2IRg==
"@firebase/installations@0.5.16":
version "0.5.16"
resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.5.16.tgz#ee83f771d36e991335d625dc861ac7d5574044e4"
integrity sha512-k3iyjr+yZnDOcJbP+CCZW3/zQJf9gYL2CNBJs9QbmFJoLz7cgIcnAT/XNDMudxcggF1goLfq4+MygpzHD0NzLA==
"@firebase/installations@0.6.4":
version "0.6.4"
resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.4.tgz#20382e33e6062ac5eff4bede8e468ed4c367609e"
integrity sha512-u5y88rtsp7NYkCHC3ElbFBrPtieUybZluXyzl7+4BsIz4sqb4vSAuwHEUgCgCeaQhvsnxDEU6icly8U9zsJigA==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/util" "1.9.3"
idb "7.0.1"
tslib "^2.1.0"
"@firebase/logger@0.3.4":
version "0.3.4"
resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.3.4.tgz#8822dd3e9168be93c1bce0b4ac235e3b165a6a68"
integrity sha512-hlFglGRgZEwoyClZcGLx/Wd+zoLfGmbDkFx56mQt/jJ0XMbfPqwId1kiPl0zgdWZX+D8iH+gT6GuLPFsJWgiGw==
"@firebase/logger@0.4.0":
version "0.4.0"
resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.4.0.tgz#15ecc03c452525f9d47318ad9491b81d1810f113"
integrity sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==
dependencies:
tslib "^2.1.0"
"@firebase/messaging-compat@0.1.21":
version "0.1.21"
resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.1.21.tgz#1e221cdd186fd48d41a8b9c42fdb912476717939"
integrity sha512-oxQCQ8EXqpSaTybryokbEM/LAqkG0L7OJuucllCg5roqRGIHE437Abus0Bn67P8TKJaYjyKxomg8wCvfmInjlg==
"@firebase/messaging-compat@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.4.tgz#323ca48deef77065b4fcda3cfd662c4337dffcfd"
integrity sha512-lyFjeUhIsPRYDPNIkYX1LcZMpoVbBWXX4rPl7c/rqc7G+EUea7IEtSt4MxTvh6fDfPuzLn7+FZADfscC+tNMfg==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/messaging" "0.11.0"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/messaging" "0.12.4"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/messaging-interop-types@0.1.1":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.1.1.tgz#03733115df2688786be5f96baa64869fb3914d0c"
integrity sha512-7XuY87zPh01EBaeS3s6co31Il5oGbPl5MxAg6Uj3fPv7PqJQlbwQ+B5k7CKSF/Y26tRxp+u+usxIvIWCSEA8CQ==
"@firebase/messaging-interop-types@0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.0.tgz#6056f8904a696bf0f7fdcf5f2ca8f008e8f6b064"
integrity sha512-ujA8dcRuVeBixGR9CtegfpU4YmZf3Lt7QYkcj693FFannwNuZgfAYaTmbJ40dtjB81SAu6tbFPL9YLNT15KmOQ==
"@firebase/messaging@0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.11.0.tgz#ab6dbcd8b95f2b65f2290eb44110979261f84399"
integrity sha512-V7+Xw4QlB8PgINY7Wml+Uj8A3S2nR0ooVoaqfRJ8ZN3W7A4aO/DCkjPsf6DXehwfqRLA7PGB9Boe8l9Idy7icA==
"@firebase/messaging@0.12.4":
version "0.12.4"
resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.12.4.tgz#ccb49df5ab97d5650c9cf5b8c77ddc34daafcfe0"
integrity sha512-6JLZct6zUaex4g7HI3QbzeUrg9xcnmDAPTWpkoMpd/GoSVWH98zDoWXMGrcvHeCAIsLpFMe4MPoZkJbrPhaASw==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/installations" "0.5.16"
"@firebase/messaging-interop-types" "0.1.1"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/installations" "0.6.4"
"@firebase/messaging-interop-types" "0.2.0"
"@firebase/util" "1.9.3"
idb "7.0.1"
tslib "^2.1.0"
"@firebase/performance-compat@0.1.17":
version "0.1.17"
resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.1.17.tgz#23774adda07f6af83299517a202f8d98ebc9a70d"
integrity sha512-Hci5MrDlRuqwVozq7LaSAufXXElz+AtmEQArix64kLRJqHhOu5K/8TpuZXM/klR6gnLyIrk+01CrAemH3zHpDw==
"@firebase/performance-compat@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.4.tgz#95cbf32057b5d9f0c75d804bc50e6ed3ba486274"
integrity sha512-nnHUb8uP9G8islzcld/k6Bg5RhX62VpbAb/Anj7IXs/hp32Eb2LqFPZK4sy3pKkBUO5wcrlRWQa6wKOxqlUqsg==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/logger" "0.3.4"
"@firebase/performance" "0.5.17"
"@firebase/performance-types" "0.1.1"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/performance" "0.6.4"
"@firebase/performance-types" "0.2.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/performance-types@0.1.1":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.1.1.tgz#ac37fff87f2e716c18fb78c138dc398d9b9aecd7"
integrity sha512-wiJRLBg8EPaYSGJqx7aqkZ3L5fULfZa9zOTs4C06K020g0zzJh9kUUO/0U3wvHz7zRQjJxTO8Jw4SDjxs3EZrA==
"@firebase/performance-types@0.2.0":
version "0.2.0"
resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.2.0.tgz#400685f7a3455970817136d9b48ce07a4b9562ff"
integrity sha512-kYrbr8e/CYr1KLrLYZZt2noNnf+pRwDq2KK9Au9jHrBMnb0/C9X9yWSXmZkFt4UIdsQknBq8uBB7fsybZdOBTA==
"@firebase/performance@0.5.17":
version "0.5.17"
resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.5.17.tgz#f0aa9724df9e2ef095f176c2ef1accfa75e3bac6"
integrity sha512-NDgzI5JYo6Itnj1FWhMkK3LtwKhtOnhC+WBkxezjzFVuCOornQjvu7ucAU1o2dHXh7MFruhHGFPsHyfkkMCljA==
"@firebase/performance@0.6.4":
version "0.6.4"
resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.6.4.tgz#0ad766bfcfab4f386f4fe0bef43bbcf505015069"
integrity sha512-HfTn/bd8mfy/61vEqaBelNiNnvAbUtME2S25A67Nb34zVuCSCRIX4SseXY6zBnOFj3oLisaEqhVcJmVPAej67g==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/installations" "0.5.16"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/installations" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/remote-config-compat@0.1.16":
version "0.1.16"
resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.1.16.tgz#2953f8d556145eb57cb4244eb3e2c4a2c6f19804"
integrity sha512-BWonzeqODnGki/fZ17zOnjJFR5CWbIOU0PmYGjWBnbkWxpFDdE3zNsz8JTVd/Mkt7y2PHFMYpLsyZ473E/62FQ==
"@firebase/remote-config-compat@0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.4.tgz#1f494c81a6c9560b1f9ca1b4fbd4bbbe47cf4776"
integrity sha512-FKiki53jZirrDFkBHglB3C07j5wBpitAaj8kLME6g8Mx+aq7u9P7qfmuSRytiOItADhWUj7O1JIv7n9q87SuwA==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/logger" "0.3.4"
"@firebase/remote-config" "0.3.15"
"@firebase/remote-config-types" "0.2.1"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/remote-config" "0.4.4"
"@firebase/remote-config-types" "0.3.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/remote-config-types@0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.2.1.tgz#9f7dfb6b0066443592b055dddc57b0c954b0e83c"
integrity sha512-1PGx4vKtMMd5uB6G1Nj2b8fOnJx7mIJGzkdyfhIM1oQx9k3dJ+pVu4StrNm46vHaD8ZlOQLr91YfUE43xSXwSg==
"@firebase/remote-config-types@0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.3.0.tgz#689900dcdb3e5c059e8499b29db393e4e51314b4"
integrity sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA==
"@firebase/remote-config@0.3.15":
version "0.3.15"
resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.3.15.tgz#97e14d08a1065ce1ccd63b13a6eaa0927164556d"
integrity sha512-ZCyqoCaftoNvc2r4zPaqNV4OgC4sRHjcQI+agzXESnhDLnTY8DpCaQ0m9j6deHuxxDOgu8QPDb8psLbjR+9CgQ==
"@firebase/remote-config@0.4.4":
version "0.4.4"
resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.4.4.tgz#6a496117054de58744bc9f382d2a6d1e14060c65"
integrity sha512-x1ioTHGX8ZwDSTOVp8PBLv2/wfwKzb4pxi0gFezS5GCJwbLlloUH4YYZHHS83IPxnua8b6l0IXUaWd0RgbWwzQ==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/installations" "0.5.16"
"@firebase/logger" "0.3.4"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/installations" "0.6.4"
"@firebase/logger" "0.4.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/storage-compat@0.1.22":
version "0.1.22"
resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.1.22.tgz#0eba37444a525fce3854c68eacc1d2b5d87f8b5a"
integrity sha512-uv33WnAEcxf2983Z03uhJmKc91LKSsRijFwut8xeoJamJoGAVj1Tc9Mio491aI1KZ+RMkNFghHL2FpxjuvxpPg==
"@firebase/storage-compat@0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.3.2.tgz#51a97170fd652a516f729f82b97af369e5a2f8d7"
integrity sha512-wvsXlLa9DVOMQJckbDNhXKKxRNNewyUhhbXev3t8kSgoCotd1v3MmqhKKz93ePhDnhHnDs7bYHy+Qa8dRY6BXw==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/storage" "0.9.14"
"@firebase/storage-types" "0.6.1"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/storage" "0.11.2"
"@firebase/storage-types" "0.8.0"
"@firebase/util" "1.9.3"
tslib "^2.1.0"
"@firebase/storage-types@0.6.1":
version "0.6.1"
resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.6.1.tgz#76b71b6f6ef5df4cf286e63f58e92638b9dcd62d"
integrity sha512-/pkNzKiGCSjdBBZHPvWL1kkPZfM3pFJ38HPJE1xTHwLBwdrFb4JrmY+5/E4ma5ePsbejecIOD1SZhEKDB/JwUQ==
"@firebase/storage-types@0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.8.0.tgz#f1e40a5361d59240b6e84fac7fbbbb622bfaf707"
integrity sha512-isRHcGrTs9kITJC0AVehHfpraWFui39MPaU7Eo8QfWlqW7YPymBmRgjDrlOgFdURh6Cdeg07zmkLP5tzTKRSpg==
"@firebase/storage@0.9.14":
version "0.9.14"
resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.9.14.tgz#e70a0e6a706df8401acfa9991306b77eb1e32d7d"
integrity sha512-he8VAJ4BLkQdebnna15TI1/ymkwQTeKnjA/psKMAJ2+/UswD/68bCMKOlTrMvw6Flv3zc5YZk1xdL9DHR0i6wg==
"@firebase/storage@0.11.2":
version "0.11.2"
resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.11.2.tgz#c5e0316543fe1c4026b8e3910f85ad73f5b77571"
integrity sha512-CtvoFaBI4hGXlXbaCHf8humajkbXhs39Nbh6MbNxtwJiCqxPy9iH3D3CCfXAvP0QvAAwmJUTK3+z9a++Kc4nkA==
dependencies:
"@firebase/component" "0.5.21"
"@firebase/util" "1.7.3"
"@firebase/component" "0.6.4"
"@firebase/util" "1.9.3"
node-fetch "2.6.7"
tslib "^2.1.0"
"@firebase/util@1.7.3":
version "1.7.3"
resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.7.3.tgz#e71640b6b2970b754f947235ceb10cba3f70e62c"
integrity sha512-wxNqWbqokF551WrJ9BIFouU/V5SL1oYCGx1oudcirdhadnQRFH5v1sjgGL7cUV/UsekSycygphdrF2lxBxOYKg==
"@firebase/util@1.9.3":
version "1.9.3"
resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.9.3.tgz#45458dd5cd02d90e55c656e84adf6f3decf4b7ed"
integrity sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==
dependencies:
tslib "^2.1.0"
"@firebase/webchannel-wrapper@0.8.1":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.8.1.tgz#5fbb3808677aa6b88bf79968237d3bb14595b1ba"
integrity sha512-CJW8vxt6bJaBeco2VnlJjmCmAkrrtIdf0GGKvpAB4J5gw8Gi0rHb+qsgKp6LsyS5W6ALPLawLs7phZmw02dvLw==
"@firebase/webchannel-wrapper@0.10.1":
version "0.10.1"
resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.1.tgz#60bb2aaf129f9e00621f8d698722ddba6ee1f8ac"
integrity sha512-Dq5rYfEpdeel0bLVN+nfD1VWmzCkK+pJbSjIawGE+RY4+NIJqhbUDDQjvV0NUK84fMfwxvtFoCtEe70HfZjFcw==
"@grpc/grpc-js@^1.3.2":
"@grpc/grpc-js@~1.7.0":
version "1.7.3"
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.7.3.tgz#f2ea79f65e31622d7f86d4b4c9ae38f13ccab99a"
integrity sha512-H9l79u4kJ2PVSxUNA08HMYAnUBLj9v6KjYQ7SQ71hOZcEXhShE/y5iQCesP8+6/Ik/7i2O0a10bPquIcYfufog==
@@ -2044,15 +2050,15 @@
yargs "^16.2.0"
"@grpc/proto-loader@^0.7.0":
version "0.7.3"
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.3.tgz#75a6f95b51b85c5078ac7394da93850c32d36bb8"
integrity sha512-5dAvoZwna2Py3Ef96Ux9jIkp3iZ62TUsV00p3wVBPNX5K178UbNi8Q7gQVqwXT1Yq9RejIGG9G2IPEo93T6RcA==
version "0.7.7"
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.7.tgz#d33677a77eea8407f7c66e2abd97589b60eb4b21"
integrity sha512-1TIeXOi8TuSCQprPItwoMymZXxWT0CPxUhkrkeCUH+D8U7QDwQ6b7SUz2MaLuWM2llT+J/TVFLmQI5KtML3BhQ==
dependencies:
"@types/long" "^4.0.1"
lodash.camelcase "^4.3.0"
long "^4.0.0"
protobufjs "^7.0.0"
yargs "^16.2.0"
yargs "^17.7.2"
"@hookform/resolvers@^2.6.0":
version "2.9.10"
@@ -3061,11 +3067,16 @@
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
"@types/node@*":
version "18.11.9"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4"
integrity sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==
"@types/node@>=12.12.47", "@types/node@>=13.7.0":
version "20.3.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.0.tgz#719498898d5defab83c3560f45d8498f58d11938"
integrity sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==
"@types/node@^17.0.23":
version "17.0.45"
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190"
@@ -4013,6 +4024,15 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"
clsx@^1.1.0, clsx@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
@@ -4905,6 +4925,11 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
estree-walker@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
estree-walker@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
@@ -5076,36 +5101,36 @@ find-up@^5.0.0:
path-exists "^4.0.0"
firebase@^9.12.1:
version "9.14.0"
resolved "https://registry.yarnpkg.com/firebase/-/firebase-9.14.0.tgz#407de4855092e607d3ee1fb222294ab2b45c4798"
integrity sha512-wePrsf7W33mhT7RVXQavragoAgXb/NDm22vuhwJXkprrQ2Y9alrEKC5LTAtLJL3P2dHdDmeylS6PLZwWPEE79A==
version "9.22.2"
resolved "https://registry.yarnpkg.com/firebase/-/firebase-9.22.2.tgz#8619bbdf38ab691d6b14da5d863370ab2c7ab6e5"
integrity sha512-eBXsaTzXPx3Y0QhuuluG/qR58tlOx2X/W0GKNoF004FcG9L2gHuvGu5/bIczvrPyfNOCqDF+I5I/kOQi8l9m0A==
dependencies:
"@firebase/analytics" "0.8.4"
"@firebase/analytics-compat" "0.1.17"
"@firebase/app" "0.8.4"
"@firebase/app-check" "0.5.17"
"@firebase/app-check-compat" "0.2.17"
"@firebase/app-compat" "0.1.39"
"@firebase/app-types" "0.8.1"
"@firebase/auth" "0.20.11"
"@firebase/auth-compat" "0.2.24"
"@firebase/database" "0.13.10"
"@firebase/database-compat" "0.2.10"
"@firebase/firestore" "3.7.3"
"@firebase/firestore-compat" "0.2.3"
"@firebase/functions" "0.8.8"
"@firebase/functions-compat" "0.2.8"
"@firebase/installations" "0.5.16"
"@firebase/installations-compat" "0.1.16"
"@firebase/messaging" "0.11.0"
"@firebase/messaging-compat" "0.1.21"
"@firebase/performance" "0.5.17"
"@firebase/performance-compat" "0.1.17"
"@firebase/remote-config" "0.3.15"
"@firebase/remote-config-compat" "0.1.16"
"@firebase/storage" "0.9.14"
"@firebase/storage-compat" "0.1.22"
"@firebase/util" "1.7.3"
"@firebase/analytics" "0.10.0"
"@firebase/analytics-compat" "0.2.6"
"@firebase/app" "0.9.12"
"@firebase/app-check" "0.8.0"
"@firebase/app-check-compat" "0.3.7"
"@firebase/app-compat" "0.2.12"
"@firebase/app-types" "0.9.0"
"@firebase/auth" "0.23.2"
"@firebase/auth-compat" "0.4.2"
"@firebase/database" "0.14.4"
"@firebase/database-compat" "0.3.4"
"@firebase/firestore" "3.12.2"
"@firebase/firestore-compat" "0.3.11"
"@firebase/functions" "0.10.0"
"@firebase/functions-compat" "0.3.5"
"@firebase/installations" "0.6.4"
"@firebase/installations-compat" "0.2.4"
"@firebase/messaging" "0.12.4"
"@firebase/messaging-compat" "0.2.4"
"@firebase/performance" "0.6.4"
"@firebase/performance-compat" "0.2.4"
"@firebase/remote-config" "0.4.4"
"@firebase/remote-config-compat" "0.2.4"
"@firebase/storage" "0.11.2"
"@firebase/storage-compat" "0.3.2"
"@firebase/util" "1.9.3"
firebaseui@^6.0.1:
version "6.0.2"
@@ -5564,7 +5589,7 @@ idb@7.0.1:
resolved "https://registry.yarnpkg.com/idb/-/idb-7.0.1.tgz#d2875b3a2f205d854ee307f6d196f246fea590a7"
integrity sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==
idb@^7.0.1:
idb@7.1.1, idb@^7.0.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b"
integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==
@@ -6309,9 +6334,9 @@ long@^4.0.0:
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
long@^5.0.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/long/-/long-5.2.1.tgz#e27595d0083d103d2fa2c20c7699f8e0c92b897f"
integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==
version "5.2.3"
resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1"
integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==
longest-streak@^3.0.0:
version "3.1.0"
@@ -6363,7 +6388,7 @@ magic-string@^0.22.4:
dependencies:
vlq "^0.2.2"
magic-string@^0.25.0, magic-string@^0.25.7:
magic-string@^0.25.0, magic-string@^0.25.3, magic-string@^0.25.7:
version "0.25.9"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
@@ -6910,10 +6935,10 @@ mlly@^1.2.0:
pkg-types "^1.0.3"
ufo "^1.1.2"
monaco-editor-auto-typings@^0.4.0:
version "0.4.3"
resolved "https://registry.yarnpkg.com/monaco-editor-auto-typings/-/monaco-editor-auto-typings-0.4.3.tgz#24498064ff876c641467815e65d54ae75f31cd7f"
integrity sha512-7lpiWHkg8eX2DRJGApaFq1wGn95Ute3Xv4PLz36qFyTytzz86irjxwMl00JnOOGX/R0eUbfuudbEtkQh2VK9Gg==
monaco-editor-auto-typings@^0.4.3:
version "0.4.4"
resolved "https://registry.yarnpkg.com/monaco-editor-auto-typings/-/monaco-editor-auto-typings-0.4.4.tgz#fd5320879949c420325107c5873acc445a58701a"
integrity sha512-vs5sPWO0V3pUX5BwEdCqroXNPzLjsVEqHciQ8DCQ+wtPrah3tn1oxwF4gW5cudTvmENGnbsjSrdLbmNRWFgstw==
monaco-editor@^0.33.0:
version "0.33.0"
@@ -7413,9 +7438,9 @@ protobufjs@^6.11.3:
long "^4.0.0"
protobufjs@^7.0.0:
version "7.1.2"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.1.2.tgz#a0cf6aeaf82f5625bffcf5a38b7cd2a7de05890c"
integrity sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==
version "7.2.3"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.3.tgz#01af019e40d9c6133c49acbb3ff9e30f4f0f70b2"
integrity sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
"@protobufjs/base64" "^1.1.2"
@@ -8066,7 +8091,7 @@ rifm@^0.12.1:
resolved "https://registry.yarnpkg.com/rifm/-/rifm-0.12.1.tgz#8fa77f45b7f1cda2a0068787ac821f0593967ac4"
integrity sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg==
rimraf@^3.0.0, rimraf@^3.0.2:
rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
@@ -8080,6 +8105,22 @@ rimraf@~2.6.2:
dependencies:
glob "^7.1.3"
rollup-plugin-inject@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rollup-plugin-inject/-/rollup-plugin-inject-3.0.2.tgz#e4233855bfba6c0c12a312fd6649dff9a13ee9f4"
integrity sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==
dependencies:
estree-walker "^0.6.1"
magic-string "^0.25.3"
rollup-pluginutils "^2.8.1"
rollup-plugin-node-polyfills@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/rollup-plugin-node-polyfills/-/rollup-plugin-node-polyfills-0.2.1.tgz#53092a2744837164d5b8a28812ba5f3ff61109fd"
integrity sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==
dependencies:
rollup-plugin-inject "^3.0.0"
rollup-plugin-terser@^7.0.0:
version "7.0.2"
resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
@@ -8090,6 +8131,13 @@ rollup-plugin-terser@^7.0.0:
serialize-javascript "^4.0.0"
terser "^5.0.0"
rollup-pluginutils@^2.8.1:
version "2.8.2"
resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e"
integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==
dependencies:
estree-walker "^0.6.1"
rollup@^2.43.1:
version "2.79.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
@@ -8170,15 +8218,6 @@ seedrandom@^3.0.5:
resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7"
integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==
selenium-webdriver@4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.5.0.tgz#7e20d0fc038177970dad81159950c12f7411ac0d"
integrity sha512-9mSFii+lRwcnT2KUAB1kqvx6+mMiiQHH60Y0VUtr3kxxi3oZ3CV3B8e2nuJ7T4SPb+Q6VA0swswe7rYpez07Bg==
dependencies:
jszip "^3.10.0"
tmp "^0.2.1"
ws ">=8.7.0"
semver@7.x, semver@^7.3.2, semver@^7.3.7:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
@@ -8419,7 +8458,7 @@ string-natural-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
string-width@^4.1.0, string-width@^4.2.0:
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -8714,13 +8753,6 @@ tinyspy@^2.1.0:
resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.1.1.tgz#9e6371b00c259e5c5b301917ca18c01d40ae558c"
integrity sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==
tmp@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==
dependencies:
rimraf "^3.0.0"
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
@@ -8818,11 +8850,16 @@ tslib@^1.8.1:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0:
tslib@^2.0.1, tslib@^2.4.0:
version "2.4.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==
tslib@^2.1.0:
version "2.5.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913"
integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==
tss-react@^4.4.4:
version "4.4.4"
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-4.4.4.tgz#12207842dfc58676a9f4d0f532741257428a78e7"
@@ -9571,11 +9608,6 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
ws@>=8.7.0:
version "8.11.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143"
integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==
xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
@@ -9611,7 +9643,7 @@ yargs-parser@^20.2.2:
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
yargs-parser@^21.0.1:
yargs-parser@^21.0.1, yargs-parser@^21.1.1:
version "21.1.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
@@ -9629,6 +9661,19 @@ yargs@^16.2.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"
yargs@^17.7.2:
version "17.7.2"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
dependencies:
cliui "^8.0.1"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.3"
y18n "^5.0.5"
yargs-parser "^21.1.1"
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"