mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
Merge branch 'develop' into feat/webhooks
* develop: (21 commits) generateBiggerId: remove console.log fix generateSmallerId algorithm (#567) fix merge fix inline cell of connect-service Fixes issue where the title field name is shown rather than the value Update reload screen copy (#530) Derivatives: don't list current field in listener field options potentially fix side drawer randomly scrolling JSON field: improve tree editor dark mode JSON: fix array support CodeEditor: use text field background color added a temp skip button for rules setting step JSON editor: add code editor mode (#509) CodeEditor: use TextField box-shadows & fix RichTextEditor box-shadows CodeEditor: fix onChange not being passed as prop consolidate CodeEditor to components/CodeEditor, allow resize, use github themes add CircularProgressOptical Import CSV: prevent import to ID field Import CSV: fix crash User Settings: move darker dark mode to theme ...
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
"@emotion/styled": "^11.3.0",
|
||||
"@hookform/resolvers": "^2.8.1",
|
||||
"@mdi/js": "^6.2.95",
|
||||
"@monaco-editor/react": "^4.1.0",
|
||||
"@monaco-editor/react": "^4.3.1",
|
||||
"@mui/icons-material": "^5.0.0",
|
||||
"@mui/lab": "^5.0.0-alpha.50",
|
||||
"@mui/material": "^5.0.0",
|
||||
|
||||
10
src/assets/icons/ResizeBottomRight.tsx
Normal file
10
src/assets/icons/ResizeBottomRight.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import SvgIcon, { SvgIconProps } from "@mui/material/SvgIcon";
|
||||
import { mdiResizeBottomRight } from "@mdi/js";
|
||||
|
||||
export default function ResizeBottomRight(props: SvgIconProps) {
|
||||
return (
|
||||
<SvgIcon {...props}>
|
||||
<path d={mdiResizeBottomRight} />
|
||||
</SvgIcon>
|
||||
);
|
||||
}
|
||||
19
src/components/CircularProgressOptical.tsx
Normal file
19
src/components/CircularProgressOptical.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { CircularProgress, CircularProgressProps } from "@mui/material";
|
||||
|
||||
export default function CircularProgressOptical({
|
||||
size = 40,
|
||||
...props
|
||||
}: CircularProgressProps & { size?: number }) {
|
||||
const DEFAULT_SIZE = 40;
|
||||
const DEFAULT_THICKNESS = 3.6;
|
||||
const linearThickness = (DEFAULT_SIZE / size) * DEFAULT_THICKNESS;
|
||||
const opticalRatio = 1 - (1 - size / DEFAULT_SIZE) / 2;
|
||||
|
||||
return (
|
||||
<CircularProgress
|
||||
{...props}
|
||||
size={size}
|
||||
thickness={linearThickness * opticalRatio}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
import React, { useRef, useMemo, useState } from "react";
|
||||
import clsx from "clsx";
|
||||
import Editor, { useMonaco } from "@monaco-editor/react";
|
||||
|
||||
import { makeStyles, createStyles } from "@mui/styles";
|
||||
import { useTheme } from "@mui/material";
|
||||
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
editorWrapper: { position: "relative" },
|
||||
resizeIcon: {
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
color: theme.palette.text.disabled,
|
||||
},
|
||||
saveButton: {
|
||||
marginTop: theme.spacing(1),
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export interface ICodeEditorProps {
|
||||
onChange: (value: string) => void;
|
||||
value: string;
|
||||
height?: number;
|
||||
wrapperProps?: Partial<React.HTMLAttributes<HTMLDivElement>>;
|
||||
disabled?: boolean;
|
||||
editorOptions?: any;
|
||||
}
|
||||
|
||||
export default function CodeEditor({
|
||||
onChange,
|
||||
value,
|
||||
height = 400,
|
||||
wrapperProps,
|
||||
disabled,
|
||||
editorOptions,
|
||||
}: ICodeEditorProps) {
|
||||
const theme = useTheme();
|
||||
const [initialEditorValue] = useState(value ?? "");
|
||||
const { tableState } = useProjectContext();
|
||||
const classes = useStyles();
|
||||
const monacoInstance = useMonaco();
|
||||
|
||||
const editorRef = useRef<any>();
|
||||
|
||||
function handleEditorDidMount(_, editor) {
|
||||
editorRef.current = editor;
|
||||
}
|
||||
|
||||
const themeTransformer = (theme: string) => {
|
||||
switch (theme) {
|
||||
case "dark":
|
||||
return "vs-dark";
|
||||
default:
|
||||
return theme;
|
||||
}
|
||||
};
|
||||
|
||||
useMemo(async () => {
|
||||
if (!monacoInstance) {
|
||||
// useMonaco returns a monaco instance but initialisation is done asynchronously
|
||||
// dont execute the logic until the instance is initialised
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
monacoInstance.languages.typescript.javascriptDefaults.setDiagnosticsOptions(
|
||||
{
|
||||
noSemanticValidation: true,
|
||||
noSyntaxValidation: false,
|
||||
}
|
||||
);
|
||||
// compiler options
|
||||
monacoInstance.languages.typescript.javascriptDefaults.setCompilerOptions(
|
||||
{
|
||||
target: monacoInstance.languages.typescript.ScriptTarget.ES5,
|
||||
allowNonTsExtensions: true,
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"An error occurred during initialization of Monaco: ",
|
||||
error
|
||||
);
|
||||
}
|
||||
}, [tableState?.columns]);
|
||||
|
||||
return (
|
||||
<div
|
||||
{...wrapperProps}
|
||||
className={clsx(classes.editorWrapper, wrapperProps?.className)}
|
||||
>
|
||||
<Editor
|
||||
theme={themeTransformer(theme.palette.mode)}
|
||||
height={height}
|
||||
onMount={handleEditorDidMount}
|
||||
language="javascript"
|
||||
value={initialEditorValue}
|
||||
options={{
|
||||
readOnly: disabled,
|
||||
fontFamily: theme.typography.fontFamilyMono,
|
||||
rulers: [80],
|
||||
minimap: { enabled: false },
|
||||
...editorOptions,
|
||||
}}
|
||||
onChange={onChange as any}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
97
src/components/CodeEditor/extensions.d.ts
vendored
Normal file
97
src/components/CodeEditor/extensions.d.ts
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
type Trigger = "create" | "update" | "delete";
|
||||
type Triggers = Trigger[];
|
||||
|
||||
// function types that defines extension body and should run
|
||||
type Condition =
|
||||
| boolean
|
||||
| ((data: ExtensionContext) => boolean | Promise<boolean>);
|
||||
|
||||
// the argument that the extension body takes in
|
||||
type ExtensionContext = {
|
||||
row: Row;
|
||||
ref: FirebaseFirestore.DocumentReference;
|
||||
storage: firebasestorage.Storage;
|
||||
db: FirebaseFirestore.Firestore;
|
||||
auth: adminauth.BaseAuth;
|
||||
change: any;
|
||||
triggerType: Triggers;
|
||||
fieldTypes: any;
|
||||
extensionConfig: {
|
||||
label: string;
|
||||
type: string;
|
||||
triggers: Trigger[];
|
||||
conditions: Condition;
|
||||
requiredFields: string[];
|
||||
extensionBody: any;
|
||||
};
|
||||
utilFns: any;
|
||||
};
|
||||
|
||||
// extension body definition
|
||||
type slackEmailBody = {
|
||||
channels?: string[];
|
||||
text?: string;
|
||||
emails: string[];
|
||||
blocks?: object[];
|
||||
attachments?: any;
|
||||
};
|
||||
|
||||
type slackChannelBody = {
|
||||
channels: string[];
|
||||
text?: string;
|
||||
emails?: string[];
|
||||
blocks?: object[];
|
||||
attachments?: any;
|
||||
};
|
||||
|
||||
type DocSyncBody = (context: ExtensionContext) => Promise<{
|
||||
fieldsToSync: Fields;
|
||||
row: Row;
|
||||
targetPath: string;
|
||||
}>;
|
||||
|
||||
type HistorySnapshotBody = (context: ExtensionContext) => Promise<{
|
||||
trackedFields: Fields;
|
||||
}>;
|
||||
|
||||
type AlgoliaIndexBody = (context: ExtensionContext) => Promise<{
|
||||
fieldsToSync: Fields;
|
||||
index: string;
|
||||
row: Row;
|
||||
objectID: string;
|
||||
}>;
|
||||
|
||||
type MeiliIndexBody = (context: ExtensionContext) => Promise<{
|
||||
fieldsToSync: Fields;
|
||||
index: string;
|
||||
row: Row;
|
||||
objectID: string;
|
||||
}>;
|
||||
|
||||
type BigqueryIndexBody = (context: ExtensionContext) => Promise<{
|
||||
fieldsToSync: Fields;
|
||||
index: string;
|
||||
row: Row;
|
||||
objectID: string;
|
||||
}>;
|
||||
|
||||
type SlackMessageBody = (
|
||||
context: ExtensionContext
|
||||
) => Promise<slackEmailBody | slackChannelBody>;
|
||||
|
||||
type SendgridEmailBody = (context: ExtensionContext) => Promise<any>;
|
||||
|
||||
type ApiCallBody = (context: ExtensionContext) => Promise<{
|
||||
body: string;
|
||||
url: string;
|
||||
method: string;
|
||||
callback: any;
|
||||
}>;
|
||||
|
||||
type TwilioMessageBody = (context: ExtensionContext) => Promise<{
|
||||
body: string;
|
||||
from: string;
|
||||
to: string;
|
||||
}>;
|
||||
|
||||
type TaskBody = (context: ExtensionContext) => Promise<any>;
|
||||
@@ -844,9 +844,9 @@ declare namespace FirebaseFirestore {
|
||||
* `exists` property will always be true and `data()` will never return
|
||||
* 'undefined'.
|
||||
*/
|
||||
export class QueryDocumentSnapshot<T = DocumentData> extends DocumentSnapshot<
|
||||
T
|
||||
> {
|
||||
export class QueryDocumentSnapshot<
|
||||
T = DocumentData
|
||||
> extends DocumentSnapshot<T> {
|
||||
private constructor();
|
||||
|
||||
/**
|
||||
535
src/components/CodeEditor/github-dark-default.json
Normal file
535
src/components/CodeEditor/github-dark-default.json
Normal file
@@ -0,0 +1,535 @@
|
||||
{
|
||||
"inherit": true,
|
||||
"base": "vs-dark",
|
||||
"colors": {
|
||||
"focusBorder": "#1f6feb",
|
||||
"foreground": "#c9d1d9",
|
||||
"descriptionForeground": "#8b949e",
|
||||
"errorForeground": "#f85149",
|
||||
"textLink.foreground": "#58a6ff",
|
||||
"textLink.activeForeground": "#58a6ff",
|
||||
"textBlockQuote.background": "#010409",
|
||||
"textBlockQuote.border": "#30363d",
|
||||
"textCodeBlock.background": "#6e768166",
|
||||
"textPreformat.foreground": "#8b949e",
|
||||
"textSeparator.foreground": "#21262d",
|
||||
"button.background": "#238636",
|
||||
"button.foreground": "#ffffff",
|
||||
"button.hoverBackground": "#2ea043",
|
||||
"button.secondaryBackground": "#282e33",
|
||||
"button.secondaryForeground": "#c9d1d9",
|
||||
"button.secondaryHoverBackground": "#30363d",
|
||||
"checkbox.background": "#161b22",
|
||||
"checkbox.border": "#30363d",
|
||||
"dropdown.background": "#161b22",
|
||||
"dropdown.border": "#30363d",
|
||||
"dropdown.foreground": "#c9d1d9",
|
||||
"dropdown.listBackground": "#161b22",
|
||||
"input.background": "#0d1117",
|
||||
"input.border": "#30363d",
|
||||
"input.foreground": "#c9d1d9",
|
||||
"input.placeholderForeground": "#484f58",
|
||||
"badge.foreground": "#f0f6fc",
|
||||
"badge.background": "#1f6feb",
|
||||
"progressBar.background": "#1f6feb",
|
||||
"titleBar.activeForeground": "#8b949e",
|
||||
"titleBar.activeBackground": "#0d1117",
|
||||
"titleBar.inactiveForeground": "#8b949e",
|
||||
"titleBar.inactiveBackground": "#010409",
|
||||
"titleBar.border": "#30363d",
|
||||
"activityBar.foreground": "#c9d1d9",
|
||||
"activityBar.inactiveForeground": "#8b949e",
|
||||
"activityBar.background": "#0d1117",
|
||||
"activityBarBadge.foreground": "#f0f6fc",
|
||||
"activityBarBadge.background": "#1f6feb",
|
||||
"activityBar.activeBorder": "#f78166",
|
||||
"activityBar.border": "#30363d",
|
||||
"sideBar.foreground": "#c9d1d9",
|
||||
"sideBar.background": "#010409",
|
||||
"sideBar.border": "#30363d",
|
||||
"sideBarTitle.foreground": "#c9d1d9",
|
||||
"sideBarSectionHeader.foreground": "#c9d1d9",
|
||||
"sideBarSectionHeader.background": "#010409",
|
||||
"sideBarSectionHeader.border": "#30363d",
|
||||
"list.hoverForeground": "#c9d1d9",
|
||||
"list.inactiveSelectionForeground": "#c9d1d9",
|
||||
"list.activeSelectionForeground": "#c9d1d9",
|
||||
"list.hoverBackground": "#6e76811a",
|
||||
"list.inactiveSelectionBackground": "#6e768166",
|
||||
"list.activeSelectionBackground": "#6e768166",
|
||||
"list.focusForeground": "#c9d1d9",
|
||||
"list.focusBackground": "#388bfd26",
|
||||
"list.inactiveFocusBackground": "#388bfd26",
|
||||
"list.highlightForeground": "#58a6ff",
|
||||
"tree.indentGuidesStroke": "#21262d",
|
||||
"notificationCenterHeader.foreground": "#8b949e",
|
||||
"notificationCenterHeader.background": "#161b22",
|
||||
"notifications.foreground": "#c9d1d9",
|
||||
"notifications.background": "#161b22",
|
||||
"notifications.border": "#30363d",
|
||||
"notificationsErrorIcon.foreground": "#f85149",
|
||||
"notificationsWarningIcon.foreground": "#d29922",
|
||||
"notificationsInfoIcon.foreground": "#58a6ff",
|
||||
"pickerGroup.border": "#30363d",
|
||||
"pickerGroup.foreground": "#8b949e",
|
||||
"quickInput.background": "#161b22",
|
||||
"quickInput.foreground": "#c9d1d9",
|
||||
"statusBar.foreground": "#8b949e",
|
||||
"statusBar.background": "#0d1117",
|
||||
"statusBar.border": "#30363d",
|
||||
"statusBar.noFolderBackground": "#0d1117",
|
||||
"statusBar.debuggingBackground": "#da3633",
|
||||
"statusBar.debuggingForeground": "#f0f6fc",
|
||||
"statusBarItem.prominentBackground": "#161b22",
|
||||
"editorGroupHeader.tabsBackground": "#010409",
|
||||
"editorGroupHeader.tabsBorder": "#30363d",
|
||||
"editorGroup.border": "#30363d",
|
||||
"tab.activeForeground": "#c9d1d9",
|
||||
"tab.inactiveForeground": "#8b949e",
|
||||
"tab.inactiveBackground": "#010409",
|
||||
"tab.activeBackground": "#0d1117",
|
||||
"tab.hoverBackground": "#0d1117",
|
||||
"tab.unfocusedHoverBackground": "#6e76811a",
|
||||
"tab.border": "#30363d",
|
||||
"tab.unfocusedActiveBorderTop": "#30363d",
|
||||
"tab.activeBorder": "#0d1117",
|
||||
"tab.unfocusedActiveBorder": "#0d1117",
|
||||
"tab.activeBorderTop": "#f78166",
|
||||
"breadcrumb.foreground": "#8b949e",
|
||||
"breadcrumb.focusForeground": "#c9d1d9",
|
||||
"breadcrumb.activeSelectionForeground": "#8b949e",
|
||||
"breadcrumbPicker.background": "#161b22",
|
||||
"editor.foreground": "#c9d1d9",
|
||||
"editor.background": "#0d1117",
|
||||
"editorWidget.background": "#161b22",
|
||||
"editor.foldBackground": "#6e76811a",
|
||||
"editor.lineHighlightBackground": "#6e76811a",
|
||||
"editorLineNumber.foreground": "#8b949e",
|
||||
"editorLineNumber.activeForeground": "#c9d1d9",
|
||||
"editorIndentGuide.background": "#21262d",
|
||||
"editorIndentGuide.activeBackground": "#30363d",
|
||||
"editorWhitespace.foreground": "#484f58",
|
||||
"editorCursor.foreground": "#58a6ff",
|
||||
"editor.findMatchBackground": "#ffd33d44",
|
||||
"editor.findMatchHighlightBackground": "#ffd33d22",
|
||||
"editor.linkedEditingBackground": "#3392FF22",
|
||||
"editor.inactiveSelectionBackground": "#3392FF22",
|
||||
"editor.selectionBackground": "#3392FF44",
|
||||
"editor.selectionHighlightBackground": "#17E5E633",
|
||||
"editor.selectionHighlightBorder": "#17E5E600",
|
||||
"editor.wordHighlightBackground": "#17E5E600",
|
||||
"editor.wordHighlightStrongBackground": "#17E5E600",
|
||||
"editor.wordHighlightBorder": "#17E5E699",
|
||||
"editor.wordHighlightStrongBorder": "#17E5E666",
|
||||
"editorBracketMatch.background": "#17E5E650",
|
||||
"editorBracketMatch.border": "#17E5E600",
|
||||
"editorGutter.modifiedBackground": "#bb800966",
|
||||
"editorGutter.addedBackground": "#2ea04366",
|
||||
"editorGutter.deletedBackground": "#f8514966",
|
||||
"diffEditor.insertedTextBackground": "#2ea04326",
|
||||
"diffEditor.removedTextBackground": "#f8514926",
|
||||
"scrollbar.shadow": "#0008",
|
||||
"scrollbarSlider.background": "#484F5833",
|
||||
"scrollbarSlider.hoverBackground": "#484F5844",
|
||||
"scrollbarSlider.activeBackground": "#484F5888",
|
||||
"editorOverviewRuler.border": "#010409",
|
||||
"panel.background": "#010409",
|
||||
"panel.border": "#30363d",
|
||||
"panelTitle.activeBorder": "#f78166",
|
||||
"panelTitle.activeForeground": "#c9d1d9",
|
||||
"panelTitle.inactiveForeground": "#8b949e",
|
||||
"panelInput.border": "#30363d",
|
||||
"terminal.foreground": "#8b949e",
|
||||
"terminal.ansiBlack": "#484f58",
|
||||
"terminal.ansiRed": "#ff7b72",
|
||||
"terminal.ansiGreen": "#3fb950",
|
||||
"terminal.ansiYellow": "#d29922",
|
||||
"terminal.ansiBlue": "#58a6ff",
|
||||
"terminal.ansiMagenta": "#bc8cff",
|
||||
"terminal.ansiCyan": "#39c5cf",
|
||||
"terminal.ansiWhite": "#b1bac4",
|
||||
"terminal.ansiBrightBlack": "#6e7681",
|
||||
"terminal.ansiBrightRed": "#ffa198",
|
||||
"terminal.ansiBrightGreen": "#56d364",
|
||||
"terminal.ansiBrightYellow": "#e3b341",
|
||||
"terminal.ansiBrightBlue": "#79c0ff",
|
||||
"terminal.ansiBrightMagenta": "#d2a8ff",
|
||||
"terminal.ansiBrightCyan": "#56d4dd",
|
||||
"terminal.ansiBrightWhite": "#f0f6fc",
|
||||
"gitDecoration.addedResourceForeground": "#3fb950",
|
||||
"gitDecoration.modifiedResourceForeground": "#d29922",
|
||||
"gitDecoration.deletedResourceForeground": "#f85149",
|
||||
"gitDecoration.untrackedResourceForeground": "#3fb950",
|
||||
"gitDecoration.ignoredResourceForeground": "#484f58",
|
||||
"gitDecoration.conflictingResourceForeground": "#db6d28",
|
||||
"gitDecoration.submoduleResourceForeground": "#8b949e",
|
||||
"debugToolBar.background": "#161b22",
|
||||
"editor.stackFrameHighlightBackground": "#D2992225",
|
||||
"editor.focusedStackFrameHighlightBackground": "#3FB95025",
|
||||
"peekViewEditor.matchHighlightBackground": "#ffd33d33",
|
||||
"peekViewResult.matchHighlightBackground": "#ffd33d33",
|
||||
"peekViewEditor.background": "#0d111788",
|
||||
"peekViewResult.background": "#0d1117",
|
||||
"settings.headerForeground": "#8b949e",
|
||||
"settings.modifiedItemIndicator": "#bb800966",
|
||||
"welcomePage.buttonBackground": "#21262d",
|
||||
"welcomePage.buttonHoverBackground": "#30363d"
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"foreground": "#8b949e",
|
||||
"token": "comment"
|
||||
},
|
||||
{
|
||||
"foreground": "#8b949e",
|
||||
"token": "punctuation.definition.comment"
|
||||
},
|
||||
{
|
||||
"foreground": "#8b949e",
|
||||
"token": "string.comment"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "constant"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "entity.name.constant"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "variable.other.constant"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "variable.language"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "entity"
|
||||
},
|
||||
{
|
||||
"foreground": "#ffa657",
|
||||
"token": "entity.name"
|
||||
},
|
||||
{
|
||||
"foreground": "#ffa657",
|
||||
"token": "meta.export.default"
|
||||
},
|
||||
{
|
||||
"foreground": "#ffa657",
|
||||
"token": "meta.definition.variable"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "variable.parameter.function"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "meta.jsx.children"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "meta.block"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "meta.tag.attributes"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "entity.name.constant"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "meta.object.member"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "meta.embedded.expression"
|
||||
},
|
||||
{
|
||||
"foreground": "#d2a8ff",
|
||||
"token": "entity.name.function"
|
||||
},
|
||||
{
|
||||
"foreground": "#7ee787",
|
||||
"token": "entity.name.tag"
|
||||
},
|
||||
{
|
||||
"foreground": "#7ee787",
|
||||
"token": "support.class.component"
|
||||
},
|
||||
{
|
||||
"foreground": "#ff7b72",
|
||||
"token": "keyword"
|
||||
},
|
||||
{
|
||||
"foreground": "#ff7b72",
|
||||
"token": "storage"
|
||||
},
|
||||
{
|
||||
"foreground": "#ff7b72",
|
||||
"token": "storage.type"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "storage.modifier.package"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "storage.modifier.import"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "storage.type.java"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"token": "string"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"token": "punctuation.definition.string"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"token": "string punctuation.section.embedded source"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "support"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "meta.property-name"
|
||||
},
|
||||
{
|
||||
"foreground": "#ffa657",
|
||||
"token": "variable"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "variable.other"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic",
|
||||
"foreground": "#ffa198",
|
||||
"token": "invalid.broken"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic",
|
||||
"foreground": "#ffa198",
|
||||
"token": "invalid.deprecated"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic",
|
||||
"foreground": "#ffa198",
|
||||
"token": "invalid.illegal"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic",
|
||||
"foreground": "#ffa198",
|
||||
"token": "invalid.unimplemented"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic underline",
|
||||
"background": "#ff7b72",
|
||||
"foreground": "#0d1117",
|
||||
"content": "^M",
|
||||
"token": "carriage-return"
|
||||
},
|
||||
{
|
||||
"foreground": "#ffa198",
|
||||
"token": "message.error"
|
||||
},
|
||||
{
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "string source"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "string variable"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"token": "source.regexp"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"token": "string.regexp"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"token": "string.regexp.character-class"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"token": "string.regexp constant.character.escape"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"token": "string.regexp source.ruby.embedded"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"token": "string.regexp string.regexp.arbitrary-repitition"
|
||||
},
|
||||
{
|
||||
"fontStyle": "bold",
|
||||
"foreground": "#7ee787",
|
||||
"token": "string.regexp constant.character.escape"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "support.constant"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "support.variable"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "meta.module-reference"
|
||||
},
|
||||
{
|
||||
"foreground": "#ffa657",
|
||||
"token": "punctuation.definition.list.begin.markdown"
|
||||
},
|
||||
{
|
||||
"fontStyle": "bold",
|
||||
"foreground": "#79c0ff",
|
||||
"token": "markup.heading"
|
||||
},
|
||||
{
|
||||
"fontStyle": "bold",
|
||||
"foreground": "#79c0ff",
|
||||
"token": "markup.heading entity.name"
|
||||
},
|
||||
{
|
||||
"foreground": "#7ee787",
|
||||
"token": "markup.quote"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic",
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "markup.italic"
|
||||
},
|
||||
{
|
||||
"fontStyle": "bold",
|
||||
"foreground": "#c9d1d9",
|
||||
"token": "markup.bold"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "markup.raw"
|
||||
},
|
||||
{
|
||||
"background": "#490202",
|
||||
"foreground": "#ffa198",
|
||||
"token": "markup.deleted"
|
||||
},
|
||||
{
|
||||
"background": "#490202",
|
||||
"foreground": "#ffa198",
|
||||
"token": "meta.diff.header.from-file"
|
||||
},
|
||||
{
|
||||
"background": "#490202",
|
||||
"foreground": "#ffa198",
|
||||
"token": "punctuation.definition.deleted"
|
||||
},
|
||||
{
|
||||
"background": "#04260f",
|
||||
"foreground": "#7ee787",
|
||||
"token": "markup.inserted"
|
||||
},
|
||||
{
|
||||
"background": "#04260f",
|
||||
"foreground": "#7ee787",
|
||||
"token": "meta.diff.header.to-file"
|
||||
},
|
||||
{
|
||||
"background": "#04260f",
|
||||
"foreground": "#7ee787",
|
||||
"token": "punctuation.definition.inserted"
|
||||
},
|
||||
{
|
||||
"background": "#5a1e02",
|
||||
"foreground": "#ffa657",
|
||||
"token": "markup.changed"
|
||||
},
|
||||
{
|
||||
"background": "#5a1e02",
|
||||
"foreground": "#ffa657",
|
||||
"token": "punctuation.definition.changed"
|
||||
},
|
||||
{
|
||||
"foreground": "#161b22",
|
||||
"background": "#79c0ff",
|
||||
"token": "markup.ignored"
|
||||
},
|
||||
{
|
||||
"foreground": "#161b22",
|
||||
"background": "#79c0ff",
|
||||
"token": "markup.untracked"
|
||||
},
|
||||
{
|
||||
"foreground": "#d2a8ff",
|
||||
"fontStyle": "bold",
|
||||
"token": "meta.diff.range"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "meta.diff.header"
|
||||
},
|
||||
{
|
||||
"fontStyle": "bold",
|
||||
"foreground": "#79c0ff",
|
||||
"token": "meta.separator"
|
||||
},
|
||||
{
|
||||
"foreground": "#79c0ff",
|
||||
"token": "meta.output"
|
||||
},
|
||||
{
|
||||
"foreground": "#8b949e",
|
||||
"token": "brackethighlighter.tag"
|
||||
},
|
||||
{
|
||||
"foreground": "#8b949e",
|
||||
"token": "brackethighlighter.curly"
|
||||
},
|
||||
{
|
||||
"foreground": "#8b949e",
|
||||
"token": "brackethighlighter.round"
|
||||
},
|
||||
{
|
||||
"foreground": "#8b949e",
|
||||
"token": "brackethighlighter.square"
|
||||
},
|
||||
{
|
||||
"foreground": "#8b949e",
|
||||
"token": "brackethighlighter.angle"
|
||||
},
|
||||
{
|
||||
"foreground": "#8b949e",
|
||||
"token": "brackethighlighter.quote"
|
||||
},
|
||||
{
|
||||
"foreground": "#ffa198",
|
||||
"token": "brackethighlighter.unmatched"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"fontStyle": "underline",
|
||||
"token": "constant.other.reference.link"
|
||||
},
|
||||
{
|
||||
"foreground": "#a5d6ff",
|
||||
"fontStyle": "underline",
|
||||
"token": "string.other.link"
|
||||
}
|
||||
],
|
||||
"encodedTokensColors": []
|
||||
}
|
||||
531
src/components/CodeEditor/github-light-default.json
Normal file
531
src/components/CodeEditor/github-light-default.json
Normal file
@@ -0,0 +1,531 @@
|
||||
{
|
||||
"inherit": true,
|
||||
"base": "vs",
|
||||
"colors": {
|
||||
"focusBorder": "#0969da",
|
||||
"foreground": "#24292f",
|
||||
"descriptionForeground": "#57606a",
|
||||
"errorForeground": "#cf222e",
|
||||
"textLink.foreground": "#0969da",
|
||||
"textLink.activeForeground": "#0969da",
|
||||
"textBlockQuote.background": "#f6f8fa",
|
||||
"textBlockQuote.border": "#d0d7de",
|
||||
"textCodeBlock.background": "#afb8c133",
|
||||
"textPreformat.foreground": "#57606a",
|
||||
"textSeparator.foreground": "#d8dee4",
|
||||
"button.background": "#2da44e",
|
||||
"button.foreground": "#ffffff",
|
||||
"button.hoverBackground": "#2c974b",
|
||||
"button.secondaryBackground": "#ebecf0",
|
||||
"button.secondaryForeground": "#24292f",
|
||||
"button.secondaryHoverBackground": "#f3f4f6",
|
||||
"checkbox.background": "#f6f8fa",
|
||||
"checkbox.border": "#d0d7de",
|
||||
"dropdown.background": "#ffffff",
|
||||
"dropdown.border": "#d0d7de",
|
||||
"dropdown.foreground": "#24292f",
|
||||
"dropdown.listBackground": "#ffffff",
|
||||
"input.background": "#ffffff",
|
||||
"input.border": "#d0d7de",
|
||||
"input.foreground": "#24292f",
|
||||
"input.placeholderForeground": "#6e7781",
|
||||
"badge.foreground": "#ffffff",
|
||||
"badge.background": "#0969da",
|
||||
"progressBar.background": "#0969da",
|
||||
"titleBar.activeForeground": "#57606a",
|
||||
"titleBar.activeBackground": "#ffffff",
|
||||
"titleBar.inactiveForeground": "#57606a",
|
||||
"titleBar.inactiveBackground": "#f6f8fa",
|
||||
"titleBar.border": "#d0d7de",
|
||||
"activityBar.foreground": "#24292f",
|
||||
"activityBar.inactiveForeground": "#57606a",
|
||||
"activityBar.background": "#ffffff",
|
||||
"activityBarBadge.foreground": "#ffffff",
|
||||
"activityBarBadge.background": "#0969da",
|
||||
"activityBar.activeBorder": "#fd8c73",
|
||||
"activityBar.border": "#d0d7de",
|
||||
"sideBar.foreground": "#24292f",
|
||||
"sideBar.background": "#f6f8fa",
|
||||
"sideBar.border": "#d0d7de",
|
||||
"sideBarTitle.foreground": "#24292f",
|
||||
"sideBarSectionHeader.foreground": "#24292f",
|
||||
"sideBarSectionHeader.background": "#f6f8fa",
|
||||
"sideBarSectionHeader.border": "#d0d7de",
|
||||
"list.hoverForeground": "#24292f",
|
||||
"list.inactiveSelectionForeground": "#24292f",
|
||||
"list.activeSelectionForeground": "#24292f",
|
||||
"list.hoverBackground": "#eaeef280",
|
||||
"list.inactiveSelectionBackground": "#afb8c133",
|
||||
"list.activeSelectionBackground": "#afb8c133",
|
||||
"list.focusForeground": "#24292f",
|
||||
"list.focusBackground": "#ddf4ff",
|
||||
"list.inactiveFocusBackground": "#ddf4ff",
|
||||
"list.highlightForeground": "#0969da",
|
||||
"tree.indentGuidesStroke": "#d8dee4",
|
||||
"notificationCenterHeader.foreground": "#57606a",
|
||||
"notificationCenterHeader.background": "#f6f8fa",
|
||||
"notifications.foreground": "#24292f",
|
||||
"notifications.background": "#ffffff",
|
||||
"notifications.border": "#d0d7de",
|
||||
"notificationsErrorIcon.foreground": "#cf222e",
|
||||
"notificationsWarningIcon.foreground": "#9a6700",
|
||||
"notificationsInfoIcon.foreground": "#0969da",
|
||||
"pickerGroup.border": "#d0d7de",
|
||||
"pickerGroup.foreground": "#57606a",
|
||||
"quickInput.background": "#ffffff",
|
||||
"quickInput.foreground": "#24292f",
|
||||
"statusBar.foreground": "#57606a",
|
||||
"statusBar.background": "#ffffff",
|
||||
"statusBar.border": "#d0d7de",
|
||||
"statusBar.noFolderBackground": "#ffffff",
|
||||
"statusBar.debuggingBackground": "#cf222e",
|
||||
"statusBar.debuggingForeground": "#ffffff",
|
||||
"statusBarItem.prominentBackground": "#f6f8fa",
|
||||
"editorGroupHeader.tabsBackground": "#f6f8fa",
|
||||
"editorGroupHeader.tabsBorder": "#d0d7de",
|
||||
"editorGroup.border": "#d0d7de",
|
||||
"tab.activeForeground": "#24292f",
|
||||
"tab.inactiveForeground": "#57606a",
|
||||
"tab.inactiveBackground": "#f6f8fa",
|
||||
"tab.activeBackground": "#ffffff",
|
||||
"tab.hoverBackground": "#ffffff",
|
||||
"tab.unfocusedHoverBackground": "#eaeef280",
|
||||
"tab.border": "#d0d7de",
|
||||
"tab.unfocusedActiveBorderTop": "#d0d7de",
|
||||
"tab.activeBorder": "#ffffff",
|
||||
"tab.unfocusedActiveBorder": "#ffffff",
|
||||
"tab.activeBorderTop": "#fd8c73",
|
||||
"breadcrumb.foreground": "#57606a",
|
||||
"breadcrumb.focusForeground": "#24292f",
|
||||
"breadcrumb.activeSelectionForeground": "#57606a",
|
||||
"breadcrumbPicker.background": "#ffffff",
|
||||
"editor.foreground": "#24292f",
|
||||
"editor.background": "#ffffff",
|
||||
"editorWidget.background": "#ffffff",
|
||||
"editor.foldBackground": "#6e77811a",
|
||||
"editor.lineHighlightBackground": "#eaeef280",
|
||||
"editorLineNumber.foreground": "#57606a",
|
||||
"editorLineNumber.activeForeground": "#24292f",
|
||||
"editorIndentGuide.background": "#d8dee4",
|
||||
"editorIndentGuide.activeBackground": "#d0d7de",
|
||||
"editorWhitespace.foreground": "#6e7781",
|
||||
"editorCursor.foreground": "#0969da",
|
||||
"editor.findMatchBackground": "#bf8700",
|
||||
"editor.findMatchHighlightBackground": "#ffdf5d66",
|
||||
"editor.linkedEditingBackground": "#0366d611",
|
||||
"editor.inactiveSelectionBackground": "#0366d611",
|
||||
"editor.selectionBackground": "#0366d625",
|
||||
"editor.selectionHighlightBackground": "#34d05840",
|
||||
"editor.selectionHighlightBorder": "#34d05800",
|
||||
"editor.wordHighlightBackground": "#34d05800",
|
||||
"editor.wordHighlightStrongBackground": "#34d05800",
|
||||
"editor.wordHighlightBorder": "#24943e99",
|
||||
"editor.wordHighlightStrongBorder": "#24943e50",
|
||||
"editorBracketMatch.background": "#34d05840",
|
||||
"editorBracketMatch.border": "#34d05800",
|
||||
"editorGutter.modifiedBackground": "#d4a72c66",
|
||||
"editorGutter.addedBackground": "#4ac26b66",
|
||||
"editorGutter.deletedBackground": "#ff818266",
|
||||
"diffEditor.insertedTextBackground": "#dafbe1",
|
||||
"diffEditor.removedTextBackground": "#ffebe9",
|
||||
"scrollbar.shadow": "#6a737d33",
|
||||
"scrollbarSlider.background": "#959da533",
|
||||
"scrollbarSlider.hoverBackground": "#959da544",
|
||||
"scrollbarSlider.activeBackground": "#959da588",
|
||||
"editorOverviewRuler.border": "#ffffff",
|
||||
"panel.background": "#f6f8fa",
|
||||
"panel.border": "#d0d7de",
|
||||
"panelTitle.activeBorder": "#fd8c73",
|
||||
"panelTitle.activeForeground": "#24292f",
|
||||
"panelTitle.inactiveForeground": "#57606a",
|
||||
"panelInput.border": "#d0d7de",
|
||||
"terminal.foreground": "#57606a",
|
||||
"terminal.ansiBlack": "#24292f",
|
||||
"terminal.ansiRed": "#cf222e",
|
||||
"terminal.ansiGreen": "#116329",
|
||||
"terminal.ansiYellow": "#4d2d00",
|
||||
"terminal.ansiBlue": "#0969da",
|
||||
"terminal.ansiMagenta": "#8250df",
|
||||
"terminal.ansiCyan": "#1b7c83",
|
||||
"terminal.ansiWhite": "#6e7781",
|
||||
"terminal.ansiBrightBlack": "#57606a",
|
||||
"terminal.ansiBrightRed": "#a40e26",
|
||||
"terminal.ansiBrightGreen": "#1a7f37",
|
||||
"terminal.ansiBrightYellow": "#633c01",
|
||||
"terminal.ansiBrightBlue": "#218bff",
|
||||
"terminal.ansiBrightMagenta": "#a475f9",
|
||||
"terminal.ansiBrightCyan": "#3192aa",
|
||||
"terminal.ansiBrightWhite": "#8c959f",
|
||||
"gitDecoration.addedResourceForeground": "#1a7f37",
|
||||
"gitDecoration.modifiedResourceForeground": "#9a6700",
|
||||
"gitDecoration.deletedResourceForeground": "#cf222e",
|
||||
"gitDecoration.untrackedResourceForeground": "#1a7f37",
|
||||
"gitDecoration.ignoredResourceForeground": "#6e7781",
|
||||
"gitDecoration.conflictingResourceForeground": "#bc4c00",
|
||||
"gitDecoration.submoduleResourceForeground": "#57606a",
|
||||
"debugToolBar.background": "#ffffff",
|
||||
"editor.stackFrameHighlightBackground": "#ffd33d33",
|
||||
"editor.focusedStackFrameHighlightBackground": "#28a74525",
|
||||
"settings.headerForeground": "#57606a",
|
||||
"settings.modifiedItemIndicator": "#d4a72c66",
|
||||
"welcomePage.buttonBackground": "#f6f8fa",
|
||||
"welcomePage.buttonHoverBackground": "#f3f4f6"
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"foreground": "#6e7781",
|
||||
"token": "comment"
|
||||
},
|
||||
{
|
||||
"foreground": "#6e7781",
|
||||
"token": "punctuation.definition.comment"
|
||||
},
|
||||
{
|
||||
"foreground": "#6e7781",
|
||||
"token": "string.comment"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "constant"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "entity.name.constant"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "variable.other.constant"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "variable.language"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "entity"
|
||||
},
|
||||
{
|
||||
"foreground": "#953800",
|
||||
"token": "entity.name"
|
||||
},
|
||||
{
|
||||
"foreground": "#953800",
|
||||
"token": "meta.export.default"
|
||||
},
|
||||
{
|
||||
"foreground": "#953800",
|
||||
"token": "meta.definition.variable"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "variable.parameter.function"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "meta.jsx.children"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "meta.block"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "meta.tag.attributes"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "entity.name.constant"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "meta.object.member"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "meta.embedded.expression"
|
||||
},
|
||||
{
|
||||
"foreground": "#8250df",
|
||||
"token": "entity.name.function"
|
||||
},
|
||||
{
|
||||
"foreground": "#116329",
|
||||
"token": "entity.name.tag"
|
||||
},
|
||||
{
|
||||
"foreground": "#116329",
|
||||
"token": "support.class.component"
|
||||
},
|
||||
{
|
||||
"foreground": "#cf222e",
|
||||
"token": "keyword"
|
||||
},
|
||||
{
|
||||
"foreground": "#cf222e",
|
||||
"token": "storage"
|
||||
},
|
||||
{
|
||||
"foreground": "#cf222e",
|
||||
"token": "storage.type"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "storage.modifier.package"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "storage.modifier.import"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "storage.type.java"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"token": "string"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"token": "punctuation.definition.string"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"token": "string punctuation.section.embedded source"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "support"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "meta.property-name"
|
||||
},
|
||||
{
|
||||
"foreground": "#953800",
|
||||
"token": "variable"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "variable.other"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic",
|
||||
"foreground": "#82071e",
|
||||
"token": "invalid.broken"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic",
|
||||
"foreground": "#82071e",
|
||||
"token": "invalid.deprecated"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic",
|
||||
"foreground": "#82071e",
|
||||
"token": "invalid.illegal"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic",
|
||||
"foreground": "#82071e",
|
||||
"token": "invalid.unimplemented"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic underline",
|
||||
"background": "#cf222e",
|
||||
"foreground": "#f6f8fa",
|
||||
"content": "^M",
|
||||
"token": "carriage-return"
|
||||
},
|
||||
{
|
||||
"foreground": "#82071e",
|
||||
"token": "message.error"
|
||||
},
|
||||
{
|
||||
"foreground": "#24292f",
|
||||
"token": "string source"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "string variable"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"token": "source.regexp"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"token": "string.regexp"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"token": "string.regexp.character-class"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"token": "string.regexp constant.character.escape"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"token": "string.regexp source.ruby.embedded"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"token": "string.regexp string.regexp.arbitrary-repitition"
|
||||
},
|
||||
{
|
||||
"fontStyle": "bold",
|
||||
"foreground": "#116329",
|
||||
"token": "string.regexp constant.character.escape"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "support.constant"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "support.variable"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "meta.module-reference"
|
||||
},
|
||||
{
|
||||
"foreground": "#953800",
|
||||
"token": "punctuation.definition.list.begin.markdown"
|
||||
},
|
||||
{
|
||||
"fontStyle": "bold",
|
||||
"foreground": "#0550ae",
|
||||
"token": "markup.heading"
|
||||
},
|
||||
{
|
||||
"fontStyle": "bold",
|
||||
"foreground": "#0550ae",
|
||||
"token": "markup.heading entity.name"
|
||||
},
|
||||
{
|
||||
"foreground": "#116329",
|
||||
"token": "markup.quote"
|
||||
},
|
||||
{
|
||||
"fontStyle": "italic",
|
||||
"foreground": "#24292f",
|
||||
"token": "markup.italic"
|
||||
},
|
||||
{
|
||||
"fontStyle": "bold",
|
||||
"foreground": "#24292f",
|
||||
"token": "markup.bold"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "markup.raw"
|
||||
},
|
||||
{
|
||||
"background": "#FFEBE9",
|
||||
"foreground": "#82071e",
|
||||
"token": "markup.deleted"
|
||||
},
|
||||
{
|
||||
"background": "#FFEBE9",
|
||||
"foreground": "#82071e",
|
||||
"token": "meta.diff.header.from-file"
|
||||
},
|
||||
{
|
||||
"background": "#FFEBE9",
|
||||
"foreground": "#82071e",
|
||||
"token": "punctuation.definition.deleted"
|
||||
},
|
||||
{
|
||||
"background": "#dafbe1",
|
||||
"foreground": "#116329",
|
||||
"token": "markup.inserted"
|
||||
},
|
||||
{
|
||||
"background": "#dafbe1",
|
||||
"foreground": "#116329",
|
||||
"token": "meta.diff.header.to-file"
|
||||
},
|
||||
{
|
||||
"background": "#dafbe1",
|
||||
"foreground": "#116329",
|
||||
"token": "punctuation.definition.inserted"
|
||||
},
|
||||
{
|
||||
"background": "#ffd8b5",
|
||||
"foreground": "#953800",
|
||||
"token": "markup.changed"
|
||||
},
|
||||
{
|
||||
"background": "#ffd8b5",
|
||||
"foreground": "#953800",
|
||||
"token": "punctuation.definition.changed"
|
||||
},
|
||||
{
|
||||
"foreground": "#eaeef2",
|
||||
"background": "#0550ae",
|
||||
"token": "markup.ignored"
|
||||
},
|
||||
{
|
||||
"foreground": "#eaeef2",
|
||||
"background": "#0550ae",
|
||||
"token": "markup.untracked"
|
||||
},
|
||||
{
|
||||
"foreground": "#8250df",
|
||||
"fontStyle": "bold",
|
||||
"token": "meta.diff.range"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "meta.diff.header"
|
||||
},
|
||||
{
|
||||
"fontStyle": "bold",
|
||||
"foreground": "#0550ae",
|
||||
"token": "meta.separator"
|
||||
},
|
||||
{
|
||||
"foreground": "#0550ae",
|
||||
"token": "meta.output"
|
||||
},
|
||||
{
|
||||
"foreground": "#57606a",
|
||||
"token": "brackethighlighter.tag"
|
||||
},
|
||||
{
|
||||
"foreground": "#57606a",
|
||||
"token": "brackethighlighter.curly"
|
||||
},
|
||||
{
|
||||
"foreground": "#57606a",
|
||||
"token": "brackethighlighter.round"
|
||||
},
|
||||
{
|
||||
"foreground": "#57606a",
|
||||
"token": "brackethighlighter.square"
|
||||
},
|
||||
{
|
||||
"foreground": "#57606a",
|
||||
"token": "brackethighlighter.angle"
|
||||
},
|
||||
{
|
||||
"foreground": "#57606a",
|
||||
"token": "brackethighlighter.quote"
|
||||
},
|
||||
{
|
||||
"foreground": "#82071e",
|
||||
"token": "brackethighlighter.unmatched"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"fontStyle": "underline",
|
||||
"token": "constant.other.reference.link"
|
||||
},
|
||||
{
|
||||
"foreground": "#0a3069",
|
||||
"fontStyle": "underline",
|
||||
"token": "string.other.link"
|
||||
}
|
||||
],
|
||||
"encodedTokensColors": []
|
||||
}
|
||||
276
src/components/CodeEditor/index.tsx
Normal file
276
src/components/CodeEditor/index.tsx
Normal file
@@ -0,0 +1,276 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import Editor, { EditorProps, useMonaco } from "@monaco-editor/react";
|
||||
import type { editor, languages } from "monaco-editor/esm/vs/editor/editor.api";
|
||||
import githubLightTheme from "./github-light-default.json";
|
||||
import githubDarkTheme from "./github-dark-default.json";
|
||||
|
||||
import { useTheme, Box, BoxProps } from "@mui/material";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
import ResizeBottomRightIcon from "assets/icons/ResizeBottomRight";
|
||||
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
import { getFieldProp } from "components/fields";
|
||||
|
||||
/* eslint-disable import/no-webpack-loader-syntax */
|
||||
import firestoreDefs from "!!raw-loader!./firestore.d.ts";
|
||||
import firebaseAuthDefs from "!!raw-loader!./firebaseAuth.d.ts";
|
||||
import firebaseStorageDefs from "!!raw-loader!./firebaseStorage.d.ts";
|
||||
import utilsDefs from "!!raw-loader!./utils.d.ts";
|
||||
import extensionsDefs from "!!raw-loader!./extensions.d.ts";
|
||||
|
||||
export interface ICodeEditorProps extends Partial<EditorProps> {
|
||||
value: string;
|
||||
minHeight?: number;
|
||||
disabled?: boolean;
|
||||
error?: boolean;
|
||||
containerProps?: Partial<BoxProps>;
|
||||
|
||||
extraLibs?: string[];
|
||||
onValidate?: EditorProps["onValidate"];
|
||||
onValidStatusUpdate?: (result: {
|
||||
isValid: boolean;
|
||||
markers: editor.IMarker[];
|
||||
}) => void;
|
||||
diagnosticsOptions?: languages.typescript.DiagnosticsOptions;
|
||||
onUnmount?: () => void;
|
||||
}
|
||||
|
||||
export default function CodeEditor({
|
||||
value,
|
||||
minHeight = 100,
|
||||
disabled,
|
||||
error,
|
||||
containerProps,
|
||||
|
||||
extraLibs,
|
||||
onValidate,
|
||||
onValidStatusUpdate,
|
||||
diagnosticsOptions,
|
||||
onUnmount,
|
||||
|
||||
...props
|
||||
}: ICodeEditorProps) {
|
||||
const theme = useTheme();
|
||||
const { tableState } = useProjectContext();
|
||||
|
||||
const [initialEditorValue] = useState(value ?? "");
|
||||
const monaco = useMonaco();
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
onUnmount?.();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onValidate_: EditorProps["onValidate"] = (markers) => {
|
||||
if (onValidStatusUpdate)
|
||||
onValidStatusUpdate({ isValid: markers.length <= 0, markers });
|
||||
else if (onValidate) onValidate(markers);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!monaco) {
|
||||
// useMonaco returns a monaco instance but initialisation is done asynchronously
|
||||
// dont execute the logic until the instance is initialised
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
try {
|
||||
monaco.editor.defineTheme("github-light", githubLightTheme as any);
|
||||
monaco.editor.defineTheme("github-dark", githubDarkTheme as any);
|
||||
monaco.editor.setTheme("github-" + theme.palette.mode);
|
||||
} catch (error) {
|
||||
console.error("Could not set Monaco theme: ", error);
|
||||
}
|
||||
});
|
||||
}, [monaco, theme.palette.mode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!monaco) {
|
||||
// useMonaco returns a monaco instance but initialisation is done asynchronously
|
||||
// dont execute the logic until the instance is initialised
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
monaco.editor.defineTheme("github-light", githubLightTheme as any);
|
||||
monaco.editor.defineTheme("github-dark", githubDarkTheme as any);
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(firestoreDefs);
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
firebaseAuthDefs
|
||||
);
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
firebaseStorageDefs
|
||||
);
|
||||
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions(
|
||||
diagnosticsOptions ?? {
|
||||
noSemanticValidation: true,
|
||||
noSyntaxValidation: false,
|
||||
}
|
||||
);
|
||||
// compiler options
|
||||
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
|
||||
target: monaco.languages.typescript.ScriptTarget.ES2020,
|
||||
allowNonTsExtensions: true,
|
||||
});
|
||||
if (extraLibs) {
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
extraLibs.join("\n"),
|
||||
"ts:filename/extraLibs.d.ts"
|
||||
);
|
||||
}
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
utilsDefs,
|
||||
"ts:filename/utils.d.ts"
|
||||
);
|
||||
|
||||
const rowDefinition =
|
||||
Object.keys(tableState?.columns!)
|
||||
.map((columnKey: string) => {
|
||||
const column = tableState?.columns[columnKey];
|
||||
return `static ${columnKey}: ${getFieldProp("type", column.type)}`;
|
||||
})
|
||||
.join(";\n") + ";";
|
||||
|
||||
const availableFields = Object.keys(tableState?.columns!)
|
||||
.map((columnKey: string) => `"${columnKey}"`)
|
||||
.join("|\n");
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
[
|
||||
"/**",
|
||||
" * extensions type configuration",
|
||||
" */",
|
||||
"// basic types that are used in all places",
|
||||
`type Row = {${rowDefinition}};`,
|
||||
`type Field = ${availableFields} | string | object;`,
|
||||
`type Fields = Field[];`,
|
||||
extensionsDefs,
|
||||
].join("\n"),
|
||||
"ts:filename/extensions.d.ts"
|
||||
);
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
[
|
||||
"declare var require: any;",
|
||||
"declare var Buffer: any;",
|
||||
"const ref: FirebaseFirestore.DocumentReference;",
|
||||
"const storage: firebasestorage.Storage;",
|
||||
"const db: FirebaseFirestore.Firestore;",
|
||||
"const auth: adminauth.BaseAuth;",
|
||||
"declare class row {",
|
||||
" /**",
|
||||
" * Returns the row fields",
|
||||
" */",
|
||||
rowDefinition,
|
||||
"}",
|
||||
].join("\n"),
|
||||
"ts:filename/rowFields.d.ts"
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"An error occurred during initialization of Monaco: ",
|
||||
error
|
||||
);
|
||||
}
|
||||
}, [tableState?.columns, monaco, diagnosticsOptions, extraLibs]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
minWidth: 400,
|
||||
minHeight,
|
||||
height: minHeight,
|
||||
borderRadius: 1,
|
||||
resize: "vertical",
|
||||
overflow: "hidden",
|
||||
position: "relative",
|
||||
backgroundColor: disabled ? "transparent" : theme.palette.action.input,
|
||||
|
||||
"&::after": {
|
||||
content: '""',
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
pointerEvents: "none",
|
||||
borderRadius: "inherit",
|
||||
|
||||
boxShadow: `0 -1px 0 0 ${theme.palette.text.disabled} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
transition: theme.transitions.create("box-shadow", {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
},
|
||||
|
||||
"&:hover::after": {
|
||||
boxShadow: `0 -1px 0 0 ${theme.palette.text.primary} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
},
|
||||
"&:focus-within::after": {
|
||||
boxShadow: `0 -2px 0 0 ${theme.palette.primary.main} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
},
|
||||
|
||||
...(error
|
||||
? {
|
||||
"&::after, &:hover::after, &:focus-within::after": {
|
||||
boxShadow: `0 -2px 0 0 ${theme.palette.error.main} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
|
||||
"& .editor": {
|
||||
// Overwrite user-select: none that causes editor
|
||||
// to not be focusable in Safari
|
||||
userSelect: "auto",
|
||||
height: "100%",
|
||||
},
|
||||
|
||||
"& .monaco-editor, & .monaco-editor .margin, & .monaco-editor-background":
|
||||
{
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
|
||||
...containerProps?.sx,
|
||||
}}
|
||||
>
|
||||
<Editor
|
||||
defaultLanguage="javascript"
|
||||
value={initialEditorValue}
|
||||
onValidate={onValidate_}
|
||||
loading={<CircularProgressOptical size={20} sx={{ m: 2 }} />}
|
||||
className="editor"
|
||||
{...props}
|
||||
options={{
|
||||
readOnly: disabled,
|
||||
fontFamily: theme.typography.fontFamilyMono,
|
||||
rulers: [80],
|
||||
minimap: { enabled: false },
|
||||
lineNumbersMinChars: 4,
|
||||
lineDecorationsWidth: 0,
|
||||
automaticLayout: true,
|
||||
fixedOverflowWidgets: true,
|
||||
tabSize: 2,
|
||||
...props.options,
|
||||
}}
|
||||
/>
|
||||
|
||||
<ResizeBottomRightIcon
|
||||
aria-label="This code editor is resizable"
|
||||
color="action"
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: 1,
|
||||
right: 1,
|
||||
zIndex: 1,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
50
src/components/CodeEditor/utils.d.ts
vendored
Normal file
50
src/components/CodeEditor/utils.d.ts
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* utility functions
|
||||
*/
|
||||
declare namespace utilFns {
|
||||
/**
|
||||
* Sends out an email through sendGrid
|
||||
*/
|
||||
function sendEmail(msg: {
|
||||
from: string;
|
||||
templateId: string;
|
||||
personalizations: { to: string; dynamic_template_data: any }[];
|
||||
}): void {}
|
||||
|
||||
/**
|
||||
* Gets the secret defined in Google Cloud Secret
|
||||
*/
|
||||
async function getSecret(name: string, v?: string): any {}
|
||||
|
||||
/**
|
||||
* Async version of forEach
|
||||
*/
|
||||
async function asyncForEach(array: any[], callback: Function): void {}
|
||||
|
||||
/**
|
||||
* Generate random ID from numbers and English characters including lowercase and uppercase
|
||||
*/
|
||||
function generateId(): string {}
|
||||
|
||||
/**
|
||||
* Add an item to an array field
|
||||
*/
|
||||
function arrayUnion(val: string): void {}
|
||||
|
||||
/**
|
||||
* Remove an item to an array field
|
||||
*/
|
||||
function arrayRemove(val: string): void {}
|
||||
|
||||
/**
|
||||
* Increment a number field
|
||||
*/
|
||||
function increment(val: number): void {}
|
||||
|
||||
function hasRequiredFields(requiredFields: string[], data: any): boolean {}
|
||||
|
||||
function hasAnyRole(
|
||||
authorizedRoles: string[],
|
||||
context: functions.https.CallableContext
|
||||
): boolean {}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
import React from "react";
|
||||
import { Component } from "react";
|
||||
import EmptyState, { IEmptyStateProps } from "./EmptyState";
|
||||
|
||||
import { Button } from "@mui/material";
|
||||
import ReloadIcon from "@mui/icons-material/Refresh";
|
||||
import InlineOpenInNewIcon from "components/InlineOpenInNewIcon";
|
||||
import meta from "../../package.json";
|
||||
class ErrorBoundary extends React.Component<
|
||||
|
||||
import meta from "@root/package.json";
|
||||
|
||||
class ErrorBoundary extends Component<
|
||||
IEmptyStateProps & { render?: (errorMessage: string) => React.ReactNode }
|
||||
> {
|
||||
state = { hasError: false, errorMessage: "" };
|
||||
@@ -25,13 +27,14 @@ class ErrorBoundary extends React.Component<
|
||||
if (this.state.hasError) {
|
||||
if (this.props.render) return this.props.render(this.state.errorMessage);
|
||||
|
||||
return (
|
||||
<EmptyState
|
||||
message="Something went wrong"
|
||||
description={
|
||||
<>
|
||||
<span>{this.state.errorMessage}</span>
|
||||
{this.state.errorMessage.startsWith("Loading chunk") ? (
|
||||
if (this.state.errorMessage.startsWith("Loading chunk"))
|
||||
return (
|
||||
<EmptyState
|
||||
Icon={ReloadIcon}
|
||||
message="New update available"
|
||||
description={
|
||||
<>
|
||||
<span>Reload this page to get the latest update</span>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
@@ -40,19 +43,28 @@ class ErrorBoundary extends React.Component<
|
||||
>
|
||||
Reload
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
href={
|
||||
meta.repository.url.replace(".git", "") +
|
||||
"/issues/new/choose"
|
||||
}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Report issue
|
||||
<InlineOpenInNewIcon />
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
fullScreen
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<EmptyState
|
||||
message="Something went wrong"
|
||||
description={
|
||||
<>
|
||||
<span>{this.state.errorMessage}</span>
|
||||
<Button
|
||||
href={
|
||||
meta.repository.url.replace(".git", "") + "/issues/new/choose"
|
||||
}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Report issue
|
||||
<InlineOpenInNewIcon />
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
fullScreen
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import { use100vh } from "react-div-100vh";
|
||||
|
||||
import {
|
||||
Fade,
|
||||
Stack,
|
||||
StackProps,
|
||||
CircularProgress,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { Fade, Stack, StackProps, Typography } from "@mui/material";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
|
||||
interface ILoadingProps extends Partial<StackProps> {
|
||||
message?: string;
|
||||
fullScreen?: boolean;
|
||||
@@ -33,7 +29,7 @@ export default function Loading({
|
||||
...props.style,
|
||||
}}
|
||||
>
|
||||
<CircularProgress />
|
||||
<CircularProgressOptical />
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
component="div"
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
Typography,
|
||||
ListItemSecondaryAction,
|
||||
Divider,
|
||||
Grow,
|
||||
@@ -25,8 +26,14 @@ export default function UserMenu(props: IconButtonProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [themeSubMenu, setThemeSubMenu] = useState<EventTarget | null>(null);
|
||||
|
||||
const { userDoc, theme, themeOverridden, setTheme, setThemeOverridden } =
|
||||
useAppContext();
|
||||
const {
|
||||
userDoc,
|
||||
theme,
|
||||
themeOverridden,
|
||||
setTheme,
|
||||
setThemeOverridden,
|
||||
projectId,
|
||||
} = useAppContext();
|
||||
|
||||
const displayName = userDoc?.state?.doc?.user?.displayName;
|
||||
const avatarUrl = userDoc?.state?.doc?.user?.photoURL;
|
||||
@@ -95,7 +102,13 @@ export default function UserMenu(props: IconButtonProps) {
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={displayName}
|
||||
secondary={email}
|
||||
secondary={
|
||||
<>
|
||||
{email}
|
||||
<br />
|
||||
<Typography variant="caption">Project: {projectId}</Typography>
|
||||
</>
|
||||
}
|
||||
primaryTypographyProps={{ variant: "subtitle1" }}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
@@ -44,15 +44,15 @@ const useStyles = makeStyles((theme) =>
|
||||
border: "none",
|
||||
|
||||
backgroundColor: theme.palette.action.input,
|
||||
boxShadow: `0 0 0 1px ${theme.palette.action.inputOutline} inset,
|
||||
0 -1px 0 0 ${theme.palette.text.disabled} inset`,
|
||||
boxShadow: `0 -1px 0 0 ${theme.palette.text.disabled} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
transition: theme.transitions.create("box-shadow", {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
|
||||
"&:hover": {
|
||||
boxShadow: `0 0 0 1px ${theme.palette.action.inputOutline} inset,
|
||||
0 -1px 0 0 ${theme.palette.text.primary} inset`,
|
||||
boxShadow: `0 -1px 0 0 ${theme.palette.text.primary} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -92,8 +92,8 @@ const useStyles = makeStyles((theme) =>
|
||||
|
||||
focus: {
|
||||
"& .tox.tox-tinymce, & .tox.tox-tinymce:hover": {
|
||||
boxShadow: `0 0 0 1px ${theme.palette.action.inputOutline} inset,
|
||||
0 -2px 0 0 ${theme.palette.primary.main} inset`,
|
||||
boxShadow: `0 -2px 0 0 ${theme.palette.primary.main} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -29,23 +29,6 @@ export default function Personalization({
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={settings.theme?.dark?.palette?.darker}
|
||||
onChange={(e) => {
|
||||
updateSettings({
|
||||
theme: _merge(settings.theme, {
|
||||
dark: { palette: { darker: e.target.checked } },
|
||||
}),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label="Darker dark theme"
|
||||
sx={{ my: -10 / 8 }}
|
||||
/>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
@@ -62,7 +45,7 @@ export default function Personalization({
|
||||
/>
|
||||
}
|
||||
label="Customize theme colors"
|
||||
style={{ marginLeft: -11, marginBottom: -10 }}
|
||||
style={{ marginLeft: -11, marginBottom: -10, marginTop: -10 }}
|
||||
/>
|
||||
|
||||
<Collapse in={customizedThemeColor} style={{ marginTop: 0 }}>
|
||||
|
||||
@@ -1,39 +1,68 @@
|
||||
import { IUserSettingsChildProps } from "pages/Settings/UserSettings";
|
||||
import _merge from "lodash/merge";
|
||||
|
||||
import {
|
||||
FormControl,
|
||||
RadioGroup,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
Divider,
|
||||
Checkbox,
|
||||
} from "@mui/material";
|
||||
|
||||
import { useAppContext } from "contexts/AppContext";
|
||||
|
||||
export default function Theme() {
|
||||
export default function Theme({
|
||||
settings,
|
||||
updateSettings,
|
||||
}: IUserSettingsChildProps) {
|
||||
const { theme, themeOverridden, setTheme, setThemeOverridden } =
|
||||
useAppContext();
|
||||
|
||||
return (
|
||||
<FormControl component="fieldset" variant="standard" sx={{ my: -10 / 8 }}>
|
||||
<legend style={{ fontSize: 0 }}>Theme</legend>
|
||||
<>
|
||||
<FormControl component="fieldset" variant="standard" sx={{ my: -10 / 8 }}>
|
||||
<legend style={{ fontSize: 0 }}>Theme</legend>
|
||||
|
||||
<RadioGroup
|
||||
value={themeOverridden ? theme : "system"}
|
||||
onChange={(e) => {
|
||||
if (e.target.value === "system") {
|
||||
setThemeOverridden(false);
|
||||
} else {
|
||||
setTheme(e.target.value as typeof theme);
|
||||
setThemeOverridden(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
control={<Radio />}
|
||||
value="system"
|
||||
label="Match system theme"
|
||||
/>
|
||||
<FormControlLabel control={<Radio />} value="light" label="Light" />
|
||||
<FormControlLabel control={<Radio />} value="dark" label="Dark" />
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<RadioGroup
|
||||
value={themeOverridden ? theme : "system"}
|
||||
onChange={(e) => {
|
||||
if (e.target.value === "system") {
|
||||
setThemeOverridden(false);
|
||||
} else {
|
||||
setTheme(e.target.value as typeof theme);
|
||||
setThemeOverridden(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
control={<Radio />}
|
||||
value="system"
|
||||
label="Match system theme"
|
||||
/>
|
||||
<FormControlLabel control={<Radio />} value="light" label="Light" />
|
||||
<FormControlLabel control={<Radio />} value="dark" label="Dark" />
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
|
||||
<Divider />
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={settings.theme?.dark?.palette?.darker}
|
||||
onChange={(e) => {
|
||||
updateSettings({
|
||||
theme: _merge(settings.theme, {
|
||||
dark: { palette: { darker: e.target.checked } },
|
||||
}),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label="Darker dark theme"
|
||||
style={{ marginLeft: -11, marginBottom: -10, marginTop: 13 }}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Stack, CircularProgress, Typography } from "@mui/material";
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import CheckIcon from "@mui/icons-material/Check";
|
||||
import ArrowIcon from "@mui/icons-material/ArrowForward";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
|
||||
export interface ISetupItemProps {
|
||||
status: "complete" | "loading" | "incomplete";
|
||||
@@ -25,12 +26,7 @@ export default function SetupItem({
|
||||
{status === "complete" ? (
|
||||
<CheckIcon aria-label="Item complete" color="action" />
|
||||
) : status === "loading" ? (
|
||||
<CircularProgress
|
||||
id="progress"
|
||||
size={20}
|
||||
thickness={5}
|
||||
sx={{ m: 0.25 }}
|
||||
/>
|
||||
<CircularProgressOptical id="progress" size={20} sx={{ m: 0.25 }} />
|
||||
) : (
|
||||
<ArrowIcon aria-label="Item" color="primary" />
|
||||
)}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { CONFIG } from "config/dbPaths";
|
||||
import { requiredRules, adminRules, utilFns } from "config/firestoreRules";
|
||||
import { rowyRun } from "utils/rowyRun";
|
||||
import { runRoutes } from "constants/runRoutes";
|
||||
import { useConfirmation } from "components/ConfirmationDialog";
|
||||
|
||||
export default function Step4Rules({
|
||||
rowyRunUrl,
|
||||
@@ -28,6 +29,7 @@ export default function Step4Rules({
|
||||
setCompletion,
|
||||
}: ISetupStepBodyProps) {
|
||||
const { projectId, getAuthToken } = useAppContext();
|
||||
const { requestConfirmation } = useConfirmation();
|
||||
|
||||
const [hasRules, setHasRules] = useState(completion.rules);
|
||||
const [adminRule, setAdminRule] = useState(true);
|
||||
@@ -83,13 +85,11 @@ export default function Step4Rules({
|
||||
body: { ruleset: newRules },
|
||||
});
|
||||
if (!res.success) throw new Error(res.message);
|
||||
|
||||
const isSuccessful = await checkRules(rowyRunUrl, authToken);
|
||||
if (isSuccessful) {
|
||||
setCompletion((c) => ({ ...c, rules: true }));
|
||||
setHasRules(true);
|
||||
}
|
||||
|
||||
setRulesStatus("IDLE");
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
@@ -97,6 +97,19 @@ export default function Step4Rules({
|
||||
}
|
||||
};
|
||||
|
||||
const handleSkip = () => {
|
||||
requestConfirmation({
|
||||
title: "Skip rules",
|
||||
body: "This might prevent you or other users in your project from accessing firestore data on Rowy",
|
||||
confirm: "Skip",
|
||||
cancel: "cancel",
|
||||
handleConfirm: async () => {
|
||||
setCompletion((c) => ({ ...c, rules: true }));
|
||||
setHasRules(true);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="inherit">
|
||||
@@ -201,15 +214,23 @@ export default function Step4Rules({
|
||||
Please check the generated rules first.
|
||||
</Typography>
|
||||
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={setRules}
|
||||
loading={rulesStatus === "LOADING"}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
Set Firestore Rules
|
||||
</LoadingButton>
|
||||
|
||||
{" "}
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={setRules}
|
||||
loading={rulesStatus === "LOADING"}
|
||||
>
|
||||
Set Firestore Rules
|
||||
</LoadingButton>
|
||||
<Button onClick={handleSkip}>Skip</Button>
|
||||
</div>
|
||||
{rulesStatus !== "LOADING" && typeof rulesStatus === "string" && (
|
||||
<Typography variant="caption" color="error">
|
||||
{rulesStatus}
|
||||
@@ -246,7 +267,6 @@ export const checkRules = async (
|
||||
sanitizedRules.includes(
|
||||
utilFns.replace(/\s{2,}/g, " ").replace(/\n/g, " ")
|
||||
);
|
||||
|
||||
return hasRules;
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
|
||||
@@ -51,8 +51,8 @@ export default function Form({ values }: IFormProps) {
|
||||
const { control, reset, formState, getValues } = methods;
|
||||
const { dirtyFields } = formState;
|
||||
|
||||
const column = sideDrawerRef?.current?.cell?.column;
|
||||
useEffect(() => {
|
||||
const column = sideDrawerRef?.current?.cell?.column;
|
||||
if (!column) return;
|
||||
|
||||
const labelElem = document.getElementById(
|
||||
@@ -65,7 +65,7 @@ export default function Form({ values }: IFormProps) {
|
||||
if (labelElem) labelElem.scrollIntoView({ behavior: "smooth" });
|
||||
if (fieldElem) fieldElem.focus({ preventScroll: true });
|
||||
}, 200);
|
||||
}, [sideDrawerRef?.current]);
|
||||
}, [column]);
|
||||
|
||||
return (
|
||||
<form>
|
||||
|
||||
@@ -46,18 +46,10 @@ export default function SideDrawer() {
|
||||
setCell!((cell) => ({ column: cell!.column, row }));
|
||||
|
||||
const idx = tableState?.columns[cell!.column]?.index;
|
||||
console.log(
|
||||
"selectCell",
|
||||
{ rowIdx: cell!.row, idx },
|
||||
dataGridRef?.current?.selectCell
|
||||
);
|
||||
dataGridRef?.current?.selectCell({ rowIdx: row, idx }, false);
|
||||
};
|
||||
|
||||
const [urlDocState, dispatchUrlDoc] = useDoc({});
|
||||
// useEffect(() => {
|
||||
// if (urlDocState.doc) setOpen(true);
|
||||
// }, [urlDocState]);
|
||||
|
||||
useEffect(() => {
|
||||
setOpen(false);
|
||||
@@ -83,7 +75,6 @@ export default function SideDrawer() {
|
||||
tableState?.rows[cell.row].ref.path
|
||||
)}`
|
||||
);
|
||||
// console.log(tableState?.tablePath, tableState?.rows[cell.row].id);
|
||||
if (urlDocState.doc) {
|
||||
urlDocState.unsubscribe();
|
||||
dispatchUrlDoc({ path: "", doc: null });
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { useState, Dispatch, SetStateAction, MutableRefObject } from "react";
|
||||
import { Stack, CircularProgress } from "@mui/material";
|
||||
|
||||
import { Stack } from "@mui/material";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
|
||||
export interface ISnackbarProgressRef {
|
||||
setProgress: Dispatch<SetStateAction<number>>;
|
||||
@@ -31,12 +33,11 @@ export default function SnackbarProgress({
|
||||
{progress}/{target}
|
||||
</span>
|
||||
|
||||
<CircularProgress
|
||||
<CircularProgressOptical
|
||||
value={(progress / target) * 100}
|
||||
variant="determinate"
|
||||
size={24}
|
||||
color="inherit"
|
||||
thickness={4}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -1,35 +1,21 @@
|
||||
import React from "react";
|
||||
import { lazy, Suspense, createElement } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { IMenuModalProps } from "..";
|
||||
|
||||
import { makeStyles, createStyles } from "@mui/styles";
|
||||
import Checkbox from "@mui/material/Checkbox";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import { Typography, TextField, MenuItem, ListItemText } from "@mui/material";
|
||||
import Subheading from "../Subheading";
|
||||
|
||||
import { getFieldProp } from "components/fields";
|
||||
import CodeEditorHelper from "components/CodeEditorHelper";
|
||||
import CodeEditor from "components/Table/editors/CodeEditor";
|
||||
import FieldSkeleton from "components/SideDrawer/Form/FieldSkeleton";
|
||||
import CodeEditorHelper from "@src/components/CodeEditor/CodeEditorHelper";
|
||||
import FormAutosave from "./FormAutosave";
|
||||
import { FieldType } from "constants/fields";
|
||||
import { WIKI_LINKS } from "constants/externalLinks";
|
||||
import { name } from "@root/package.json";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
typeSelect: { marginBottom: theme.spacing(1) },
|
||||
typeSelectItem: { whiteSpace: "normal" },
|
||||
|
||||
codeEditorContainer: {
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
|
||||
mono: {
|
||||
fontFamily: theme.typography.fontFamilyMono,
|
||||
},
|
||||
})
|
||||
const CodeEditor = lazy(
|
||||
() => import("components/CodeEditor" /* webpackChunkName: "CodeEditor" */)
|
||||
);
|
||||
|
||||
export interface IDefaultValueInputProps extends IMenuModalProps {
|
||||
@@ -43,7 +29,6 @@ export default function DefaultValueInput({
|
||||
fieldName,
|
||||
...props
|
||||
}: IDefaultValueInputProps) {
|
||||
const classes = useStyles();
|
||||
const _type =
|
||||
type !== FieldType.derivative
|
||||
? type
|
||||
@@ -64,13 +49,17 @@ export default function DefaultValueInput({
|
||||
value={config.defaultValue?.type ?? "undefined"}
|
||||
onChange={(e) => handleChange("defaultValue.type")(e.target.value)}
|
||||
fullWidth
|
||||
className={classes.typeSelect}
|
||||
sx={{ mb: 1 }}
|
||||
SelectProps={{
|
||||
MenuProps: {
|
||||
sx: { "& .MuiListItemText-root": { whiteSpace: "normal" } },
|
||||
},
|
||||
}}
|
||||
>
|
||||
<MenuItem value="undefined">
|
||||
<ListItemText
|
||||
primary="Undefined"
|
||||
secondary="No default value. The field will not appear in the row’s corresponding Firestore document by default."
|
||||
className={classes.typeSelectItem}
|
||||
/>
|
||||
</MenuItem>
|
||||
<MenuItem value="null">
|
||||
@@ -78,24 +67,21 @@ export default function DefaultValueInput({
|
||||
primary="Null"
|
||||
secondary={
|
||||
<>
|
||||
Initialise as <span className={classes.mono}>null</span>.
|
||||
Initialise as <code>null</code>.
|
||||
</>
|
||||
}
|
||||
className={classes.typeSelectItem}
|
||||
/>
|
||||
</MenuItem>
|
||||
<MenuItem value="static">
|
||||
<ListItemText
|
||||
primary="Static"
|
||||
secondary="Set a specific default value for all cells in this column."
|
||||
className={classes.typeSelectItem}
|
||||
/>
|
||||
</MenuItem>
|
||||
<MenuItem value="dynamic">
|
||||
<ListItemText
|
||||
primary={`Dynamic (Requires ${name} Cloud Functions)`}
|
||||
secondary={`Write code to set the default value using this table’s ${name} Cloud Function. Setup is required.`}
|
||||
className={classes.typeSelectItem}
|
||||
/>
|
||||
</MenuItem>
|
||||
</TextField>
|
||||
@@ -135,7 +121,7 @@ export default function DefaultValueInput({
|
||||
}
|
||||
/>
|
||||
|
||||
{React.createElement(customFieldInput, {
|
||||
{createElement(customFieldInput, {
|
||||
column: { type, key: fieldName, config, ...props, ...config },
|
||||
control,
|
||||
docRef: {},
|
||||
@@ -147,18 +133,12 @@ export default function DefaultValueInput({
|
||||
{config.defaultValue?.type === "dynamic" && (
|
||||
<>
|
||||
<CodeEditorHelper docLink={WIKI_LINKS.howToDefaultValues} />
|
||||
<div className={classes.codeEditorContainer}>
|
||||
<Suspense fallback={<FieldSkeleton height={100} />}>
|
||||
<CodeEditor
|
||||
height={120}
|
||||
script={config.defaultValue?.script}
|
||||
handleChange={handleChange("defaultValue.script")}
|
||||
editorOptions={{
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
}}
|
||||
value={config.defaultValue?.script}
|
||||
onChange={handleChange("defaultValue.script")}
|
||||
/>
|
||||
</div>
|
||||
</Suspense>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState, Suspense, useMemo, createElement } from "react";
|
||||
import _set from "lodash/set";
|
||||
import { IMenuModalProps } from "..";
|
||||
|
||||
import { Typography, Divider, Stack } from "@mui/material";
|
||||
import { Typography, Stack } from "@mui/material";
|
||||
|
||||
import Modal from "components/Modal";
|
||||
import { getFieldProp } from "components/fields";
|
||||
@@ -79,6 +79,7 @@ export default function FieldSettings(props: IMenuModalProps) {
|
||||
{createElement(customFieldSettings, {
|
||||
config: newConfig,
|
||||
handleChange,
|
||||
fieldName,
|
||||
})}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { lazy, Suspense } from "react";
|
||||
import { IExtensionModalStepProps } from "./ExtensionModal";
|
||||
import useStateRef from "react-usestateref";
|
||||
|
||||
import CodeEditor from "components/Table/editors/CodeEditor";
|
||||
import CodeEditorHelper from "components/CodeEditorHelper";
|
||||
|
||||
import FieldSkeleton from "components/SideDrawer/Form/FieldSkeleton";
|
||||
import CodeEditorHelper from "@src/components/CodeEditor/CodeEditorHelper";
|
||||
import { WIKI_LINKS } from "constants/externalLinks";
|
||||
|
||||
const CodeEditor = lazy(
|
||||
() => import("components/CodeEditor" /* webpackChunkName: "CodeEditor" */)
|
||||
);
|
||||
|
||||
const additionalVariables = [
|
||||
{
|
||||
key: "change",
|
||||
@@ -38,14 +42,14 @@ export default function Step3Conditions({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<Suspense fallback={<FieldSkeleton height={200} />}>
|
||||
<CodeEditor
|
||||
script={extensionObject.conditions}
|
||||
height={200}
|
||||
handleChange={(newValue) => {
|
||||
value={extensionObject.conditions}
|
||||
minHeight={200}
|
||||
onChange={(newValue) => {
|
||||
setExtensionObject({
|
||||
...extensionObject,
|
||||
conditions: newValue,
|
||||
conditions: newValue || "",
|
||||
});
|
||||
}}
|
||||
onValidStatusUpdate={({ isValid }) => {
|
||||
@@ -60,7 +64,7 @@ export default function Step3Conditions({
|
||||
onMount={() => setConditionEditorActive(true)}
|
||||
onUnmount={() => setConditionEditorActive(false)}
|
||||
/>
|
||||
</div>
|
||||
</Suspense>
|
||||
|
||||
<CodeEditorHelper
|
||||
docLink={WIKI_LINKS.extensions}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import { lazy, Suspense } from "react";
|
||||
import { IExtensionModalStepProps } from "./ExtensionModal";
|
||||
import _upperFirst from "lodash/upperFirst";
|
||||
import useStateRef from "react-usestateref";
|
||||
|
||||
import CodeEditor from "components/Table/editors/CodeEditor";
|
||||
import CodeEditorHelper from "components/CodeEditorHelper";
|
||||
import FieldSkeleton from "components/SideDrawer/Form/FieldSkeleton";
|
||||
import CodeEditorHelper from "@src/components/CodeEditor/CodeEditorHelper";
|
||||
|
||||
import { WIKI_LINKS } from "constants/externalLinks";
|
||||
|
||||
const CodeEditor = lazy(
|
||||
() => import("components/CodeEditor" /* webpackChunkName: "CodeEditor" */)
|
||||
);
|
||||
|
||||
const additionalVariables = [
|
||||
{
|
||||
key: "change",
|
||||
@@ -38,14 +43,14 @@ export default function Step4Body({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<Suspense fallback={<FieldSkeleton height={200} />}>
|
||||
<CodeEditor
|
||||
script={extensionObject.extensionBody}
|
||||
height={400}
|
||||
handleChange={(newValue) => {
|
||||
value={extensionObject.extensionBody}
|
||||
minHeight={400}
|
||||
onChange={(newValue) => {
|
||||
setExtensionObject({
|
||||
...extensionObject,
|
||||
extensionBody: newValue,
|
||||
extensionBody: newValue || "",
|
||||
});
|
||||
}}
|
||||
onValidStatusUpdate={({ isValid }) => {
|
||||
@@ -63,7 +68,7 @@ export default function Step4Body({
|
||||
onMount={() => setBodyEditorActive(true)}
|
||||
onUnmount={() => setBodyEditorActive(false)}
|
||||
/>
|
||||
</div>
|
||||
</Suspense>
|
||||
|
||||
<CodeEditorHelper
|
||||
docLink={
|
||||
|
||||
@@ -6,7 +6,7 @@ import LoopIcon from "@mui/icons-material/Loop";
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
import { db } from "../../../firebase";
|
||||
import { isCollectionGroup } from "utils/fns";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
|
||||
import Modal from "components/Modal";
|
||||
|
||||
@@ -61,7 +61,7 @@ export default function ReExecute() {
|
||||
primary: {
|
||||
children: "Confirm",
|
||||
onClick: handleConfirm,
|
||||
startIcon: updating && <CircularProgress size={16} />,
|
||||
startIcon: updating && <CircularProgressOptical size={16} />,
|
||||
disabled: updating,
|
||||
},
|
||||
secondary: {
|
||||
|
||||
@@ -12,7 +12,6 @@ import moment from "moment";
|
||||
import {
|
||||
Chip,
|
||||
Stack,
|
||||
CircularProgress,
|
||||
Typography,
|
||||
Box,
|
||||
Tabs,
|
||||
@@ -32,6 +31,7 @@ import CloseIcon from "@mui/icons-material/Close";
|
||||
import TableHeaderButton from "./TableHeaderButton";
|
||||
import Ansi from "ansi-to-react";
|
||||
import EmptyState from "components/EmptyState";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
|
||||
import PropTypes from "prop-types";
|
||||
import routes from "constants/routes";
|
||||
@@ -244,7 +244,7 @@ function LogPanel(props) {
|
||||
})}
|
||||
<div ref={liveStreamingRef} id="live-stream-target">
|
||||
{status === "BUILDING" && (
|
||||
<CircularProgress
|
||||
<CircularProgressOptical
|
||||
className={classes.logPanelProgress}
|
||||
size={30}
|
||||
/>
|
||||
@@ -371,7 +371,7 @@ function SnackLog({ log, onClose, onOpenPanel }) {
|
||||
})}
|
||||
<div ref={liveStreamingRef} id="live-stream-target-snack">
|
||||
{status === "BUILDING" && (
|
||||
<CircularProgress
|
||||
<CircularProgressOptical
|
||||
className={classes.logPanelProgress}
|
||||
size={30}
|
||||
/>
|
||||
@@ -427,10 +427,9 @@ export default function TableLogs() {
|
||||
<>
|
||||
<LogsIcon />
|
||||
{latestStatus === "BUILDING" && (
|
||||
<CircularProgress
|
||||
<CircularProgressOptical
|
||||
className={classes.toolbarStatusIcon}
|
||||
size={12}
|
||||
thickness={6}
|
||||
style={{ padding: 1 }}
|
||||
/>
|
||||
)}
|
||||
@@ -499,7 +498,7 @@ export default function TableLogs() {
|
||||
style={{ textAlign: "left" }}
|
||||
>
|
||||
{logEntry.status === "BUILDING" && (
|
||||
<CircularProgress size={24} />
|
||||
<CircularProgressOptical size={24} />
|
||||
)}
|
||||
{logEntry.status === "SUCCESS" && <SuccessIcon />}
|
||||
{logEntry.status === "FAIL" && <FailIcon />}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { IWebhookModalStepProps } from "./WebhookModal";
|
||||
import useStateRef from "react-usestateref";
|
||||
|
||||
import CodeEditor from "components/Table/editors/CodeEditor";
|
||||
import CodeEditorHelper from "components/CodeEditorHelper";
|
||||
import CodeEditor from "components/CodeEditor";
|
||||
import CodeEditorHelper from "components/CodeEditor/CodeEditorHelper";
|
||||
|
||||
import { WIKI_LINKS } from "constants/externalLinks";
|
||||
|
||||
@@ -26,12 +26,12 @@ export default function Step3Conditions({
|
||||
<>
|
||||
<div>
|
||||
<CodeEditor
|
||||
script={webhookObject.conditions}
|
||||
height={200}
|
||||
handleChange={(newValue) => {
|
||||
value={webhookObject.conditions}
|
||||
minHeight={200}
|
||||
onChange={(newValue) => {
|
||||
setWebhookObject({
|
||||
...webhookObject,
|
||||
conditions: newValue,
|
||||
conditions: newValue || "",
|
||||
});
|
||||
}}
|
||||
onValidStatusUpdate={({ isValid }) => {
|
||||
|
||||
@@ -2,8 +2,8 @@ import { IWebhookModalStepProps } from "./WebhookModal";
|
||||
import _upperFirst from "lodash/upperFirst";
|
||||
import useStateRef from "react-usestateref";
|
||||
|
||||
import CodeEditor from "components/Table/editors/CodeEditor";
|
||||
import CodeEditorHelper from "components/CodeEditorHelper";
|
||||
import CodeEditor from "components/CodeEditor";
|
||||
import CodeEditorHelper from "components/CodeEditor/CodeEditorHelper";
|
||||
|
||||
import { WIKI_LINKS } from "constants/externalLinks";
|
||||
|
||||
@@ -26,12 +26,12 @@ export default function Step4Body({
|
||||
<>
|
||||
<div>
|
||||
<CodeEditor
|
||||
script={webhookObject.parser}
|
||||
height={400}
|
||||
handleChange={(newValue) => {
|
||||
value={webhookObject.parser}
|
||||
minHeight={400}
|
||||
onChange={(newValue) => {
|
||||
setWebhookObject({
|
||||
...webhookObject,
|
||||
parser: newValue,
|
||||
parser: newValue || "",
|
||||
});
|
||||
}}
|
||||
onValidStatusUpdate={({ isValid }) => {
|
||||
|
||||
@@ -90,7 +90,7 @@ export default function WebhookList({
|
||||
onClick={handleAddButton}
|
||||
ref={addButtonRef}
|
||||
>
|
||||
Add Webhook…
|
||||
Add webhook…
|
||||
</Button>
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
|
||||
@@ -48,7 +48,7 @@ export default function WebhookModal({
|
||||
disableBackdropClick
|
||||
disableEscapeKeyDown
|
||||
fullWidth
|
||||
title={`Webhook Logs: ${webhookObject.name}`}
|
||||
title={`Webhook logs: ${webhookObject.name}`}
|
||||
sx={{
|
||||
"& .MuiPaper-root": {
|
||||
maxWidth: 742 + 20,
|
||||
|
||||
@@ -82,7 +82,7 @@ export default function WebhookModal({
|
||||
disableBackdropClick
|
||||
disableEscapeKeyDown
|
||||
fullWidth
|
||||
title={`${mode === "add" ? "Add" : "Update"} Webhook: ${
|
||||
title={`${mode === "add" ? "Add" : "Update"} webhook: ${
|
||||
webhookNames[webhookObject.type]
|
||||
}`}
|
||||
sx={{
|
||||
|
||||
@@ -25,9 +25,9 @@ export default function Webhooks() {
|
||||
const { requestConfirmation } = useConfirmation();
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
|
||||
const currentwebhooks = (tableState?.config.webhooks ?? []) as IWebhook[];
|
||||
const currentWebhooks = (tableState?.config.webhooks ?? []) as IWebhook[];
|
||||
const [localWebhooksObjects, setLocalWebhooksObjects] =
|
||||
useState(currentwebhooks);
|
||||
useState(currentWebhooks);
|
||||
const [openWebhookList, setOpenWebhookList] = useState(false);
|
||||
const [webhookModal, setWebhookModal] = useState<{
|
||||
mode: "add" | "update";
|
||||
@@ -36,7 +36,7 @@ export default function Webhooks() {
|
||||
} | null>(null);
|
||||
const [webhookLogs, setWebhookLogs] = useState<IWebhook | null>();
|
||||
|
||||
const edited = !_isEqual(currentwebhooks, localWebhooksObjects);
|
||||
const edited = !_isEqual(currentWebhooks, localWebhooksObjects);
|
||||
|
||||
const tablePathTokens =
|
||||
tableState?.tablePath?.split("/").filter(function (_, i) {
|
||||
@@ -55,7 +55,7 @@ export default function Webhooks() {
|
||||
body: "You will lose changes you have made to webhooks",
|
||||
confirm: "Discard",
|
||||
handleConfirm: () => {
|
||||
setLocalWebhooksObjects(currentwebhooks);
|
||||
setLocalWebhooksObjects(currentWebhooks);
|
||||
setOpenWebhookList(false);
|
||||
},
|
||||
});
|
||||
@@ -171,7 +171,7 @@ export default function Webhooks() {
|
||||
return (
|
||||
<>
|
||||
<TableHeaderButton
|
||||
title="Webhook"
|
||||
title="Webhooks"
|
||||
onClick={handleOpen}
|
||||
icon={<WebhookIcon />}
|
||||
/>
|
||||
|
||||
@@ -100,7 +100,6 @@ export default function TableHeader() {
|
||||
<>
|
||||
{/* Spacer */} <div />
|
||||
<Webhooks />
|
||||
{/* Spacer */} <div />
|
||||
<Extensions />
|
||||
<TableLogs />
|
||||
{(hasDerivatives || hasExtensions) && <ReExecute />}
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
import { useRef, useMemo, useState } from "react";
|
||||
import { makeStyles, createStyles } from "@mui/styles";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import Editor, { useMonaco } from "@monaco-editor/react";
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
import { FieldType } from "constants/fields";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
editorWrapper: {
|
||||
position: "relative",
|
||||
minWidth: 400,
|
||||
minHeight: 100,
|
||||
height: "calc(100% - 50px)",
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
overflow: "hidden",
|
||||
},
|
||||
|
||||
saveButton: {
|
||||
marginTop: theme.spacing(1),
|
||||
},
|
||||
editor: {
|
||||
// overwrite user-select: none that causes editor not focusable in Safari
|
||||
userSelect: "auto",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default function CodeEditor(props: any) {
|
||||
const {
|
||||
handleChange,
|
||||
extraLibs,
|
||||
height = 400,
|
||||
script,
|
||||
onValideStatusUpdate,
|
||||
diagnosticsOptions,
|
||||
onUnmount,
|
||||
onMount,
|
||||
} = props;
|
||||
const theme = useTheme();
|
||||
const monacoInstance = useMonaco();
|
||||
|
||||
const [initialEditorValue] = useState(script ?? "");
|
||||
const { tableState } = useProjectContext();
|
||||
const classes = useStyles();
|
||||
|
||||
const editorRef = useRef<any>();
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
onUnmount?.();
|
||||
};
|
||||
}, []);
|
||||
|
||||
function handleEditorDidMount(_, editor) {
|
||||
editorRef.current = editor;
|
||||
onMount?.();
|
||||
}
|
||||
|
||||
const themeTransformer = (theme: string) => {
|
||||
switch (theme) {
|
||||
case "dark":
|
||||
return "vs-dark";
|
||||
default:
|
||||
return theme;
|
||||
}
|
||||
};
|
||||
|
||||
useMemo(async () => {
|
||||
if (!monacoInstance) {
|
||||
// useMonaco returns a monaco instance but initialisation is done asynchronously
|
||||
// dont execute the logic until the instance is initialised
|
||||
return;
|
||||
}
|
||||
|
||||
const firestoreDefsFile = await fetch(
|
||||
`${process.env.PUBLIC_URL}/firestore.d.ts`
|
||||
);
|
||||
const firebaseAuthDefsFile = await fetch(
|
||||
`${process.env.PUBLIC_URL}/auth.d.ts`
|
||||
);
|
||||
const firebaseStorageDefsFile = await fetch(
|
||||
`${process.env.PUBLIC_URL}/storage.d.ts`
|
||||
);
|
||||
const firestoreDefs = await firestoreDefsFile.text();
|
||||
const firebaseStorageDefs = await firebaseStorageDefsFile.text();
|
||||
const firebaseAuthDefs = (await firebaseAuthDefsFile.text())
|
||||
?.replace("export", "declare")
|
||||
?.replace("admin.auth", "adminauth");
|
||||
|
||||
try {
|
||||
monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
firestoreDefs
|
||||
);
|
||||
monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
firebaseAuthDefs
|
||||
);
|
||||
monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
firebaseStorageDefs
|
||||
);
|
||||
monacoInstance.languages.typescript.javascriptDefaults.setDiagnosticsOptions(
|
||||
diagnosticsOptions ?? {
|
||||
noSemanticValidation: true,
|
||||
noSyntaxValidation: false,
|
||||
}
|
||||
);
|
||||
// compiler options
|
||||
monacoInstance.languages.typescript.javascriptDefaults.setCompilerOptions(
|
||||
{
|
||||
target: monacoInstance.languages.typescript.ScriptTarget.ES2020,
|
||||
allowNonTsExtensions: true,
|
||||
}
|
||||
);
|
||||
if (extraLibs) {
|
||||
monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
extraLibs.join("\n"),
|
||||
"ts:filename/extraLibs.d.ts"
|
||||
);
|
||||
}
|
||||
monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
[
|
||||
" /**",
|
||||
" * utility functions",
|
||||
" */",
|
||||
`
|
||||
declare namespace utilFns {
|
||||
/**
|
||||
* Sends out an email through sendGrid
|
||||
*/
|
||||
function sendEmail(msg: {
|
||||
from: string;
|
||||
templateId: string;
|
||||
personalizations: { to: string; dynamic_template_data: any }[];
|
||||
}): void {}
|
||||
|
||||
/**
|
||||
* Gets the secret defined in Google Cloud Secret
|
||||
*/
|
||||
async function getSecret(name: string, v?: string): any {}
|
||||
|
||||
/**
|
||||
* Async version of forEach
|
||||
*/
|
||||
async function asyncForEach(array: any[], callback: Function): void {}
|
||||
|
||||
/**
|
||||
* Generate random ID from numbers and English characters including lowercase and uppercase
|
||||
*/
|
||||
function generateId(): string {}
|
||||
|
||||
/**
|
||||
* Add an item to an array field
|
||||
*/
|
||||
function arrayUnion(val: string): void {}
|
||||
|
||||
/**
|
||||
* Remove an item to an array field
|
||||
*/
|
||||
function arrayRemove(val: string): void {}
|
||||
|
||||
/**
|
||||
* Increment a number field
|
||||
*/
|
||||
function increment(val: number): void {}
|
||||
|
||||
function hasRequiredFields(requiredFields: string[], data: any): boolean {}
|
||||
|
||||
function hasAnyRole(
|
||||
authorizedRoles: string[],
|
||||
context: functions.https.CallableContext
|
||||
): boolean {}
|
||||
}
|
||||
|
||||
`,
|
||||
].join("\n"),
|
||||
"ts:filename/utils.d.ts"
|
||||
);
|
||||
|
||||
const rowDefinition = [
|
||||
...Object.keys(tableState?.columns!).map((columnKey: string) => {
|
||||
const column = tableState?.columns[columnKey];
|
||||
switch (column.type) {
|
||||
case FieldType.shortText:
|
||||
case FieldType.longText:
|
||||
case FieldType.email:
|
||||
case FieldType.phone:
|
||||
case FieldType.code:
|
||||
return `${columnKey}:string`;
|
||||
case FieldType.singleSelect:
|
||||
const typeString = [
|
||||
...(column.config?.options?.map((opt) => `"${opt}"`) ?? []),
|
||||
].join(" | ");
|
||||
return `${columnKey}:${typeString}`;
|
||||
case FieldType.multiSelect:
|
||||
return `${columnKey}:string[]`;
|
||||
case FieldType.checkbox:
|
||||
return `${columnKey}:boolean`;
|
||||
default:
|
||||
return `${columnKey}:any`;
|
||||
}
|
||||
}),
|
||||
].join(";\n");
|
||||
|
||||
const availableFields = Object.keys(tableState?.columns!)
|
||||
.map((columnKey: string) => `"${columnKey}"`)
|
||||
.join("|\n");
|
||||
|
||||
const extensionsDefinition = `
|
||||
// basic types that are used in all places
|
||||
type Row = {${rowDefinition}};
|
||||
type Field = ${availableFields} | string | object;
|
||||
type Fields = Field[];
|
||||
type Trigger = "create" | "update" | "delete";
|
||||
type Triggers = Trigger[];
|
||||
|
||||
// function types that defines extension body and should run
|
||||
type Condition = boolean | ((data: ExtensionContext) => boolean | Promise<boolean>);
|
||||
|
||||
// the argument that the extension body takes in
|
||||
type ExtensionContext = {
|
||||
row: Row;
|
||||
ref:FirebaseFirestore.DocumentReference;
|
||||
storage:firebasestorage.Storage;
|
||||
db:FirebaseFirestore.Firestore;
|
||||
auth:adminauth.BaseAuth;
|
||||
change: any;
|
||||
triggerType: Triggers;
|
||||
fieldTypes: any;
|
||||
extensionConfig: {
|
||||
label: string;
|
||||
type: string;
|
||||
triggers: Trigger[];
|
||||
conditions: Condition;
|
||||
requiredFields: string[];
|
||||
extensionBody: any;
|
||||
};
|
||||
utilFns: any;
|
||||
}
|
||||
|
||||
// extension body definition
|
||||
type slackEmailBody = {
|
||||
channels?: string[];
|
||||
text?: string;
|
||||
emails: string[];
|
||||
blocks?: object[];
|
||||
attachments?: any;
|
||||
}
|
||||
|
||||
type slackChannelBody = {
|
||||
channels: string[];
|
||||
text?: string;
|
||||
emails?: string[];
|
||||
blocks?: object[];
|
||||
attachments?: any;
|
||||
}
|
||||
|
||||
type DocSyncBody = (context: ExtensionContext) => Promise<{
|
||||
fieldsToSync: Fields;
|
||||
row: Row;
|
||||
targetPath: string;
|
||||
}>
|
||||
|
||||
type HistorySnapshotBody = (context: ExtensionContext) => Promise<{
|
||||
trackedFields: Fields;
|
||||
}>
|
||||
|
||||
type AlgoliaIndexBody = (context: ExtensionContext) => Promise<{
|
||||
fieldsToSync: Fields;
|
||||
index: string;
|
||||
row: Row;
|
||||
objectID: string;
|
||||
}>
|
||||
|
||||
type MeiliIndexBody = (context: ExtensionContext) => Promise<{
|
||||
fieldsToSync: Fields;
|
||||
index: string;
|
||||
row: Row;
|
||||
objectID: string;
|
||||
}>
|
||||
|
||||
type BigqueryIndexBody = (context: ExtensionContext) => Promise<{
|
||||
fieldsToSync: Fields;
|
||||
index: string;
|
||||
row: Row;
|
||||
objectID: string;
|
||||
}>
|
||||
|
||||
type SlackMessageBody = (context: ExtensionContext) => Promise<slackEmailBody | slackChannelBody>;
|
||||
|
||||
type SendgridEmailBody = (context: ExtensionContext) => Promise<any>;
|
||||
|
||||
type ApiCallBody = (context: ExtensionContext) => Promise<{
|
||||
body: string;
|
||||
url: string;
|
||||
method: string;
|
||||
callback: any;
|
||||
}>
|
||||
|
||||
type TwilioMessageBody = (context: ExtensionContext) => Promise<{
|
||||
body: string;
|
||||
from: string;
|
||||
to: string;
|
||||
}>
|
||||
|
||||
type TaskBody = (context: ExtensionContext) => Promise<any>
|
||||
`;
|
||||
|
||||
monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
[
|
||||
" /**",
|
||||
" * extensions type configuration",
|
||||
" */",
|
||||
extensionsDefinition,
|
||||
].join("\n"),
|
||||
"ts:filename/extensions.d.ts"
|
||||
);
|
||||
|
||||
monacoInstance.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
[
|
||||
" declare var require: any;",
|
||||
" declare var Buffer: any;",
|
||||
" const ref:FirebaseFirestore.DocumentReference",
|
||||
" const storage:firebasestorage.Storage",
|
||||
" const db:FirebaseFirestore.Firestore;",
|
||||
" const auth:adminauth.BaseAuth;",
|
||||
"declare class row {",
|
||||
" /**",
|
||||
" * Returns the row fields",
|
||||
" */",
|
||||
...Object.keys(tableState?.columns!).map((columnKey: string) => {
|
||||
const column = tableState?.columns[columnKey];
|
||||
switch (column.type) {
|
||||
case FieldType.shortText:
|
||||
case FieldType.longText:
|
||||
case FieldType.email:
|
||||
case FieldType.phone:
|
||||
case FieldType.code:
|
||||
return `static ${columnKey}:string`;
|
||||
case FieldType.singleSelect:
|
||||
const typeString = [
|
||||
...(column.config?.options?.map((opt) => `"${opt}"`) ?? []),
|
||||
// "string",
|
||||
].join(" | ");
|
||||
return `static ${columnKey}:${typeString}`;
|
||||
case FieldType.multiSelect:
|
||||
return `static ${columnKey}:string[]`;
|
||||
case FieldType.checkbox:
|
||||
return `static ${columnKey}:boolean`;
|
||||
default:
|
||||
return `static ${columnKey}:any`;
|
||||
}
|
||||
}),
|
||||
"}",
|
||||
].join("\n"),
|
||||
"ts:filename/rowFields.d.ts"
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"An error occurred during initialization of Monaco: ",
|
||||
error
|
||||
);
|
||||
}
|
||||
}, [tableState?.columns, monacoInstance]);
|
||||
|
||||
function handleEditorValidation(markers) {
|
||||
if (onValideStatusUpdate) {
|
||||
onValideStatusUpdate({
|
||||
isValid: markers.length <= 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.editorWrapper}>
|
||||
<Editor
|
||||
theme={themeTransformer(theme.palette.mode)}
|
||||
onMount={handleEditorDidMount}
|
||||
language="javascript"
|
||||
height={height}
|
||||
value={initialEditorValue}
|
||||
onChange={handleChange}
|
||||
onValidate={handleEditorValidation}
|
||||
options={{
|
||||
// readOnly: disabled,
|
||||
fontFamily: theme.typography.fontFamilyMono,
|
||||
rulers: [80],
|
||||
minimap: { enabled: false },
|
||||
// ...editorOptions,
|
||||
}}
|
||||
className={classes.editor}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -91,10 +91,12 @@ export default function Step1Columns({
|
||||
const { tableState } = useProjectContext();
|
||||
const tableColumns = _sortBy(Object.values(tableState?.columns ?? {}), [
|
||||
"index",
|
||||
]).map((column) => ({
|
||||
label: column.name as string,
|
||||
value: column.key as string,
|
||||
}));
|
||||
])
|
||||
.filter((column) => column.type !== FieldType.id)
|
||||
.map((column) => ({
|
||||
label: column.name as string,
|
||||
value: column.key as string,
|
||||
}));
|
||||
|
||||
const [selectedFields, setSelectedFields] = useState(
|
||||
config.pairs.map((pair) => pair.csvKey)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import _find from "lodash/find";
|
||||
import { parseJSON } from "date-fns";
|
||||
|
||||
import { makeStyles, createStyles } from "@mui/styles";
|
||||
import { Grid } from "@mui/material";
|
||||
@@ -8,6 +9,7 @@ import Column from "../Column";
|
||||
import Cell from "../Cell";
|
||||
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
import { FieldType } from "constants/fields";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
@@ -81,7 +83,11 @@ export default function Step4Preview({ csvData, config }: IStepProps) {
|
||||
<Cell
|
||||
key={csvKey + i}
|
||||
field={columnKey}
|
||||
value={row[columnKey]}
|
||||
value={
|
||||
type === FieldType.date || type === FieldType.dateTime
|
||||
? parseJSON(row[columnKey])
|
||||
: row[columnKey]
|
||||
}
|
||||
type={type}
|
||||
name={name}
|
||||
/>
|
||||
|
||||
@@ -2,10 +2,11 @@ import { useState } from "react";
|
||||
import _get from "lodash/get";
|
||||
import { useSnackbar } from "notistack";
|
||||
|
||||
import { Fab, FabProps, CircularProgress } from "@mui/material";
|
||||
import { Fab, FabProps } from "@mui/material";
|
||||
import PlayIcon from "@mui/icons-material/PlayArrow";
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
import UndoIcon from "@mui/icons-material/Undo";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
import { functions } from "@src/firebase";
|
||||
@@ -159,7 +160,7 @@ export default function ActionFab({
|
||||
{...props}
|
||||
>
|
||||
{isRunning ? (
|
||||
<CircularProgress color="secondary" size={16} thickness={5.6} />
|
||||
<CircularProgressOptical color="secondary" size={16} />
|
||||
) : (
|
||||
getStateIcon(actionState)
|
||||
)}
|
||||
|
||||
@@ -11,10 +11,7 @@ import FieldSkeleton from "components/SideDrawer/Form/FieldSkeleton";
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
|
||||
const CodeEditor = lazy(
|
||||
() =>
|
||||
import(
|
||||
"components/Table/editors/CodeEditor" /* webpackChunkName: "CodeEditor" */
|
||||
)
|
||||
() => import("components/CodeEditor" /* webpackChunkName: "CodeEditor" */)
|
||||
);
|
||||
|
||||
const Settings = ({ config, handleChange }) => {
|
||||
@@ -93,8 +90,8 @@ const Settings = ({ config, handleChange }) => {
|
||||
<Typography variant="overline">action script</Typography>
|
||||
<Suspense fallback={<FieldSkeleton height={300} />}>
|
||||
<CodeEditor
|
||||
height={300}
|
||||
script={config.script}
|
||||
minHeight={300}
|
||||
value={config.script}
|
||||
extraLibs={[
|
||||
[
|
||||
"declare class ref {",
|
||||
@@ -121,9 +118,9 @@ const Settings = ({ config, handleChange }) => {
|
||||
} else return `static ${param.name}:any`;
|
||||
}),
|
||||
"}",
|
||||
],
|
||||
].join("\n"),
|
||||
]}
|
||||
handleChange={handleChange("script")}
|
||||
onChange={handleChange("script")}
|
||||
/>
|
||||
</Suspense>
|
||||
<FormControlLabel
|
||||
@@ -175,9 +172,9 @@ const Settings = ({ config, handleChange }) => {
|
||||
<Typography variant="overline">Undo action script</Typography>
|
||||
<Suspense fallback={<FieldSkeleton height={300} />}>
|
||||
<CodeEditor
|
||||
height={300}
|
||||
script={config["undo.script"]}
|
||||
handleChange={handleChange("undo.script")}
|
||||
minHeight={300}
|
||||
value={config["undo.script"]}
|
||||
onChange={handleChange("undo.script")}
|
||||
/>
|
||||
</Suspense>
|
||||
</>
|
||||
|
||||
@@ -6,10 +6,7 @@ import { FieldType } from "constants/fields";
|
||||
import FieldsDropdown from "components/Table/ColumnMenu/FieldsDropdown";
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
const CodeEditor = lazy(
|
||||
() =>
|
||||
import(
|
||||
"components/Table/editors/CodeEditor" /* webpackChunkName: "CodeEditor" */
|
||||
)
|
||||
() => import("components/CodeEditor" /* webpackChunkName: "CodeEditor" */)
|
||||
);
|
||||
|
||||
const Settings = ({ config, handleChange }) => {
|
||||
@@ -29,7 +26,7 @@ const Settings = ({ config, handleChange }) => {
|
||||
<Typography variant="overline">Aggergate script</Typography>
|
||||
<Suspense fallback={<FieldSkeleton height={200} />}>
|
||||
<CodeEditor
|
||||
script={
|
||||
value={
|
||||
config.script ??
|
||||
`//triggerType: create | update | delete\n//aggregateState: the subtable accumulator stored in the cell of this column\n//snapshot: the triggered document snapshot of the the subcollection\n//incrementor: short for firebase.firestore.FieldValue.increment(n);\n//This script needs to return the new aggregateState cell value.
|
||||
switch (triggerType){
|
||||
@@ -45,13 +42,13 @@ switch (triggerType){
|
||||
}
|
||||
extraLibs={[
|
||||
` /**
|
||||
* increaments firestore field value
|
||||
* increments firestore field value
|
||||
*/",
|
||||
function incrementor(value:number):number {
|
||||
|
||||
}`,
|
||||
]}
|
||||
handleChange={handleChange("script")}
|
||||
onChange={handleChange("script")}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
|
||||
@@ -2,46 +2,18 @@ import { Controller } from "react-hook-form";
|
||||
import { ISideDrawerFieldProps } from "../types";
|
||||
|
||||
import CodeEditor from "components/CodeEditor";
|
||||
import { makeStyles, createStyles } from "@mui/styles";
|
||||
|
||||
const useStyles = makeStyles((theme) =>
|
||||
createStyles({
|
||||
wrapper: {
|
||||
border: "1px solid",
|
||||
borderColor:
|
||||
theme.palette.mode === "light"
|
||||
? "rgba(0, 0, 0, 0.09)"
|
||||
: "rgba(255, 255, 255, 0.09)",
|
||||
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
overflow: "hidden",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default function Code({
|
||||
control,
|
||||
column,
|
||||
disabled,
|
||||
}: ISideDrawerFieldProps) {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Controller
|
||||
control={control}
|
||||
name={column.key}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<CodeEditor
|
||||
disabled={disabled}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
wrapperProps={{ className: classes.wrapper }}
|
||||
editorOptions={{
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<CodeEditor disabled={disabled} value={value} onChange={onChange} />
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -5,13 +5,14 @@ import { ButtonBase, Grid, Chip } from "@mui/material";
|
||||
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
|
||||
|
||||
import ChipList from "components/Table/formatters/ChipList";
|
||||
import { get } from "lodash";
|
||||
|
||||
export const ConnectService = forwardRef(function ConnectService(
|
||||
{ value, showPopoverCell, disabled, column }: IPopoverInlineCellProps,
|
||||
ref: React.Ref<any>
|
||||
) {
|
||||
const config = column.config ?? {};
|
||||
|
||||
const displayKey = config.titleKey ?? config.primaryKey;
|
||||
return (
|
||||
<ButtonBase
|
||||
onClick={() => showPopoverCell(true)}
|
||||
@@ -29,9 +30,9 @@ export const ConnectService = forwardRef(function ConnectService(
|
||||
>
|
||||
<ChipList>
|
||||
{Array.isArray(value) &&
|
||||
value.map((doc: any) => (
|
||||
<Grid item key={doc.primaryKey}>
|
||||
<Chip label={config.titleKey} size="small" />
|
||||
value.map((snapshot) => (
|
||||
<Grid item key={get(snapshot, config.primaryKey)}>
|
||||
<Chip label={get(snapshot, displayKey)} size="small" />
|
||||
</Grid>
|
||||
))}
|
||||
</ChipList>
|
||||
|
||||
@@ -16,8 +16,10 @@ import { useProjectContext } from "@src/contexts/ProjectContext";
|
||||
import { runRoutes } from "@src/constants/runRoutes";
|
||||
import { WIKI_LINKS } from "constants/externalLinks";
|
||||
|
||||
const useAlgoliaSearchKeys = createPersistedState("_ROWY_algolia-search-keys");
|
||||
const useAlgoliaAppId = createPersistedState("_ROWY_algolia-app-id");
|
||||
const useAlgoliaSearchKeys = createPersistedState(
|
||||
"__ROWY__ALGOLIA_SEARCH_KEYS"
|
||||
);
|
||||
const useAlgoliaAppId = createPersistedState("__ROWY__ALGOLIA_APP_ID");
|
||||
|
||||
export type ConnectTableValue = {
|
||||
docPath: string;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { IBasicCellProps } from "../types";
|
||||
import _isFunction from "lodash/isFunction";
|
||||
import _isDate from "lodash/isDate";
|
||||
import { format } from "date-fns";
|
||||
import { DATE_FORMAT } from "constants/dates";
|
||||
|
||||
@@ -6,9 +8,12 @@ export default function Date_({
|
||||
value,
|
||||
format: formatProp,
|
||||
}: IBasicCellProps & { format?: string }) {
|
||||
if (!!value && "toDate" in value) {
|
||||
if ((!!value && _isFunction(value.toDate)) || _isDate(value)) {
|
||||
try {
|
||||
const formatted = format(value.toDate(), formatProp || DATE_FORMAT);
|
||||
const formatted = format(
|
||||
_isDate(value) ? value : value.toDate(),
|
||||
formatProp || DATE_FORMAT
|
||||
);
|
||||
return (
|
||||
<span style={{ fontVariantNumeric: "tabular-nums" }}>{formatted}</span>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { IBasicCellProps } from "../types";
|
||||
import _isFunction from "lodash/isFunction";
|
||||
import _isDate from "lodash/isDate";
|
||||
import { format } from "date-fns";
|
||||
import { DATE_TIME_FORMAT } from "constants/dates";
|
||||
|
||||
@@ -6,9 +8,12 @@ export default function DateTime({
|
||||
value,
|
||||
format: formatProp,
|
||||
}: IBasicCellProps & { format?: string }) {
|
||||
if (!!value && "toDate" in value) {
|
||||
if ((!!value && _isFunction(value.toDate)) || _isDate(value)) {
|
||||
try {
|
||||
const formatted = format(value.toDate(), formatProp || DATE_TIME_FORMAT);
|
||||
const formatted = format(
|
||||
_isDate(value) ? value : value.toDate(),
|
||||
formatProp || DATE_TIME_FORMAT
|
||||
);
|
||||
return (
|
||||
<span style={{ fontVariantNumeric: "tabular-nums" }}>{formatted}</span>
|
||||
);
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
import { lazy, Suspense } from "react";
|
||||
import { ISettingsProps } from "../types";
|
||||
|
||||
import { Grid, InputLabel } from "@mui/material";
|
||||
import MultiSelect from "@rowy/multiselect";
|
||||
import FieldSkeleton from "components/SideDrawer/Form/FieldSkeleton";
|
||||
import { FieldType } from "constants/fields";
|
||||
import FieldsDropdown from "components/Table/ColumnMenu/FieldsDropdown";
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
import CodeEditorHelper from "components/CodeEditorHelper";
|
||||
import CodeEditorHelper from "@src/components/CodeEditor/CodeEditorHelper";
|
||||
|
||||
import { FieldType } from "constants/fields";
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
import { WIKI_LINKS } from "constants/externalLinks";
|
||||
|
||||
const CodeEditor = lazy(
|
||||
() =>
|
||||
import(
|
||||
"components/Table/editors/CodeEditor" /* webpackChunkName: "CodeEditor" */
|
||||
)
|
||||
() => import("components/CodeEditor" /* webpackChunkName: "CodeEditor" */)
|
||||
);
|
||||
|
||||
const Settings = ({ config, handleChange }) => {
|
||||
export default function Settings({
|
||||
config,
|
||||
handleChange,
|
||||
fieldName,
|
||||
}: ISettingsProps) {
|
||||
const { tableState } = useProjectContext();
|
||||
if (!tableState?.columns) return <></>;
|
||||
const columnOptions = Object.values(tableState.columns)
|
||||
.filter((column) => column.fieldName !== fieldName)
|
||||
.filter((column) => column.type !== FieldType.subTable)
|
||||
.map((c) => ({ label: c.name, value: c.key }));
|
||||
|
||||
@@ -63,13 +67,9 @@ const Settings = ({ config, handleChange }) => {
|
||||
<InputLabel>Derivative script</InputLabel>
|
||||
<CodeEditorHelper docLink={WIKI_LINKS.fieldTypesDerivative} />
|
||||
<Suspense fallback={<FieldSkeleton height={200} />}>
|
||||
<CodeEditor
|
||||
script={config.script}
|
||||
handleChange={handleChange("script")}
|
||||
/>
|
||||
<CodeEditor value={config.script} onChange={handleChange("script")} />
|
||||
</Suspense>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default Settings;
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ import {
|
||||
Grid,
|
||||
Tooltip,
|
||||
Chip,
|
||||
CircularProgress,
|
||||
} from "@mui/material";
|
||||
import UploadIcon from "assets/icons/Upload";
|
||||
import { FileIcon } from ".";
|
||||
|
||||
import Confirmation from "components/Confirmation";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
import { DATE_TIME_FORMAT } from "constants/dates";
|
||||
|
||||
import { useFieldStyles } from "components/SideDrawer/Form/utils";
|
||||
@@ -148,9 +148,7 @@ function ControlledFileUploader({
|
||||
<Chip
|
||||
icon={<FileIcon />}
|
||||
label={localFile}
|
||||
deleteIcon={
|
||||
<CircularProgress size={20} thickness={4.5} color="inherit" />
|
||||
}
|
||||
deleteIcon={<CircularProgressOptical size={20} color="inherit" />}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
@@ -6,17 +6,10 @@ import _findIndex from "lodash/findIndex";
|
||||
import { format } from "date-fns";
|
||||
|
||||
import { makeStyles, createStyles } from "@mui/styles";
|
||||
import {
|
||||
alpha,
|
||||
Stack,
|
||||
Grid,
|
||||
Tooltip,
|
||||
Chip,
|
||||
IconButton,
|
||||
CircularProgress,
|
||||
} from "@mui/material";
|
||||
import { alpha, Stack, Grid, Tooltip, Chip, IconButton } from "@mui/material";
|
||||
import UploadIcon from "assets/icons/Upload";
|
||||
import ChipList from "components/Table/formatters/ChipList";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
|
||||
import { useConfirmation } from "components/ConfirmationDialog";
|
||||
import useUploader, { FileValue } from "hooks/useTable/useUploader";
|
||||
@@ -184,11 +177,10 @@ export default function File_({
|
||||
)
|
||||
) : (
|
||||
<div style={{ padding: 4 }}>
|
||||
<CircularProgress
|
||||
<CircularProgressOptical
|
||||
size={24}
|
||||
variant={progress === 0 ? "indeterminate" : "determinate"}
|
||||
value={progress}
|
||||
thickness={4}
|
||||
style={{ display: "block" }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -7,14 +7,7 @@ import { useDropzone } from "react-dropzone";
|
||||
import useUploader from "hooks/useTable/useUploader";
|
||||
|
||||
import { makeStyles, createStyles } from "@mui/styles";
|
||||
import {
|
||||
alpha,
|
||||
ButtonBase,
|
||||
Typography,
|
||||
Grid,
|
||||
CircularProgress,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import { alpha, ButtonBase, Typography, Grid, Tooltip } from "@mui/material";
|
||||
|
||||
import AddIcon from "@mui/icons-material/AddAPhotoOutlined";
|
||||
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
|
||||
@@ -22,6 +15,7 @@ import OpenIcon from "@mui/icons-material/OpenInNewOutlined";
|
||||
|
||||
import { IMAGE_MIME_TYPES } from ".";
|
||||
import Thumbnail from "components/Thumbnail";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
import { useConfirmation } from "components/ConfirmationDialog";
|
||||
import { useProjectContext } from "contexts/ProjectContext";
|
||||
|
||||
@@ -247,7 +241,7 @@ function ControlledImageUploader({
|
||||
alignItems="center"
|
||||
className={classes.overlay}
|
||||
>
|
||||
<CircularProgress
|
||||
<CircularProgressOptical
|
||||
color="inherit"
|
||||
size={48}
|
||||
variant={progress === 0 ? "indeterminate" : "determinate"}
|
||||
|
||||
@@ -12,13 +12,13 @@ import {
|
||||
Grid,
|
||||
IconButton,
|
||||
ButtonBase,
|
||||
CircularProgress,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import AddIcon from "@mui/icons-material/AddAPhotoOutlined";
|
||||
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
|
||||
import OpenIcon from "@mui/icons-material/OpenInNewOutlined";
|
||||
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
import { useConfirmation } from "components/ConfirmationDialog";
|
||||
import useUploader, { FileValue } from "hooks/useTable/useUploader";
|
||||
import { IMAGE_MIME_TYPES } from "./index";
|
||||
@@ -272,11 +272,10 @@ export default function Image_({
|
||||
)
|
||||
) : (
|
||||
<div style={{ padding: 4 }}>
|
||||
<CircularProgress
|
||||
<CircularProgressOptical
|
||||
size={24}
|
||||
variant={progress === 0 ? "indeterminate" : "determinate"}
|
||||
value={progress}
|
||||
thickness={4}
|
||||
style={{ display: "block" }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
import { Switch, FormControlLabel } from "@mui/material";
|
||||
import { Checkbox, FormControlLabel, FormHelperText } from "@mui/material";
|
||||
|
||||
const Settings = ({ config, handleChange }) => {
|
||||
return (
|
||||
<>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
<Checkbox
|
||||
checked={config.isArray}
|
||||
onChange={() => handleChange("isArray")(!Boolean(config.isArray))}
|
||||
name="isArray"
|
||||
/>
|
||||
}
|
||||
label="Set as array"
|
||||
sx={{
|
||||
alignItems: "center",
|
||||
"& .MuiFormControlLabel-label": { mt: 0 },
|
||||
}}
|
||||
label={
|
||||
<>
|
||||
Default as array
|
||||
<FormHelperText>
|
||||
You can still set individual field values as a JSON object or
|
||||
array using the code editor
|
||||
</FormHelperText>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
import { useState } from "react";
|
||||
import { Controller } from "react-hook-form";
|
||||
import createPersistedState from "use-persisted-state";
|
||||
import { ISideDrawerFieldProps } from "../types";
|
||||
|
||||
import ReactJson from "react-json-view";
|
||||
import jsonFormat from "json-format";
|
||||
import CodeEditor from "components/CodeEditor";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
import { useTheme, Tab, FormHelperText } from "@mui/material";
|
||||
import TabContext from "@mui/lab/TabContext";
|
||||
import TabList from "@mui/lab/TabList";
|
||||
import TabPanel from "@mui/lab/TabPanel";
|
||||
import { useFieldStyles } from "components/SideDrawer/Form/utils";
|
||||
|
||||
const useJsonEditor = createPersistedState("__ROWY__JSON_EDITOR");
|
||||
|
||||
const isValidJson = (val: any) => {
|
||||
try {
|
||||
if (typeof val === "string") JSON.parse(val);
|
||||
@@ -25,11 +33,31 @@ export default function Json({
|
||||
const fieldClasses = useFieldStyles();
|
||||
const theme = useTheme();
|
||||
|
||||
const [editor, setEditor] = useJsonEditor<"tree" | "code">("tree");
|
||||
const [codeValid, setCodeValid] = useState(true);
|
||||
|
||||
const changeEditor = (_, newValue) => {
|
||||
setEditor(newValue);
|
||||
setCodeValid(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<Controller
|
||||
control={control}
|
||||
name={column.key}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
const sanitizedValue =
|
||||
value !== undefined && isValidJson(value)
|
||||
? value
|
||||
: column.config?.isArray
|
||||
? []
|
||||
: {};
|
||||
const formattedJson = jsonFormat(sanitizedValue, {
|
||||
type: "space",
|
||||
char: " ",
|
||||
size: 2,
|
||||
});
|
||||
|
||||
if (disabled)
|
||||
return (
|
||||
<div
|
||||
@@ -41,12 +69,7 @@ export default function Json({
|
||||
wordBreak: "break-word",
|
||||
}}
|
||||
>
|
||||
{value &&
|
||||
jsonFormat(value, {
|
||||
type: "space",
|
||||
char: " ",
|
||||
size: 2,
|
||||
})}
|
||||
{value && formattedJson}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -55,46 +78,68 @@ export default function Json({
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={fieldClasses.root}
|
||||
style={{ overflowX: "auto", ...theme.typography.caption }}
|
||||
>
|
||||
<ReactJson
|
||||
src={
|
||||
value !== undefined && isValidJson(value)
|
||||
? value
|
||||
: column.config?.isArray
|
||||
? []
|
||||
: {}
|
||||
}
|
||||
onEdit={handleEdit}
|
||||
onAdd={handleEdit}
|
||||
onDelete={handleEdit}
|
||||
theme={{
|
||||
base00: "rgba(0, 0, 0, 0)",
|
||||
base01: theme.palette.background.default,
|
||||
base02: theme.palette.divider,
|
||||
base03: "#93a1a1",
|
||||
base04: theme.palette.text.disabled,
|
||||
base05: theme.palette.text.secondary,
|
||||
base06: "#073642",
|
||||
base07: theme.palette.text.primary,
|
||||
base08: "#d33682",
|
||||
base09: "#cb4b16",
|
||||
base0A: "#dc322f",
|
||||
base0B: "#859900",
|
||||
base0C: "#6c71c4",
|
||||
base0D: theme.palette.text.secondary,
|
||||
base0E: "#2aa198",
|
||||
base0F: "#268bd2",
|
||||
<TabContext value={editor}>
|
||||
<TabList
|
||||
onChange={changeEditor}
|
||||
aria-label="JSON editor"
|
||||
variant="standard"
|
||||
sx={{
|
||||
minHeight: 32,
|
||||
mt: -32 / 8,
|
||||
|
||||
"& .MuiTabs-flexContainer": { justifyContent: "flex-end" },
|
||||
"& .MuiTab-root": { minHeight: 32, py: 0 },
|
||||
}}
|
||||
iconStyle="triangle"
|
||||
style={{
|
||||
fontFamily: theme.typography.fontFamilyMono,
|
||||
backgroundColor: "transparent",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
>
|
||||
<Tab label="Tree" value="tree" />
|
||||
<Tab label="Code" value="code" />
|
||||
</TabList>
|
||||
|
||||
<TabPanel value="tree" sx={{ p: 0 }}>
|
||||
<div
|
||||
className={fieldClasses.root}
|
||||
style={{ overflowX: "auto", ...theme.typography.caption }}
|
||||
>
|
||||
<ReactJson
|
||||
src={sanitizedValue}
|
||||
onEdit={handleEdit}
|
||||
onAdd={handleEdit}
|
||||
onDelete={handleEdit}
|
||||
theme={
|
||||
theme.palette.mode === "dark" ? "monokai" : "rjv-default"
|
||||
}
|
||||
iconStyle="triangle"
|
||||
style={{
|
||||
fontFamily: theme.typography.fontFamilyMono,
|
||||
backgroundColor: "transparent",
|
||||
minHeight: 100 - 4 - 4,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel value="code" sx={{ p: 0 }}>
|
||||
<CodeEditor
|
||||
defaultLanguage="json"
|
||||
value={formattedJson || "{\n \n}"}
|
||||
onChange={(v) => {
|
||||
try {
|
||||
if (v) onChange(JSON.parse(v));
|
||||
} catch (e) {
|
||||
console.log(`Failed to parse JSON: ${e}`);
|
||||
setCodeValid(false);
|
||||
}
|
||||
}}
|
||||
onValidStatusUpdate={({ isValid }) => setCodeValid(isValid)}
|
||||
error={!codeValid}
|
||||
/>
|
||||
{!codeValid && (
|
||||
<FormHelperText error variant="filled">
|
||||
Invalid JSON
|
||||
</FormHelperText>
|
||||
)}
|
||||
</TabPanel>
|
||||
</TabContext>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -61,9 +61,7 @@ export interface ISideDrawerFieldProps {
|
||||
export interface ISettingsProps {
|
||||
handleChange: (key: string) => (value: any) => void;
|
||||
config: Record<string, any>;
|
||||
// TODO: WRITE TYPES
|
||||
tables: any;
|
||||
[key: string]: any;
|
||||
fieldName: string;
|
||||
}
|
||||
|
||||
// TODO: WRITE TYPES
|
||||
|
||||
@@ -270,7 +270,7 @@ const useTableData = () => {
|
||||
: [];
|
||||
|
||||
const { path } = tableState;
|
||||
const newId = generateSmallerId(rows[0]?.id ?? "zzzzzzzzzzzzzzzzzzzzzzzz");
|
||||
const newId = generateSmallerId(rows[0]?.id ?? "zzzzzzzzzzzzzzzzzzzz");
|
||||
|
||||
if (missingRequiredFields.length === 0) {
|
||||
try {
|
||||
|
||||
@@ -48,7 +48,7 @@ export default function UserSettingsPage() {
|
||||
|
||||
const sections = [
|
||||
{ title: "Account", Component: Account, props: childProps },
|
||||
{ title: "Theme", Component: Theme },
|
||||
{ title: "Theme", Component: Theme, props: childProps },
|
||||
{ title: "Personalization", Component: Personalization, props: childProps },
|
||||
];
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import { useConfirmation } from "components/ConfirmationDialog";
|
||||
import SnackbarProgress, {
|
||||
ISnackbarProgressRef,
|
||||
} from "components/SnackbarProgress";
|
||||
import CircularProgressOptical from "components/CircularProgressOptical";
|
||||
|
||||
const typographyVariants = [
|
||||
"h1",
|
||||
@@ -913,7 +914,26 @@ export default function TestView() {
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
<CircularProgress />
|
||||
<Stack spacing={1} direction="row" alignItems="flex-end">
|
||||
{/* size 40 thickness 3.6 */}
|
||||
<CircularProgress />
|
||||
<CircularProgress size={30} thickness={4.2} />
|
||||
<CircularProgress size={24} thickness={4.8} />
|
||||
<CircularProgress size={20} thickness={5.4} />
|
||||
<CircularProgress size={16} thickness={6.3} />
|
||||
<CircularProgress size={12} thickness={7.8} />
|
||||
</Stack>
|
||||
|
||||
<Stack spacing={1} direction="row" alignItems="flex-end">
|
||||
{/* size 40 thickness 3.6 */}
|
||||
<CircularProgressOptical />
|
||||
<CircularProgressOptical size={30} />
|
||||
<CircularProgressOptical size={24} />
|
||||
<CircularProgressOptical size={20} />
|
||||
<CircularProgressOptical size={16} />
|
||||
<CircularProgressOptical size={12} />
|
||||
</Stack>
|
||||
|
||||
<LinearProgress />
|
||||
</Stack>
|
||||
</Container>
|
||||
|
||||
@@ -256,23 +256,23 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
backgroundColor: theme.palette.action.input,
|
||||
},
|
||||
|
||||
boxShadow: `0 0 0 1px ${theme.palette.action.inputOutline} inset,
|
||||
0 -1px 0 0 ${theme.palette.text.disabled} inset`,
|
||||
boxShadow: `0 -1px 0 0 ${theme.palette.text.disabled} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
transition: theme.transitions.create("box-shadow", {
|
||||
duration: theme.transitions.duration.short,
|
||||
}),
|
||||
|
||||
"&:hover": {
|
||||
boxShadow: `0 0 0 1px ${theme.palette.action.inputOutline} inset,
|
||||
0 -1px 0 0 ${theme.palette.text.primary} inset`,
|
||||
boxShadow: `0 -1px 0 0 ${theme.palette.text.primary} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
},
|
||||
"&.Mui-focused, &.Mui-focused:hover": {
|
||||
boxShadow: `0 0 0 1px ${theme.palette.action.inputOutline} inset,
|
||||
0 -2px 0 0 ${theme.palette.primary.main} inset`,
|
||||
boxShadow: `0 -2px 0 0 ${theme.palette.primary.main} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
},
|
||||
"&.Mui-error, &.Mui-error:hover": {
|
||||
boxShadow: `0 0 0 1px ${theme.palette.action.inputOutline} inset,
|
||||
0 -2px 0 0 ${theme.palette.error.main} inset`,
|
||||
boxShadow: `0 -2px 0 0 ${theme.palette.error.main} inset,
|
||||
0 0 0 1px ${theme.palette.action.inputOutline} inset`,
|
||||
},
|
||||
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
@@ -368,7 +368,7 @@ export const components = (theme: Theme): ThemeOptions => {
|
||||
root: {
|
||||
width: `calc(100% - ${theme.spacing(1)})`,
|
||||
margin: theme.spacing(0, 0.5),
|
||||
padding: theme.spacing(0.5, 0.75, 0.5, 1.5),
|
||||
padding: theme.spacing(0.5, 1.5),
|
||||
minHeight: 32,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
|
||||
|
||||
@@ -68,29 +68,56 @@ export const isCollectionGroup = () => {
|
||||
const pathName = window.location.pathname.split("/")[1];
|
||||
return pathName === "tableGroup";
|
||||
};
|
||||
var characters =
|
||||
|
||||
const characters =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
export function makeId(length) {
|
||||
var result = "";
|
||||
var charactersLength = characters.length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
export const makeId = (length: number = 20) => {
|
||||
let result = "";
|
||||
const charactersLength = characters.length;
|
||||
for (var i = 0; i < length; i++)
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
export const generateSmallerId = (id: string) => {
|
||||
const indexOfFirstChar = characters.indexOf(id[0]);
|
||||
if (indexOfFirstChar !== 0)
|
||||
return characters[indexOfFirstChar - 1] + makeId(id.length - 1);
|
||||
else return id[0] + generateSmallerId(id.substr(1, id.length - 1));
|
||||
const generated = id.split("");
|
||||
for (let i = generated.length - 1; i >= 0; i--) {
|
||||
const charIndex = characters.indexOf(id[i]);
|
||||
if (charIndex > 0) {
|
||||
generated[i] = characters[charIndex - 1];
|
||||
break;
|
||||
} else if (i > 0) {
|
||||
continue;
|
||||
} else {
|
||||
generated.push(characters[characters.length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we don't get 00...0, then the next ID would be 00...0z,
|
||||
// which would appear as the second row
|
||||
if (generated.every((char) => char === characters[0]))
|
||||
generated.push(characters[characters.length - 1]);
|
||||
|
||||
return generated.join("");
|
||||
};
|
||||
|
||||
export const generateBiggerId = (id: string) => {
|
||||
const indexOfFirstChar = characters.indexOf(id[0]);
|
||||
if (indexOfFirstChar !== 61)
|
||||
return characters[indexOfFirstChar + 1] + makeId(id.length - 1);
|
||||
else return id[0] + generateBiggerId(id.substr(1, id.length - 1));
|
||||
const generated = id.split("");
|
||||
for (let i = generated.length - 1; i >= 0; i--) {
|
||||
const charIndex = characters.indexOf(id[i]);
|
||||
console.log(i, id[i], charIndex);
|
||||
if (charIndex < characters.length - 1) {
|
||||
generated[i] = characters[charIndex + 1];
|
||||
break;
|
||||
} else if (i > 0) {
|
||||
continue;
|
||||
} else {
|
||||
generated.push(characters[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return generated.join("");
|
||||
};
|
||||
|
||||
// Gets sub-table ID in $1
|
||||
|
||||
@@ -6,3 +6,7 @@ declare module "*.mp4" {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
declare module "!!raw-loader!*" {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
@@ -2374,7 +2374,7 @@
|
||||
dependencies:
|
||||
state-local "^1.0.6"
|
||||
|
||||
"@monaco-editor/react@^4.1.0":
|
||||
"@monaco-editor/react@^4.3.1":
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.3.1.tgz#d65bcbf174c39b6d4e7fec43d0cddda82b70a12a"
|
||||
integrity sha512-f+0BK1PP/W5I50hHHmwf11+Ea92E5H1VZXs+wvKplWUWOfyMa1VVwqkJrXjRvbcqHL+XdIGYWhWNdi4McEvnZg==
|
||||
|
||||
Reference in New Issue
Block a user