mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-16 11:47:50 +01:00
v2.6.1 – Bug fixes (#743)
* Bump ejs from 3.1.6 to 3.1.8
Bumps [ejs](https://github.com/mde/ejs) from 3.1.6 to 3.1.8.
- [Release notes](https://github.com/mde/ejs/releases)
- [Changelog](https://github.com/mde/ejs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mde/ejs/compare/v3.1.6...v3.1.8)
---
updated-dependencies:
- dependency-name: ejs
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
* Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)
---
updated-dependencies:
- dependency-name: minimist
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
* Bump tmpl from 1.0.4 to 1.0.5
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)
---
updated-dependencies:
- dependency-name: tmpl
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
* Bump protobufjs from 6.11.2 to 6.11.3
Bumps [protobufjs](https://github.com/protobufjs/protobuf.js) from 6.11.2 to 6.11.3.
- [Release notes](https://github.com/protobufjs/protobuf.js/releases)
- [Changelog](https://github.com/protobufjs/protobuf.js/blob/v6.11.3/CHANGELOG.md)
- [Commits](https://github.com/protobufjs/protobuf.js/compare/v6.11.2...v6.11.3)
---
updated-dependencies:
- dependency-name: protobufjs
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
* fix(rich-text-editor): fix dark mode ui appearance (#696)
* fix(rich-text-editor): fix dark mode ui appearance
* Update src/components/RichTextEditor.tsx
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* Update src/components/RichTextEditor.tsx
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* Update src/components/RichTextEditor.tsx
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* Update src/components/RichTextEditor.tsx
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* Update src/components/RichTextEditor.tsx
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* Update src/components/RichTextEditor.tsx
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* Update src/components/RichTextEditor.tsx
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* Update src/theme/RichTextEditorDarkCSS.tsx
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* Update src/theme/RichTextEditorLightCSS.tsx
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* fix(rich-text-editor): add stylings to dropdown
* fix(rich-text-editor): add toolbar stylings
* fix(rich-text-editor): reset hover&focus bg
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* update date & time filter operators for clarity
* Action field: prevent selecting self as required field (fixes ROWY-551)
* Date & Time: only show date for date filters
* move fullScreenButton to be shared, remove md settings
* bundle-analyzer
* Leaf icon: use mdi-material-ui
* Feat: Percentage field color customization (#692)
* feat(percentage-c11n): convert to table cell
* feat(percentage-c11n): add logic to default configs
* feat(percentage-c11n): add color picker to settings
* feat(percentage-c11n): change default colors
* feat(percentage-c11n): fix button text color
* feat(percentage-c11n): add labels to settings
* feat(percentage-c11n): add preview section
* feat(percentage-c11n): fix cache issues with debouncing
* feat(percentage-c11n): add width responsiveness to color picker
* feat(percentage-c11n): fix responsiveness issues
* feat(percentage-c11n): add checkbox, refactor a little
* feat(percentage-c11n): convert data type to array
* feat(percentage-c11n): refactor config states
* feat(percentage-c11n): fix defaults
* feat(percentage-c11n): add basic cell without bg
* feat(percentage-c11n): remove collapse
* feat(percentage-c11n): refactor checkStates
* feat(percentage-c11n): add grid layout
* feat(percentage-c11n): chore conventions
* feat(percentage-c11n): add default theme color to sidedrawer
* remove redundant fragment
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* fix text color in preview
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* fix: change state to derived state
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* fix: review suggestions
* fix: remove redundant change call
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* fix(percentage-c11n): remove redundant dependencies
Co-authored-by: Shams <shams.mosowi@gmail.com>
Co-authored-by: Sidney Alcantara <sidney@sidney.me>
* extend callable timeout to over 9minutes
* fix timeout value
* fix page loading with white screen while system is in dark mode
* Revert "bundle-analyzer"
This reverts commit dd214b96e4.
* fix nav items not accessible with Tab
* Percentage: don’t display if value null or undefined
* fix NavDrawer causing compile to fail
* show text field if collections array is empy
* column ids
* row ID
* fix create table showing empty dropdown for collections
* fix row not writing to db once all required fields are written
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Han Tuerker <46192266+htuerker@users.noreply.github.com>
Co-authored-by: shamsmosowi <shams.mosowi@gmail.com>
This commit is contained in:
@@ -75,6 +75,12 @@
|
||||
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap"
|
||||
/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
}
|
||||
</style>
|
||||
|
||||
<title>Rowy</title>
|
||||
|
||||
<meta name="title" content="Rowy – GCP as easy as ABC" />
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import SvgIcon, { SvgIconProps } from "@mui/material/SvgIcon";
|
||||
import { mdiLeaf } from "@mdi/js";
|
||||
|
||||
export default function Leaf(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d={mdiLeaf} />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
@@ -88,6 +88,12 @@ export { LanguageMarkdownOutline as Markdown };
|
||||
import { TableRow } from "mdi-material-ui";
|
||||
export { TableRow as Row };
|
||||
|
||||
import { Table } from "mdi-material-ui";
|
||||
export { Table };
|
||||
|
||||
import { Leaf } from "mdi-material-ui";
|
||||
export { Leaf };
|
||||
|
||||
export * from "./AddRow";
|
||||
export * from "./AddRowTop";
|
||||
export * from "./ChevronDown";
|
||||
|
||||
@@ -346,16 +346,6 @@ export const updateFieldAtom = atom(
|
||||
update[tableSettings.auditFieldUpdatedBy || "_updatedBy"] = auditValue;
|
||||
}
|
||||
|
||||
// Check for required fields
|
||||
const requiredFields = ignoreRequiredFields
|
||||
? []
|
||||
: tableColumnsOrdered
|
||||
.filter((column) => column.config?.required)
|
||||
.map((column) => column.key);
|
||||
const missingRequiredFields = ignoreRequiredFields
|
||||
? []
|
||||
: requiredFields.filter((field) => row[field] === undefined);
|
||||
|
||||
// Apply field update
|
||||
if (!deleteField) {
|
||||
// Check for equality. If updated value is same as current, skip update
|
||||
@@ -367,6 +357,17 @@ export const updateFieldAtom = atom(
|
||||
_set(update, fieldName, value);
|
||||
}
|
||||
|
||||
// Check for required fields
|
||||
const newRowValues = updateRowData(cloneDeep(row), update);
|
||||
const requiredFields = ignoreRequiredFields
|
||||
? []
|
||||
: tableColumnsOrdered
|
||||
.filter((column) => column.config?.required)
|
||||
.map((column) => column.key);
|
||||
const missingRequiredFields = ignoreRequiredFields
|
||||
? []
|
||||
: requiredFields.filter((field) => newRowValues[field] === undefined);
|
||||
|
||||
// If it’s a local row, update the row in rowsLocal
|
||||
if (isLocalRow) {
|
||||
set(tableRowsLocalAtom, {
|
||||
@@ -379,12 +380,11 @@ export const updateFieldAtom = atom(
|
||||
// If it has no missingRequiredFields, also write to db
|
||||
// And write entire row to handle the case where it doesn’t exist in db yet
|
||||
if (missingRequiredFields.length === 0) {
|
||||
const rowValues = updateRowData(cloneDeep(row), update);
|
||||
if (deleteField) unset(rowValues, fieldName);
|
||||
if (deleteField) unset(newRowValues, fieldName);
|
||||
|
||||
await updateRowDb(
|
||||
row._rowy_ref.path,
|
||||
omitRowyFields(rowValues),
|
||||
omitRowyFields(newRowValues),
|
||||
deleteField ? [fieldName] : []
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { ResizeBottomRight } from "@src/assets/icons";
|
||||
import useMonacoCustomizations, {
|
||||
IUseMonacoCustomizationsProps,
|
||||
} from "./useMonacoCustomizations";
|
||||
import FullScreenButton from "./FullScreenButton";
|
||||
import FullScreenButton from "@src/components/FullScreenButton";
|
||||
import { spreadSx } from "@src/utils/ui";
|
||||
|
||||
export interface ICodeEditorProps
|
||||
@@ -73,6 +73,7 @@ export default function CodeEditor({
|
||||
return (
|
||||
<TrapFocus open={fullScreen}>
|
||||
<Box
|
||||
component="div"
|
||||
sx={[boxSx, ...spreadSx(containerProps?.sx)]}
|
||||
style={fullScreen ? { height: "100%" } : {}}
|
||||
>
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ResizeBottomRight } from "@src/assets/icons";
|
||||
import useMonacoCustomizations, {
|
||||
IUseMonacoCustomizationsProps,
|
||||
} from "./useMonacoCustomizations";
|
||||
import FullScreenButton from "./FullScreenButton";
|
||||
import FullScreenButton from "@src/components/FullScreenButton";
|
||||
import { spreadSx } from "@src/utils/ui";
|
||||
|
||||
export interface IDiffEditorProps
|
||||
@@ -64,6 +64,7 @@ export default function DiffEditor({
|
||||
return (
|
||||
<TrapFocus open={fullScreen}>
|
||||
<Box
|
||||
component="div"
|
||||
sx={[boxSx, ...spreadSx(containerProps?.sx)]}
|
||||
style={fullScreen ? { height: "100%" } : {}}
|
||||
>
|
||||
|
||||
76
src/components/ColorPickerInput.tsx
Normal file
76
src/components/ColorPickerInput.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import { useState, useRef, MutableRefObject, useLayoutEffect } from "react";
|
||||
import { Box, useTheme } from "@mui/material";
|
||||
|
||||
import { Color, ColorPicker } from "react-color-palette";
|
||||
|
||||
const useResponsiveWidth = (): [
|
||||
width: number,
|
||||
setRef: MutableRefObject<HTMLElement | null>
|
||||
] => {
|
||||
const ref = useRef(null);
|
||||
const [width, setWidth] = useState(0);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!ref || !ref.current) {
|
||||
return;
|
||||
}
|
||||
const resizeObserver = new ResizeObserver((targets) => {
|
||||
const { width: currentWidth } = targets[0].contentRect;
|
||||
setWidth(currentWidth);
|
||||
});
|
||||
|
||||
resizeObserver.observe(ref.current);
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return [width, ref];
|
||||
};
|
||||
|
||||
export interface IColorPickerProps {
|
||||
value: Color;
|
||||
onChangeComplete: (color: Color) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export default function ColorPickerInput({
|
||||
value,
|
||||
onChangeComplete,
|
||||
disabled = false,
|
||||
}: IColorPickerProps) {
|
||||
const [localValue, setLocalValue] = useState(value);
|
||||
const [width, setRef] = useResponsiveWidth();
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Box
|
||||
ref={setRef}
|
||||
sx={[
|
||||
{
|
||||
padding: theme.spacing(1.5),
|
||||
paddingTop: theme.spacing(1),
|
||||
transitionDuration: 0,
|
||||
"& .rcp": {
|
||||
border: "none",
|
||||
"& .rcp-saturation": {
|
||||
borderRadius: theme.spacing(0.5),
|
||||
},
|
||||
"& .rcp-body": {
|
||||
boxSizing: "unset",
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<ColorPicker
|
||||
width={width}
|
||||
height={150}
|
||||
color={localValue}
|
||||
onChange={(color) => setLocalValue(color)}
|
||||
onChangeComplete={onChangeComplete}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -124,8 +124,9 @@ export default function ColumnMenu() {
|
||||
};
|
||||
|
||||
const localViewActions: IMenuContentsProps["menuItems"] = [
|
||||
{ type: "subheader" },
|
||||
{ type: "subheader", key: "subLocalView" },
|
||||
{
|
||||
key: "sortDesc",
|
||||
label: "Sort: descending",
|
||||
activeLabel: "Remove sort: descending",
|
||||
icon: <ArrowDownwardIcon />,
|
||||
@@ -139,6 +140,7 @@ export default function ColumnMenu() {
|
||||
disabled: column.type === FieldType.id,
|
||||
},
|
||||
{
|
||||
key: "sortAsc",
|
||||
label: "Sort: ascending",
|
||||
activeLabel: "Remove sort: ascending",
|
||||
icon: <ArrowUpwardIcon />,
|
||||
@@ -152,6 +154,7 @@ export default function ColumnMenu() {
|
||||
disabled: column.type === FieldType.id,
|
||||
},
|
||||
{
|
||||
key: "hide",
|
||||
label: "Hide",
|
||||
icon: <VisibilityIcon />,
|
||||
onClick: () => {
|
||||
@@ -168,6 +171,7 @@ export default function ColumnMenu() {
|
||||
disabled: !updateUserSettings,
|
||||
},
|
||||
{
|
||||
key: "filter",
|
||||
label: "Filter…",
|
||||
icon: <FilterIcon />,
|
||||
onClick: () => {
|
||||
@@ -187,9 +191,10 @@ export default function ColumnMenu() {
|
||||
];
|
||||
|
||||
const configActions: IMenuContentsProps["menuItems"] = [
|
||||
{ type: "subheader" },
|
||||
{ type: "subheader", key: "subActionsConfig" },
|
||||
{
|
||||
label: "Lock",
|
||||
key: "lock",
|
||||
activeLabel: "Unlock",
|
||||
icon: <LockOpenIcon />,
|
||||
activeIcon: <LockIcon />,
|
||||
@@ -204,6 +209,7 @@ export default function ColumnMenu() {
|
||||
},
|
||||
{
|
||||
label: "Disable resize",
|
||||
key: "disableResize",
|
||||
activeLabel: "Enable resize",
|
||||
icon: <CellResizeIcon />,
|
||||
onClick: () => {
|
||||
@@ -217,6 +223,7 @@ export default function ColumnMenu() {
|
||||
},
|
||||
{
|
||||
label: "Freeze",
|
||||
key: "freeze",
|
||||
activeLabel: "Unfreeze",
|
||||
icon: <FreezeIcon />,
|
||||
activeIcon: <UnfreezeIcon />,
|
||||
@@ -229,6 +236,7 @@ export default function ColumnMenu() {
|
||||
// { type: "subheader" },
|
||||
{
|
||||
label: "Rename…",
|
||||
key: "rename",
|
||||
icon: <EditIcon />,
|
||||
onClick: () => {
|
||||
openColumnModal({ type: "name", columnKey: column.key });
|
||||
@@ -237,6 +245,7 @@ export default function ColumnMenu() {
|
||||
},
|
||||
{
|
||||
label: `Edit type: ${getFieldProp("name", column.type)}…`,
|
||||
key: "editType",
|
||||
// This is based on the cell type
|
||||
icon: getFieldProp("icon", column.type),
|
||||
onClick: () => {
|
||||
@@ -246,6 +255,7 @@ export default function ColumnMenu() {
|
||||
},
|
||||
{
|
||||
label: `Column config…`,
|
||||
key: "columConfig",
|
||||
icon: <SettingsIcon />,
|
||||
onClick: () => {
|
||||
openColumnModal({ type: "config", columnKey: column.key });
|
||||
@@ -299,8 +309,9 @@ export default function ColumnMenu() {
|
||||
}
|
||||
};
|
||||
const derivativeActions: IMenuContentsProps["menuItems"] = [
|
||||
{ type: "subheader" },
|
||||
{ type: "subheader", key: "sub-derivative" },
|
||||
{
|
||||
key: "evaluateAll",
|
||||
label: altPress ? "Evaluate all" : "Evaluate all…",
|
||||
icon: <EvalIcon />,
|
||||
onClick: altPress
|
||||
@@ -323,9 +334,10 @@ export default function ColumnMenu() {
|
||||
];
|
||||
|
||||
const columnActions: IMenuContentsProps["menuItems"] = [
|
||||
{ type: "subheader" },
|
||||
{ type: "subheader", key: "subActions" },
|
||||
{
|
||||
label: "Insert to the left…",
|
||||
key: "insertLeft",
|
||||
icon: <ColumnPlusBeforeIcon />,
|
||||
onClick: () => {
|
||||
openColumnModal({ type: "new", index: column.index - 1 });
|
||||
@@ -334,6 +346,7 @@ export default function ColumnMenu() {
|
||||
},
|
||||
{
|
||||
label: "Insert to the right…",
|
||||
key: "insertRight",
|
||||
icon: <ColumnPlusAfterIcon />,
|
||||
onClick: () => {
|
||||
openColumnModal({ type: "new", index: column.index + 1 });
|
||||
@@ -342,6 +355,7 @@ export default function ColumnMenu() {
|
||||
},
|
||||
{
|
||||
label: `Delete column${altPress ? "" : "…"}`,
|
||||
key: "delete",
|
||||
icon: <ColumnRemoveIcon />,
|
||||
onClick: altPress
|
||||
? handleDeleteColumn
|
||||
|
||||
@@ -4,6 +4,7 @@ import { MenuItem, ListItemIcon, ListSubheader, Divider } from "@mui/material";
|
||||
|
||||
export interface IMenuContentsProps {
|
||||
menuItems: {
|
||||
key: string;
|
||||
type?: string;
|
||||
label?: string;
|
||||
activeLabel?: string;
|
||||
@@ -36,6 +37,7 @@ export default function MenuContents({ menuItems }: IMenuContentsProps) {
|
||||
return (
|
||||
<MenuItem
|
||||
key={index}
|
||||
id={`column-menu-item-${item.key}`}
|
||||
onClick={item.onClick}
|
||||
color={item.color}
|
||||
selected={item.active}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { styled, useTheme } from "@mui/material";
|
||||
import { GlobalStyles } from "tss-react";
|
||||
import { alpha, styled, useTheme } from "@mui/material";
|
||||
import { Editor } from "@tinymce/tinymce-react";
|
||||
|
||||
// TinyMCE so the global var exists
|
||||
@@ -10,7 +10,9 @@ import "tinymce/themes/silver";
|
||||
// Toolbar icons
|
||||
import "tinymce/icons/default";
|
||||
// Editor styles
|
||||
import "tinymce/skins/ui/oxide/skin.min.css";
|
||||
/* eslint import/no-webpack-loader-syntax: off */
|
||||
import skinCss from "!!raw-loader!tinymce/skins/ui/oxide/skin.min.css";
|
||||
import skinDarkCss from "!!raw-loader!tinymce/skins/ui/oxide-dark/skin.min.css";
|
||||
// Content styles, including inline UI like fake cursors
|
||||
/* eslint import/no-webpack-loader-syntax: off */
|
||||
import contentCss from "!!raw-loader!tinymce/skins/content/default/content.min.css";
|
||||
@@ -55,7 +57,32 @@ const Styles = styled("div", {
|
||||
},
|
||||
"& .tox-edit-area__iframe": { colorScheme: "auto" },
|
||||
|
||||
"& .tox-toolbar__group": { border: "none !important" },
|
||||
"& .tox-toolbar__group": {
|
||||
border: "none !important",
|
||||
"& .tox-tbtn": {
|
||||
"&:hover:": {
|
||||
backgroundColor: "inherit",
|
||||
},
|
||||
"&:focus": {
|
||||
backgroundColor: "inherit",
|
||||
},
|
||||
},
|
||||
"& .tox-tbtn__select-chevron": {
|
||||
transition: theme.transitions.create("transform", {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
},
|
||||
"& .tox-tbtn--select": {
|
||||
"& .tox-tbtn__select-chevron": {
|
||||
transform: "none",
|
||||
},
|
||||
},
|
||||
"& .tox-tbtn--active": {
|
||||
"& .tox-tbtn__select-chevron": {
|
||||
transform: "rotate(180deg)",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"& .tox-tbtn": {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
@@ -118,7 +145,74 @@ export default function RichTextEditor({
|
||||
|
||||
return (
|
||||
<Styles focus={focus} disabled={disabled}>
|
||||
<style>{theme.palette.mode === "dark" ? skinDarkCss : skinCss}</style>
|
||||
<GlobalStyles
|
||||
styles={{
|
||||
".tox": {
|
||||
"& .tox-menu.tox-menu, &.tox-tinymce-aux .tox-toolbar__overflow.tox-toolbar__overflow":
|
||||
{
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
backgroundImage:
|
||||
"linear-gradient(rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.12))", // elevation 8
|
||||
boxShadow: theme.shadows[8],
|
||||
border: "none",
|
||||
borderRadius: (theme.shape.borderRadius as number) * 2,
|
||||
},
|
||||
|
||||
"& .tox-collection--list": {
|
||||
"& .tox-collection__group.tox-collection__group": {
|
||||
padding: theme.spacing(0.5),
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0,
|
||||
},
|
||||
"& .tox-collection__item": {
|
||||
padding: theme.spacing(0.5),
|
||||
marginLeft: theme.spacing(0.5),
|
||||
marginRight: theme.spacing(0.5),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
|
||||
"& .tox-collection__item--enabled": {
|
||||
backgroundColor: theme.palette.action.hover + " !important",
|
||||
position: "relative",
|
||||
"&::before": {
|
||||
content: '""',
|
||||
display: "block",
|
||||
position: "absolute",
|
||||
top: theme.spacing(1),
|
||||
bottom: theme.spacing(1),
|
||||
left: 0,
|
||||
width: theme.spacing(0.3),
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
},
|
||||
|
||||
"& .tox-collection__item--active": {
|
||||
backgroundColor:
|
||||
alpha(
|
||||
theme.palette.primary.main,
|
||||
theme.palette.action.selectedOpacity
|
||||
) + "!important",
|
||||
},
|
||||
"& .tox-collection__item-checkmark": {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
|
||||
"&.tox-tinymce-aux .tox-toolbar__overflow.tox-toolbar__overflow": {
|
||||
padding: theme.spacing(0.5, 0),
|
||||
},
|
||||
"& .tox-tbtn.tox-tbtn": {
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
margin: 0,
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<Editor
|
||||
key={theme.palette.mode}
|
||||
disabled={disabled}
|
||||
init={{
|
||||
skin: false,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { sortBy } from "lodash-es";
|
||||
|
||||
import MultiSelect from "@rowy/multiselect";
|
||||
import { Grid } from "@mui/material";
|
||||
import LeafIcon from "@src/assets/icons/Leaf";
|
||||
import { Leaf as LeafIcon } from "@src/assets/icons";
|
||||
|
||||
import { CLOUD_RUN_REGIONS } from "@src/constants/regions";
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ export default function DraggableHeaderRenderer({
|
||||
return (
|
||||
<Grid
|
||||
key={column.key}
|
||||
id={`column-header-${column.key}`}
|
||||
ref={(ref) => {
|
||||
dragRef(ref);
|
||||
dropRef(ref);
|
||||
@@ -213,6 +214,7 @@ export default function DraggableHeaderRenderer({
|
||||
<IconButton
|
||||
size="small"
|
||||
aria-label={`Column settings for ${column.name as string}`}
|
||||
id={`column-settings-${column.key}`}
|
||||
color="inherit"
|
||||
onClick={handleOpenMenu}
|
||||
ref={buttonRef}
|
||||
|
||||
@@ -24,6 +24,7 @@ export default function TableRow(props: RowRendererProps<any>) {
|
||||
return (
|
||||
<Row
|
||||
key={props.row._rowy_ref.path}
|
||||
id={`row-${props.row._rowy_ref.path}`}
|
||||
onContextMenu={handleContextMenu}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -232,7 +232,10 @@ export default function TableSettingsDialog() {
|
||||
})),
|
||||
["section", "label"]
|
||||
),
|
||||
Array.isArray(collections) ? collections.filter((x) => x !== CONFIG) : null
|
||||
Array.isArray(collections) &&
|
||||
collections.filter((x) => x !== CONFIG).length > 0
|
||||
? collections.filter((x) => x !== CONFIG)
|
||||
: null
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import { Suspense, createElement } from "react";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
|
||||
import {
|
||||
Grid,
|
||||
MenuItem,
|
||||
ListItemText,
|
||||
Divider,
|
||||
ListSubheader,
|
||||
Typography,
|
||||
TextField,
|
||||
InputLabel,
|
||||
} from "@mui/material";
|
||||
|
||||
import ColumnSelect from "@src/components/Table/ColumnSelect";
|
||||
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";
|
||||
@@ -30,6 +35,45 @@ export default function FilterInputs({
|
||||
}: IFilterInputsProps) {
|
||||
const columnType = selectedColumn ? getFieldType(selectedColumn) : null;
|
||||
|
||||
const operators = availableFilters?.operators ?? [];
|
||||
const renderedOperatorItems = operators.map((operator) => (
|
||||
<MenuItem key={operator.value} value={operator.value}>
|
||||
<ListItemText style={{ flexShrink: 0 }}>{operator.label}</ListItemText>
|
||||
|
||||
{operator.secondaryLabel && (
|
||||
<Typography
|
||||
variant="inherit"
|
||||
color="text.disabled"
|
||||
sx={{ overflow: "hidden", textOverflow: "ellipsis", ml: 1 }}
|
||||
>
|
||||
{operator.secondaryLabel}
|
||||
</Typography>
|
||||
)}
|
||||
</MenuItem>
|
||||
));
|
||||
|
||||
// Insert ListSubheader components in between groups of operators
|
||||
for (let i = 0; i < operators.length; i++) {
|
||||
if (!operators[i].group) continue;
|
||||
|
||||
if (i === 0 || operators[i - 1].group !== operators[i].group) {
|
||||
renderedOperatorItems.splice(
|
||||
i === 0 ? 0 : i + 1,
|
||||
0,
|
||||
<ListSubheader key={operators[i].group}>
|
||||
{operators[i].group}
|
||||
</ListSubheader>
|
||||
);
|
||||
|
||||
if (i > 0)
|
||||
renderedOperatorItems.splice(
|
||||
i + 1,
|
||||
0,
|
||||
<Divider key={`divider-${operators[i].group}`} variant="middle" />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid container spacing={2} sx={{ mb: 3 }}>
|
||||
<Grid item xs={4}>
|
||||
@@ -65,29 +109,13 @@ export default function FilterInputs({
|
||||
<MenuItem disabled value="" style={{ display: "none" }}>
|
||||
Select operator
|
||||
</MenuItem>
|
||||
{availableFilters?.operators.map((operator) => (
|
||||
<MenuItem key={operator.value} value={operator.value}>
|
||||
<ListItemText style={{ flexShrink: 0 }}>
|
||||
{operator.label}
|
||||
</ListItemText>
|
||||
|
||||
{operator.secondaryLabel && (
|
||||
<Typography
|
||||
variant="inherit"
|
||||
color="text.disabled"
|
||||
style={{ overflow: "hidden", textOverflow: "ellipsis" }}
|
||||
>
|
||||
{operator.secondaryLabel}
|
||||
</Typography>
|
||||
)}
|
||||
</MenuItem>
|
||||
))}
|
||||
{renderedOperatorItems}
|
||||
</TextField>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={4}>
|
||||
<Grid item xs={4} key={query.key + query.operator}>
|
||||
{query.key && query.operator && (
|
||||
<>
|
||||
<ErrorBoundary FallbackComponent={InlineErrorFallback}>
|
||||
<InputLabel
|
||||
variant="filled"
|
||||
id={`filters-label-${query.key}`}
|
||||
@@ -111,10 +139,11 @@ export default function FilterInputs({
|
||||
setQuery((query) => ({ ...query, value }));
|
||||
},
|
||||
disabled,
|
||||
operator: query.operator,
|
||||
}
|
||||
)}
|
||||
</Suspense>
|
||||
</>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -75,8 +75,8 @@ export default function FiltersPopover({
|
||||
);
|
||||
|
||||
const formattedValue = availableFilters?.valueFormatter
|
||||
? availableFilters.valueFormatter(filter.value)
|
||||
: filter.value;
|
||||
? availableFilters.valueFormatter(filter.value, filter.operator)
|
||||
: filter.value.toString();
|
||||
|
||||
return (
|
||||
<Chip
|
||||
|
||||
@@ -93,10 +93,9 @@ export default function ActionFab({
|
||||
return resp;
|
||||
};
|
||||
const handleCallableAction = async (data: any) => {
|
||||
const resp: any = await httpsCallable(
|
||||
firebaseFunctions,
|
||||
callableName
|
||||
)(data);
|
||||
const resp: any = await httpsCallable(firebaseFunctions, callableName, {
|
||||
timeout: 550000,
|
||||
})(data);
|
||||
return resp.data;
|
||||
};
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ const CodeEditor = lazy(
|
||||
import("@src/components/CodeEditor" /* webpackChunkName: "CodeEditor" */)
|
||||
);
|
||||
|
||||
const Settings = ({ config, onChange }: ISettingsProps) => {
|
||||
const Settings = ({ config, onChange, fieldName }: ISettingsProps) => {
|
||||
const [projectId] = useAtom(projectIdAtom, globalScope);
|
||||
const [roles] = useAtom(projectRolesAtom, globalScope);
|
||||
const [settings] = useAtom(projectSettingsAtom, globalScope);
|
||||
@@ -77,10 +77,12 @@ const Settings = ({ config, onChange }: ISettingsProps) => {
|
||||
// ? ["requirements", "friction", "action", "undo", "customization"]
|
||||
// : ["requirements", "friction", "action", "customization"];
|
||||
|
||||
const columnOptions = tableColumnsOrdered.map((c) => ({
|
||||
label: c.name,
|
||||
value: c.key,
|
||||
}));
|
||||
const columnOptions = tableColumnsOrdered
|
||||
.map((c) => ({
|
||||
label: c.name,
|
||||
value: c.key,
|
||||
}))
|
||||
.filter((c) => c.value !== fieldName);
|
||||
|
||||
const formattedParamsJson = stringify(
|
||||
Array.isArray(config.params) ? config.params : [],
|
||||
@@ -145,6 +147,7 @@ const Settings = ({ config, onChange }: ISettingsProps) => {
|
||||
<Grid item xs={12} sm={6}>
|
||||
<MultiSelect
|
||||
label="Required roles"
|
||||
labelPlural="roles"
|
||||
options={roles ?? []}
|
||||
value={config.requiredRoles ?? []}
|
||||
onChange={onChange("requiredRoles")}
|
||||
@@ -158,6 +161,7 @@ const Settings = ({ config, onChange }: ISettingsProps) => {
|
||||
<Grid item xs={12} sm={6}>
|
||||
<MultiSelect
|
||||
label="Required fields"
|
||||
labelPlural="fields"
|
||||
options={columnOptions}
|
||||
value={config.requiredFields ?? []}
|
||||
onChange={onChange("requiredFields")}
|
||||
|
||||
14
src/components/fields/DateTime/FilterCustomInput.tsx
Normal file
14
src/components/fields/DateTime/FilterCustomInput.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { IFilterCustomInputProps } from "@src/components/fields/types";
|
||||
import DateTimeInput from "./SideDrawerField";
|
||||
import DateInput from "@src/components/fields/Date/SideDrawerField";
|
||||
|
||||
export default function FilterCustomInput({
|
||||
onChange,
|
||||
operator,
|
||||
...props
|
||||
}: IFilterCustomInputProps) {
|
||||
if (operator && operator.startsWith("date-"))
|
||||
return <DateInput {...(props as any)} onChange={onChange} />;
|
||||
|
||||
return <DateTimeInput {...(props as any)} onChange={onChange} />;
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import { getFieldId } from "@src/components/SideDrawer/utils";
|
||||
|
||||
export interface IDateProps extends ISideDrawerFieldProps {}
|
||||
|
||||
export default function Date_({
|
||||
export default function DateTime({
|
||||
column,
|
||||
value,
|
||||
onChange,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { format } from "date-fns";
|
||||
import { DATE_TIME_FORMAT } from "@src/constants/dates";
|
||||
import { DATE_TIME_FORMAT, DATE_FORMAT } from "@src/constants/dates";
|
||||
import { IFilterOperator } from "@src/components/fields/types";
|
||||
|
||||
export const filterOperators: IFilterOperator[] = [
|
||||
@@ -7,60 +7,75 @@ export const filterOperators: IFilterOperator[] = [
|
||||
label: "equals",
|
||||
secondaryLabel: "==",
|
||||
value: "time-minute-equal",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "not equal to",
|
||||
secondaryLabel: "!=",
|
||||
value: "!=",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "before",
|
||||
secondaryLabel: "<",
|
||||
value: "<",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "after",
|
||||
secondaryLabel: ">",
|
||||
value: ">",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "before or at",
|
||||
secondaryLabel: "<=",
|
||||
value: "<=",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "at or after",
|
||||
secondaryLabel: ">=",
|
||||
value: ">=",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "where date is is",
|
||||
label: "where date is",
|
||||
secondaryLabel: "date ==",
|
||||
value: "date-equal",
|
||||
group: "Date",
|
||||
},
|
||||
{
|
||||
label: "where date is before",
|
||||
secondaryLabel: "date <",
|
||||
value: "date-before",
|
||||
group: "Date",
|
||||
},
|
||||
{
|
||||
label: "where date is after",
|
||||
secondaryLabel: "date >",
|
||||
value: "date-after",
|
||||
group: "Date",
|
||||
},
|
||||
{
|
||||
label: "where date is before or on",
|
||||
secondaryLabel: "date <=",
|
||||
value: "date-before-equal",
|
||||
group: "Date",
|
||||
},
|
||||
{
|
||||
label: "where date is on or after",
|
||||
secondaryLabel: "date >=",
|
||||
value: "date-after-equal",
|
||||
group: "Date",
|
||||
},
|
||||
];
|
||||
|
||||
export const valueFormatter = (value: any) => {
|
||||
if (value && value.toDate) return format(value.toDate(), DATE_TIME_FORMAT);
|
||||
export const valueFormatter = (value: any, operator: string) => {
|
||||
if (value && value.toDate)
|
||||
return format(
|
||||
value.toDate(),
|
||||
operator.startsWith("date") ? DATE_FORMAT : DATE_TIME_FORMAT
|
||||
);
|
||||
return "";
|
||||
};
|
||||
|
||||
@@ -21,6 +21,12 @@ const SideDrawerField = lazy(
|
||||
const Settings = lazy(
|
||||
() => import("./Settings" /* webpackChunkName: "Settings-DateTime" */)
|
||||
);
|
||||
const FilterCustomInput = lazy(
|
||||
() =>
|
||||
import(
|
||||
"./FilterCustomInput" /* webpackChunkName: "FilterCustomInput-DateTime" */
|
||||
)
|
||||
);
|
||||
|
||||
export const config: IFieldConfig = {
|
||||
type: FieldType.dateTime,
|
||||
@@ -34,7 +40,11 @@ export const config: IFieldConfig = {
|
||||
TableCell: withHeavyCell(BasicCell, TableCell),
|
||||
TableEditor: NullEditor as any,
|
||||
SideDrawerField,
|
||||
filter: { operators: filterOperators, valueFormatter },
|
||||
filter: {
|
||||
operators: filterOperators,
|
||||
valueFormatter,
|
||||
customInput: FilterCustomInput,
|
||||
},
|
||||
settings: Settings,
|
||||
csvImportParser: (value) => parseJSON(value).getTime(),
|
||||
csvExportFormatter: (value: any, config?: any) =>
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { ISettingsProps } from "@src/components/fields/types";
|
||||
import MultiSelect from "@rowy/multiselect";
|
||||
|
||||
const languages = [
|
||||
"javascript",
|
||||
"typescript",
|
||||
"json",
|
||||
"html",
|
||||
"css",
|
||||
"scss",
|
||||
"shell",
|
||||
"yaml",
|
||||
"xml",
|
||||
"ruby",
|
||||
"python",
|
||||
"php",
|
||||
"markdown",
|
||||
"rust",
|
||||
"csharp",
|
||||
"cpp",
|
||||
"c",
|
||||
"java",
|
||||
"go",
|
||||
"plaintext",
|
||||
];
|
||||
|
||||
export default function Settings({ config, onChange }: ISettingsProps) {
|
||||
return (
|
||||
<MultiSelect
|
||||
searchable
|
||||
multiple={false}
|
||||
options={languages}
|
||||
value={config.language ?? "javascript"}
|
||||
onChange={(value) => {
|
||||
onChange("language")(value);
|
||||
}}
|
||||
label="Language"
|
||||
labelPlural="languages"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -6,10 +6,6 @@ import { Markdown as MarkdownIcon } from "@src/assets/icons";
|
||||
import BasicCell from "./BasicCell";
|
||||
import withSideDrawerEditor from "@src/components/Table/editors/withSideDrawerEditor";
|
||||
|
||||
const Settings = lazy(
|
||||
() => import("./Settings" /* webpackChunkName: "Settings-markdown" */)
|
||||
);
|
||||
|
||||
const SideDrawerField = lazy(
|
||||
() =>
|
||||
import(
|
||||
@@ -29,6 +25,5 @@ export const config: IFieldConfig = {
|
||||
TableCell: withBasicCell(BasicCell),
|
||||
TableEditor: withSideDrawerEditor(BasicCell),
|
||||
SideDrawerField,
|
||||
settings: Settings,
|
||||
};
|
||||
export default config;
|
||||
|
||||
@@ -1,41 +1,23 @@
|
||||
import { IBasicCellProps } from "@src/components/fields/types";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
import { resultColorsScale } from "@src/utils/color";
|
||||
|
||||
export default function Percentage({ value }: IBasicCellProps) {
|
||||
const theme = useTheme();
|
||||
|
||||
if (typeof value === "number")
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: resultColorsScale(value).toHex(),
|
||||
if (value === null || value === undefined) return null;
|
||||
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
opacity: 0.5,
|
||||
|
||||
zIndex: 0,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
textAlign: "right",
|
||||
color: theme.palette.text.primary,
|
||||
|
||||
position: "relative",
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
{Math.round(value * 100)}%
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
return null;
|
||||
const percentage = typeof value === "number" ? value : 0;
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
textAlign: "right",
|
||||
color: theme.palette.text.primary,
|
||||
position: "relative",
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
{Math.round(percentage * 100)}%
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
171
src/components/fields/Percentage/Settings.tsx
Normal file
171
src/components/fields/Percentage/Settings.tsx
Normal file
@@ -0,0 +1,171 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import {
|
||||
Box,
|
||||
Checkbox,
|
||||
Grid,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
TextField,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import ColorPickerInput from "@src/components/ColorPickerInput";
|
||||
import { ISettingsProps } from "@src/components/fields/types";
|
||||
|
||||
import { Color, toColor } from "react-color-palette";
|
||||
import { fieldSx } from "@src/components/SideDrawer/utils";
|
||||
import { resultColorsScale, defaultColors } from "@src/utils/color";
|
||||
|
||||
const colorLabels: { [key: string]: string } = {
|
||||
0: "Start",
|
||||
1: "Middle",
|
||||
2: "End",
|
||||
};
|
||||
|
||||
export default function Settings({ onChange, config }: ISettingsProps) {
|
||||
const colors: string[] = config.colors ?? defaultColors;
|
||||
|
||||
const [checkStates, setCheckStates] = useState<boolean[]>(
|
||||
colors.map(Boolean)
|
||||
);
|
||||
|
||||
const onCheckboxChange = (index: number, checked: boolean) => {
|
||||
onChange("colors")(
|
||||
colors.map((value: any, idx: number) =>
|
||||
index === idx ? (checked ? value || defaultColors[idx] : null) : value
|
||||
)
|
||||
);
|
||||
setCheckStates(
|
||||
checkStates.map((value, idx) => (index === idx ? checked : value))
|
||||
);
|
||||
};
|
||||
|
||||
const handleColorChange = (index: number, color: Color): void => {
|
||||
onChange("colors")(
|
||||
colors.map((value, idx) => (index === idx ? color.hex : value))
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid container>
|
||||
{checkStates.map((checked: boolean, index: number) => {
|
||||
const colorHex = colors[index];
|
||||
return (
|
||||
<Grid
|
||||
xs={12}
|
||||
md={4}
|
||||
item
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "end",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
checked={checked}
|
||||
sx={[
|
||||
fieldSx,
|
||||
{
|
||||
width: "auto",
|
||||
boxShadow: "none",
|
||||
backgroundColor: "inherit",
|
||||
"&:hover": {
|
||||
backgroundColor: "inherit",
|
||||
},
|
||||
},
|
||||
]}
|
||||
onChange={() => onCheckboxChange(index, !checked)}
|
||||
/>
|
||||
<TextField
|
||||
select
|
||||
label={colorLabels[index]}
|
||||
value={1}
|
||||
fullWidth
|
||||
disabled={!checkStates[index]}
|
||||
>
|
||||
<MenuItem value={1} sx={{ display: "none" }}>
|
||||
{checked && (
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: colorHex,
|
||||
width: 15,
|
||||
height: 15,
|
||||
mr: 1.5,
|
||||
boxShadow: (theme) =>
|
||||
`0 0 0 1px ${theme.palette.divider} inset`,
|
||||
borderRadius: 0.5,
|
||||
opacity: 0.5,
|
||||
}}
|
||||
/>
|
||||
<Box>{colorHex}</Box>
|
||||
</Box>
|
||||
)}
|
||||
</MenuItem>
|
||||
{colorHex && (
|
||||
<div>
|
||||
<ColorPickerInput
|
||||
value={toColor("hex", colorHex)}
|
||||
onChangeComplete={(color) =>
|
||||
handleColorChange(index, color)
|
||||
}
|
||||
disabled={!checkStates[index]}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</TextField>
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
<Preview colors={config.colors} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const Preview = ({ colors }: { colors: any }) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<InputLabel>
|
||||
Preview:
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{[0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1].map((value) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
padding: "0.5rem 0",
|
||||
color: theme.palette.text.primary,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
key={value}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
backgroundColor: resultColorsScale(
|
||||
value,
|
||||
colors,
|
||||
theme.palette.background.paper
|
||||
).toHex(),
|
||||
opacity: 0.5,
|
||||
}}
|
||||
/>
|
||||
<Typography style={{ position: "relative", zIndex: 1 }}>
|
||||
{Math.floor(value * 100)}%
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</InputLabel>
|
||||
);
|
||||
};
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ISideDrawerFieldProps } from "@src/components/fields/types";
|
||||
|
||||
import { TextField, InputAdornment, Box } from "@mui/material";
|
||||
import { emphasize } from "@mui/material/styles";
|
||||
import { TextField, InputAdornment, Box, useTheme } from "@mui/material";
|
||||
import { resultColorsScale } from "@src/utils/color";
|
||||
import { getFieldId } from "@src/components/SideDrawer/utils";
|
||||
|
||||
@@ -12,6 +11,8 @@ export default function Percentage({
|
||||
onSubmit,
|
||||
disabled,
|
||||
}: ISideDrawerFieldProps) {
|
||||
const { colors } = (column as any).config;
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<TextField
|
||||
variant="filled"
|
||||
@@ -34,11 +35,14 @@ export default function Percentage({
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: 0.5,
|
||||
boxShadow: (theme) =>
|
||||
`0 0 0 1px ${theme.palette.divider} inest`,
|
||||
boxShadow: `0 0 0 1px ${theme.palette.divider} inset`,
|
||||
backgroundColor:
|
||||
typeof value === "number"
|
||||
? resultColorsScale(value).toHex() + "!important"
|
||||
? resultColorsScale(
|
||||
value,
|
||||
colors,
|
||||
theme.palette.background.paper
|
||||
).toHex() + "!important"
|
||||
: undefined,
|
||||
}}
|
||||
/>
|
||||
|
||||
41
src/components/fields/Percentage/TableCell.tsx
Normal file
41
src/components/fields/Percentage/TableCell.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import { IHeavyCellProps } from "@src/components/fields/types";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
import { resultColorsScale } from "@src/utils/color";
|
||||
|
||||
export default function Percentage({ column, value }: IHeavyCellProps) {
|
||||
const theme = useTheme();
|
||||
const { colors } = (column as any).config;
|
||||
|
||||
const percentage = typeof value === "number" ? value : 0;
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: resultColorsScale(
|
||||
percentage,
|
||||
colors,
|
||||
theme.palette.background.paper
|
||||
).toHex(),
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
opacity: 0.5,
|
||||
zIndex: 0,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
textAlign: "right",
|
||||
color: theme.palette.text.primary,
|
||||
position: "relative",
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
{Math.round(percentage * 100)}%
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,12 +1,20 @@
|
||||
import { lazy } from "react";
|
||||
import { IFieldConfig, FieldType } from "@src/components/fields/types";
|
||||
import withBasicCell from "@src/components/fields/_withTableCell/withBasicCell";
|
||||
import withHeavyCell from "@src/components/fields/_withTableCell/withHeavyCell";
|
||||
|
||||
import { Percentage as PercentageIcon } from "@src/assets/icons";
|
||||
import BasicCell from "./BasicCell";
|
||||
import TextEditor from "@src/components/Table/editors/TextEditor";
|
||||
import { filterOperators } from "@src/components/fields/Number/Filter";
|
||||
import BasicContextMenuActions from "@src/components/fields/_BasicCell/BasicCellContextMenuActions";
|
||||
|
||||
const BasicCell = lazy(
|
||||
() => import("./BasicCell" /* webpackChunkName: "BasicCell-Percentage" */)
|
||||
);
|
||||
|
||||
const TableCell = lazy(
|
||||
() => import("./TableCell" /* webpackChunkName: "TableCell-Percentage" */)
|
||||
);
|
||||
|
||||
const SideDrawerField = lazy(
|
||||
() =>
|
||||
import(
|
||||
@@ -14,6 +22,10 @@ const SideDrawerField = lazy(
|
||||
)
|
||||
);
|
||||
|
||||
const Settings = lazy(
|
||||
() => import("./Settings" /* webpackChunkName: "Settings-Percentage" */)
|
||||
);
|
||||
|
||||
export const config: IFieldConfig = {
|
||||
type: FieldType.percentage,
|
||||
name: "Percentage",
|
||||
@@ -22,11 +34,13 @@ export const config: IFieldConfig = {
|
||||
initialValue: 0,
|
||||
initializable: true,
|
||||
icon: <PercentageIcon />,
|
||||
requireConfiguration: true,
|
||||
description: "Percentage stored as a number between 0 and 1.",
|
||||
contextMenuActions: BasicContextMenuActions,
|
||||
TableCell: withBasicCell(BasicCell),
|
||||
TableCell: withHeavyCell(BasicCell, TableCell),
|
||||
TableEditor: TextEditor,
|
||||
SideDrawerField,
|
||||
settings: Settings,
|
||||
filter: {
|
||||
operators: filterOperators,
|
||||
},
|
||||
|
||||
@@ -35,9 +35,9 @@ export interface IFieldConfig {
|
||||
settingsValidator?: (config: Record<string, any>) => Record<string, string>;
|
||||
filter?: {
|
||||
operators: IFilterOperator[];
|
||||
customInput?: React.ComponentType<{ onChange: (value: any) => void }>;
|
||||
customInput?: React.ComponentType<IFilterCustomInputProps>;
|
||||
defaultValue?: any;
|
||||
valueFormatter?: (value: any) => string;
|
||||
valueFormatter?: (value: any, operator: TableFilter["operator"]) => string;
|
||||
};
|
||||
sortKey?: string;
|
||||
csvExportFormatter?: (value: any, config?: any) => string;
|
||||
@@ -104,4 +104,11 @@ export interface IFilterOperator {
|
||||
value: TableFilter["operator"];
|
||||
label: string;
|
||||
secondaryLabel?: React.ReactNode;
|
||||
group?: string;
|
||||
}
|
||||
|
||||
export interface IFilterCustomInputProps {
|
||||
onChange: (value: any) => void;
|
||||
operator: TableFilter["operator"];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ export default function NavDrawer({
|
||||
{...({ component: "button" } as any)}
|
||||
style={{ textAlign: "left" }}
|
||||
sx={{ mb: 1 }}
|
||||
onClick={(e) => {
|
||||
onClick={(e: any) => {
|
||||
if (closeDrawer) closeDrawer(e);
|
||||
openTableSettingsDialog({});
|
||||
}}
|
||||
|
||||
@@ -1,29 +1,45 @@
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
import { MenuItem, MenuItemProps } from "@mui/material";
|
||||
import { spreadSx } from "@src/utils/ui";
|
||||
|
||||
export default function NavItem(props: MenuItemProps<typeof Link>) {
|
||||
const linkProps = { target: "_blank", rel: "noopener noreferrer" };
|
||||
|
||||
export default function NavItem(
|
||||
props: MenuItemProps<typeof Link | "a" | "button">
|
||||
) {
|
||||
const { pathname } = useLocation();
|
||||
|
||||
return (
|
||||
<MenuItem
|
||||
component={Link}
|
||||
selected={pathname === props.to}
|
||||
role="none"
|
||||
tabIndex={0}
|
||||
component={"to" in props ? Link : "href" in props ? "a" : "button"}
|
||||
selected={"to" in props ? pathname === props.to : false}
|
||||
{...props}
|
||||
sx={{
|
||||
"& .MuiListItemText-primary": {
|
||||
typography: "button",
|
||||
{...("href" in props ? linkProps : {})}
|
||||
sx={[
|
||||
{
|
||||
overflow: "hidden",
|
||||
textAlign: "left",
|
||||
color: "text.secondary",
|
||||
},
|
||||
"& .MuiListItemIcon-root": { opacity: 0.87 },
|
||||
|
||||
"&:hover, &.Mui-selected": {
|
||||
"& .MuiListItemText-primary": { color: "text.primary" },
|
||||
"& .MuiSvgIcon-root": { color: "text.primary" },
|
||||
},
|
||||
"& .MuiListItemText-primary": {
|
||||
typography: "button",
|
||||
overflow: "hidden",
|
||||
},
|
||||
"& .MuiSvgIcon-root": {
|
||||
color: "inherit",
|
||||
opacity: 0.87,
|
||||
display: "block",
|
||||
},
|
||||
|
||||
...props.sx,
|
||||
"&&::before": { left: "auto", right: 0 },
|
||||
}}
|
||||
"&:hover, &.Mui-selected": {
|
||||
"& .MuiListItemText-primary": { color: "text.primary" },
|
||||
"& .MuiSvgIcon-root": { color: "text.primary" },
|
||||
},
|
||||
},
|
||||
...spreadSx(props.sx),
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import { colord } from "colord";
|
||||
|
||||
export const resultColors = {
|
||||
No: "#ED4747",
|
||||
Maybe: "#f3c900",
|
||||
Yes: "#1fad5f",
|
||||
};
|
||||
export const defaultColors = ["#ED4747", "#F3C900", "#1FAD5F"];
|
||||
|
||||
export const resultColorsScale = (value: number) =>
|
||||
export const resultColorsScale = (
|
||||
value: number,
|
||||
colors: any = defaultColors,
|
||||
defaultColor: string = "#fff"
|
||||
) =>
|
||||
value <= 0.5
|
||||
? colord(resultColors.No).mix(resultColors.Maybe, value * 2)
|
||||
: colord(resultColors.Maybe).mix(resultColors.Yes, (value - 0.5) * 2);
|
||||
? colord(colors[0] || defaultColor).mix(
|
||||
colors[1] || defaultColor,
|
||||
value * 2
|
||||
)
|
||||
: colord(colors[1] || defaultColor).mix(
|
||||
colors[2] || defaultColor,
|
||||
(value - 0.5) * 2
|
||||
);
|
||||
|
||||
104
yarn.lock
104
yarn.lock
@@ -3100,7 +3100,7 @@
|
||||
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
|
||||
integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
|
||||
integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==
|
||||
|
||||
"@protobufjs/base64@^1.1.2":
|
||||
version "1.1.2"
|
||||
@@ -3115,12 +3115,12 @@
|
||||
"@protobufjs/eventemitter@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
|
||||
integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
|
||||
integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==
|
||||
|
||||
"@protobufjs/fetch@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
|
||||
integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
|
||||
integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.1"
|
||||
"@protobufjs/inquire" "^1.1.0"
|
||||
@@ -3128,27 +3128,27 @@
|
||||
"@protobufjs/float@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
|
||||
integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
|
||||
integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==
|
||||
|
||||
"@protobufjs/inquire@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
|
||||
integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
|
||||
integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==
|
||||
|
||||
"@protobufjs/path@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
|
||||
integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
|
||||
integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==
|
||||
|
||||
"@protobufjs/pool@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
|
||||
integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
|
||||
integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==
|
||||
|
||||
"@protobufjs/utf8@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
|
||||
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
||||
|
||||
"@react-dnd/asap@^4.0.0":
|
||||
version "4.0.1"
|
||||
@@ -3836,9 +3836,9 @@
|
||||
integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==
|
||||
|
||||
"@types/long@^4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
|
||||
integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
|
||||
integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
|
||||
|
||||
"@types/mdast@^3.0.0":
|
||||
version "3.0.10"
|
||||
@@ -3862,21 +3862,16 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
|
||||
integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==
|
||||
|
||||
"@types/node@*":
|
||||
"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
|
||||
version "18.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.0.tgz#67c7b724e1bcdd7a8821ce0d5ee184d3b4dd525a"
|
||||
integrity sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==
|
||||
|
||||
"@types/node@^17.0.23":
|
||||
version "17.0.26"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.26.tgz#1bbff9b23ee5a64f87b4f30c0c854b112ee2e635"
|
||||
integrity sha512-z/FG/6DUO7pnze3AE3TBGIjGGKkvCcGcWINe1C7cADY8hKLJPDYpzsNE37uExQ4md5RFtTCvg+M8Mu1Enyeg2A==
|
||||
|
||||
"@types/node@>=12.12.47", "@types/node@>=13.7.0":
|
||||
version "16.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.13.tgz#7dfd9c14661edc65cccd43a29eb454174642370d"
|
||||
integrity sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg==
|
||||
|
||||
"@types/node@^17.0.23":
|
||||
version "17.0.23"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da"
|
||||
integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==
|
||||
|
||||
"@types/parse-json@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||
@@ -4676,11 +4671,6 @@ astral-regex@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
|
||||
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
|
||||
|
||||
async@0.9.x:
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
|
||||
integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
|
||||
|
||||
async@^2.6.2:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
|
||||
@@ -4689,9 +4679,9 @@ async@^2.6.2:
|
||||
lodash "^4.17.14"
|
||||
|
||||
async@^3.2.3:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9"
|
||||
integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
|
||||
integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
@@ -5439,7 +5429,7 @@ compression@^1.7.4:
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
concat-stream@~1.6.0:
|
||||
version "1.6.2"
|
||||
@@ -6215,20 +6205,13 @@ ee-first@1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
||||
|
||||
ejs@^3.1.5:
|
||||
version "3.1.7"
|
||||
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.7.tgz#c544d9c7f715783dd92f0bddcf73a59e6962d006"
|
||||
integrity sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==
|
||||
ejs@^3.1.5, ejs@^3.1.6:
|
||||
version "3.1.8"
|
||||
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b"
|
||||
integrity sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==
|
||||
dependencies:
|
||||
jake "^10.8.5"
|
||||
|
||||
ejs@^3.1.6:
|
||||
version "3.1.6"
|
||||
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.6.tgz#5bfd0a0689743bb5268b3550cceeebbc1702822a"
|
||||
integrity sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==
|
||||
dependencies:
|
||||
jake "^10.6.1"
|
||||
|
||||
electron-to-chromium@^1.3.649:
|
||||
version "1.3.671"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.671.tgz#8feaed6eae42d279fa4611f58c42a5a1eb81b2a0"
|
||||
@@ -6935,11 +6918,11 @@ file-selector@^0.1.12:
|
||||
tslib "^2.0.1"
|
||||
|
||||
filelist@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b"
|
||||
integrity sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5"
|
||||
integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==
|
||||
dependencies:
|
||||
minimatch "^3.0.4"
|
||||
minimatch "^5.0.1"
|
||||
|
||||
filesize@^8.0.6:
|
||||
version "8.0.7"
|
||||
@@ -8133,16 +8116,6 @@ istanbul-reports@^3.1.3:
|
||||
html-escaper "^2.0.0"
|
||||
istanbul-lib-report "^3.0.0"
|
||||
|
||||
jake@^10.6.1:
|
||||
version "10.8.4"
|
||||
resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.4.tgz#f6a8b7bf90c6306f768aa82bb7b98bf4ca15e84a"
|
||||
integrity sha512-MtWeTkl1qGsWUtbl/Jsca/8xSoK3x0UmS82sNbjqxxG/de/M/3b1DntdjHgPMC50enlTNwXOCRqPXLLt5cCfZA==
|
||||
dependencies:
|
||||
async "0.9.x"
|
||||
chalk "^4.0.2"
|
||||
filelist "^1.0.1"
|
||||
minimatch "^3.0.4"
|
||||
|
||||
jake@^10.8.5:
|
||||
version "10.8.5"
|
||||
resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.5.tgz#f2183d2c59382cb274226034543b9c03b8164c46"
|
||||
@@ -9754,12 +9727,7 @@ minimatch@^5.0.1, minimatch@^5.1.0:
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimist@^1.1.1, minimist@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.6:
|
||||
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
|
||||
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
|
||||
@@ -11047,9 +11015,9 @@ property-information@^6.0.0:
|
||||
integrity sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==
|
||||
|
||||
protobufjs@^6.10.0:
|
||||
version "6.11.2"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b"
|
||||
integrity sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==
|
||||
version "6.11.3"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74"
|
||||
integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.2"
|
||||
"@protobufjs/base64" "^1.1.2"
|
||||
@@ -12964,9 +12932,9 @@ tmp@^0.2.1:
|
||||
rimraf "^3.0.0"
|
||||
|
||||
tmpl@1.0.x:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
|
||||
integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
|
||||
integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
|
||||
Reference in New Issue
Block a user