mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-28 16:06:41 +01:00
new function wrappers with defs
This commit is contained in:
6
src/components/CodeEditor/rowy.d.ts
vendored
6
src/components/CodeEditor/rowy.d.ts
vendored
@@ -96,9 +96,3 @@ interface Rowy {
|
||||
}
|
||||
|
||||
declare const rowy: Rowy;
|
||||
type SecretNames = "sendgrid" | "unsplash" | "twilio";
|
||||
enum secrets {
|
||||
sendgrid = "sendgrid",
|
||||
unsplash = "unsplash",
|
||||
twilio = "twilio",
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ import firebaseStorageDefs from "!!raw-loader!./firebaseStorage.d.ts";
|
||||
import utilsDefs from "!!raw-loader!./utils.d.ts";
|
||||
import rowyUtilsDefs from "!!raw-loader!./rowy.d.ts";
|
||||
import extensionsDefs from "!!raw-loader!./extensions.d.ts";
|
||||
import derivativeDefs from "!!raw-loader!./derivative.d.ts";
|
||||
import defaultValueDefs from "!!raw-loader!./defaultValue.d.ts";
|
||||
import { runRoutes } from "@src/constants/runRoutes";
|
||||
|
||||
export interface IUseMonacoCustomizationsProps {
|
||||
minHeight?: number;
|
||||
@@ -53,7 +54,7 @@ export default function useMonacoCustomizations({
|
||||
fullScreen,
|
||||
}: IUseMonacoCustomizationsProps) {
|
||||
const theme = useTheme();
|
||||
const { tableState } = useProjectContext();
|
||||
const { tableState, rowyRun } = useProjectContext();
|
||||
|
||||
const monaco = useMonaco();
|
||||
|
||||
@@ -104,9 +105,6 @@ export default function useMonacoCustomizations({
|
||||
"ts:filename/utils.d.ts"
|
||||
);
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(rowyUtilsDefs);
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
derivativeDefs
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"An error occurred during initialization of Monaco: ",
|
||||
@@ -144,7 +142,6 @@ export default function useMonacoCustomizations({
|
||||
}, [monaco, stringifiedDiagnosticsOptions]);
|
||||
|
||||
const addJsonFieldDefinition = async (columnKey, interfaceName) => {
|
||||
// add delay
|
||||
const samples = tableState?.rows
|
||||
.map((row) => row[columnKey])
|
||||
.filter((entry) => entry !== undefined)
|
||||
@@ -168,19 +165,38 @@ export default function useMonacoCustomizations({
|
||||
rendererOptions: { "just-types": "true" },
|
||||
});
|
||||
const newLib = result.lines.join("\n").replaceAll("export ", "");
|
||||
console.log(newLib);
|
||||
// console.log(newLib);
|
||||
monaco?.languages.typescript.javascriptDefaults.addExtraLib(newLib);
|
||||
}
|
||||
};
|
||||
|
||||
const setSecrets = async (monaco, rowyRun) => {
|
||||
// set secret options
|
||||
try {
|
||||
const listSecrets = await rowyRun({
|
||||
route: runRoutes.listSecrets,
|
||||
});
|
||||
const secretsDef = `type SecretNames = ${listSecrets
|
||||
.map((secret) => `"${secret}"`)
|
||||
.join(" | ")}
|
||||
enum secrets {
|
||||
${listSecrets.map((secret) => `${secret} = "${secret}"`).join("\n")}
|
||||
}
|
||||
`;
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(secretsDef);
|
||||
} catch (error) {
|
||||
console.error("Could not set secret definitions: ", error);
|
||||
}
|
||||
};
|
||||
// Set row definitions
|
||||
useEffect(() => {
|
||||
if (!monaco) return;
|
||||
|
||||
if (!monaco || !rowyRun || !tableState?.columns) return;
|
||||
console.log("setting row definitions");
|
||||
try {
|
||||
const rowDefinition =
|
||||
Object.keys(tableState?.columns!)
|
||||
Object.keys(tableState.columns)
|
||||
.map((columnKey: string) => {
|
||||
const column = tableState?.columns[columnKey];
|
||||
const column = tableState.columns[columnKey];
|
||||
if (getColumnType(column) === "JSON") {
|
||||
const interfaceName =
|
||||
columnKey[0].toUpperCase() + columnKey.slice(1);
|
||||
@@ -194,7 +210,7 @@ export default function useMonacoCustomizations({
|
||||
})
|
||||
.join(";\n") + ";";
|
||||
|
||||
const availableFields = Object.keys(tableState?.columns!)
|
||||
const availableFields = Object.keys(tableState.columns)
|
||||
.map((columnKey: string) => `"${columnKey}"`)
|
||||
.join("|\n");
|
||||
|
||||
@@ -232,7 +248,13 @@ export default function useMonacoCustomizations({
|
||||
} catch (error) {
|
||||
console.error("Could not set row definitions: ", error);
|
||||
}
|
||||
}, [monaco, tableState?.columns]);
|
||||
// set available secrets from secretManager
|
||||
try {
|
||||
setSecrets(monaco, rowyRun);
|
||||
} catch (error) {
|
||||
console.error("Could not set secrets: ", error);
|
||||
}
|
||||
}, [monaco, tableState?.columns, rowyRun]);
|
||||
|
||||
let boxSx: SystemStyleObject<Theme> = {
|
||||
minWidth: 400,
|
||||
|
||||
@@ -13,16 +13,54 @@ import FormAutosave from "./FormAutosave";
|
||||
import { FieldType } from "@src/constants/fields";
|
||||
import { WIKI_LINKS } from "@src/constants/externalLinks";
|
||||
import { name } from "@root/package.json";
|
||||
|
||||
const CodeEditor = lazy(
|
||||
/* eslint-disable import/no-webpack-loader-syntax */
|
||||
import defaultValueDefs from "!!raw-loader!./defaultValue.d.ts";
|
||||
const _CodeEditor = lazy(
|
||||
() =>
|
||||
import("@src/components/CodeEditor" /* webpackChunkName: "CodeEditor" */)
|
||||
);
|
||||
|
||||
const diagnosticsOptions = {
|
||||
noSemanticValidation: false,
|
||||
noSyntaxValidation: false,
|
||||
noSuggestionDiagnostics: true,
|
||||
};
|
||||
|
||||
export interface IDefaultValueInputProps extends IMenuModalProps {
|
||||
handleChange: (key: any) => (update: any) => void;
|
||||
}
|
||||
|
||||
const CodeEditor = ({ type, config, handleChange }) => {
|
||||
const returnType = getFieldProp("dataType", type) ?? "any";
|
||||
const defaultValueFn = config.defaultValue?.defaultValueFn
|
||||
? config.defaultValue?.defaultValueFn
|
||||
: config.defaultValue?.script
|
||||
? `const defaultValueFn : DefaultValue = async ({row,ref,db,storage,auth})=>{
|
||||
${config.defaultValue.script}
|
||||
}`
|
||||
: `const defaultValueFn: DefaultValue = async ({row,ref,db,storage,auth})=>{
|
||||
// Write your default value code here
|
||||
// for example:
|
||||
// generate random hex color
|
||||
// const color = "#" + Math.floor(Math.random() * 16777215).toString(16);
|
||||
// return color;
|
||||
// checkout the documentation for more info: https://docs.rowy.io/how-to/default-values#dynamic
|
||||
}`;
|
||||
return (
|
||||
<_CodeEditor
|
||||
value={defaultValueFn}
|
||||
diagnosticsOptions={diagnosticsOptions}
|
||||
extraLibs={[
|
||||
defaultValueDefs.replace(
|
||||
`"PLACEHOLDER_OUTPUT_TYPE"`,
|
||||
`${returnType} | Promise<${returnType}>`
|
||||
),
|
||||
]}
|
||||
onChange={handleChange("defaultValue.defaultValueFn")}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default function DefaultValueInput({
|
||||
config,
|
||||
handleChange,
|
||||
@@ -42,6 +80,7 @@ export default function DefaultValueInput({
|
||||
config.defaultValue?.value ?? getFieldProp("initialValue", _type),
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<TextField
|
||||
@@ -136,8 +175,9 @@ export default function DefaultValueInput({
|
||||
<CodeEditorHelper docLink={WIKI_LINKS.howToDefaultValues} />
|
||||
<Suspense fallback={<FieldSkeleton height={100} />}>
|
||||
<CodeEditor
|
||||
value={config.defaultValue?.script}
|
||||
onChange={handleChange("defaultValue.script")}
|
||||
config={config}
|
||||
type={type}
|
||||
handleChange={handleChange}
|
||||
/>
|
||||
</Suspense>
|
||||
</>
|
||||
|
||||
8
src/components/Table/ColumnMenu/FieldSettings/defaultValue.d.ts
vendored
Normal file
8
src/components/Table/ColumnMenu/FieldSettings/defaultValue.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
type DefaultValueContext = {
|
||||
row: Row;
|
||||
ref: FirebaseFirestore.DocumentReference;
|
||||
storage: firebasestorage.Storage;
|
||||
db: FirebaseFirestore.Firestore;
|
||||
auth: firebaseauth.BaseAuth;
|
||||
};
|
||||
type DefaultValue = (context: DefaultValueContext) => "PLACEHOLDER_OUTPUT_TYPE";
|
||||
@@ -14,7 +14,6 @@ export default function ContextMenu() {
|
||||
const configActions =
|
||||
getFieldProp("contextMenuActions", selectedColumn.type) ||
|
||||
function empty() {};
|
||||
console.log(configActions);
|
||||
const actions = configActions(selectedCell, resetContextMenu) || [];
|
||||
|
||||
if (!anchorEle || actions.length === 0) return <></>;
|
||||
|
||||
@@ -32,6 +32,14 @@ import FormFieldSnippets from "./FormFieldSnippets";
|
||||
import { useProjectContext } from "@src/contexts/ProjectContext";
|
||||
import { WIKI_LINKS } from "@src/constants/externalLinks";
|
||||
import { useAppContext } from "@src/contexts/AppContext";
|
||||
/* eslint-disable import/no-webpack-loader-syntax */
|
||||
import actionDefs from "!!raw-loader!./action.d.ts";
|
||||
|
||||
const diagnosticsOptions = {
|
||||
noSemanticValidation: false,
|
||||
noSyntaxValidation: false,
|
||||
noSuggestionDiagnostics: true,
|
||||
};
|
||||
|
||||
const CodeEditor = lazy(
|
||||
() =>
|
||||
@@ -62,7 +70,7 @@ const Settings = ({ config, onChange }) => {
|
||||
|
||||
const scriptExtraLibs = [
|
||||
[
|
||||
"declare class actionParams {",
|
||||
"declare class ActionParams {",
|
||||
" /**",
|
||||
" * actionParams are provided by dialog popup form",
|
||||
" */",
|
||||
@@ -76,6 +84,7 @@ const Settings = ({ config, onChange }) => {
|
||||
}),
|
||||
"}",
|
||||
].join("\n"),
|
||||
actionDefs,
|
||||
];
|
||||
|
||||
// Backwards-compatibility: previously user could set `confirmation` without
|
||||
@@ -86,6 +95,72 @@ const Settings = ({ config, onChange }) => {
|
||||
typeof config.confirmation === "string" &&
|
||||
config.confirmation !== "");
|
||||
|
||||
const runFn = config.runFn
|
||||
? config.derivativeFn
|
||||
: config?.script
|
||||
? `const action:Action = async ({row,ref,db,storage,auth,actionParams,user}) => {
|
||||
${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.getSecret")}
|
||||
}`
|
||||
: `const action:Action = async ({row,ref,db,storage,auth,actionParams,user}) => {
|
||||
// Write your action code here
|
||||
// for example:
|
||||
// const authToken = await rowy.secrets.getSecret("service")
|
||||
// try {
|
||||
// const resp = await fetch('https://example.com/api/v1/users/'+ref.id,{
|
||||
// method: 'PUT',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'Authorization': authToken
|
||||
// },
|
||||
// body: JSON.stringify(row)
|
||||
// })
|
||||
//
|
||||
// return {
|
||||
// success: true,
|
||||
// message: 'User updated successfully on example service',
|
||||
// status: "upto date"
|
||||
// }
|
||||
// } catch (error) {
|
||||
// return {
|
||||
// success: false,
|
||||
// message: 'User update failed on example service',
|
||||
// }
|
||||
// }
|
||||
// checkout the documentation for more info: https://docs.rowy.io/field-types/action#script
|
||||
}`;
|
||||
|
||||
const undoFn = config.undoFn
|
||||
? config.undoFn
|
||||
: _get(config, "undo.script")
|
||||
? `const action:Action = async ({row,ref,db,storage,auth,actionParams,user}) => {
|
||||
${_get(config, "undo.script")}
|
||||
}`
|
||||
: `const action:Action = async ({row,ref,db,storage,auth,actionParams,user}) => {
|
||||
// Write your undo code here
|
||||
// for example:
|
||||
// const authToken = await rowy.secrets.getSecret("service")
|
||||
// try {
|
||||
// const resp = await fetch('https://example.com/api/v1/users/'+ref.id,{
|
||||
// method: 'DELETE',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// 'Authorization': authToken
|
||||
// },
|
||||
// body: JSON.stringify(row)
|
||||
// })
|
||||
//
|
||||
// return {
|
||||
// success: true,
|
||||
// message: 'User deleted successfully on example service',
|
||||
// status: null
|
||||
// }
|
||||
// } catch (error) {
|
||||
// return {
|
||||
// success: false,
|
||||
// message: 'User delete failed on example service',
|
||||
// }
|
||||
// }
|
||||
}`;
|
||||
return (
|
||||
<SteppedAccordion
|
||||
steps={[
|
||||
@@ -338,9 +413,10 @@ const Settings = ({ config, onChange }) => {
|
||||
<Suspense fallback={<FieldSkeleton height={300} />}>
|
||||
<CodeEditor
|
||||
minHeight={200}
|
||||
value={config.script}
|
||||
onChange={onChange("script")}
|
||||
value={runFn}
|
||||
onChange={onChange("runFn")}
|
||||
extraLibs={scriptExtraLibs}
|
||||
diagnosticsOptions={diagnosticsOptions}
|
||||
/>
|
||||
</Suspense>
|
||||
<CodeEditorHelper
|
||||
@@ -447,8 +523,8 @@ const Settings = ({ config, onChange }) => {
|
||||
<InputLabel variant="filled">Undo script</InputLabel>
|
||||
<Suspense fallback={<FieldSkeleton height={300} />}>
|
||||
<CodeEditor
|
||||
value={_get(config, "undo.script")}
|
||||
onChange={onChange("undo.script")}
|
||||
value={undoFn}
|
||||
onChange={onChange("undoFn")}
|
||||
extraLibs={scriptExtraLibs}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
26
src/components/fields/Action/action.d.ts
vendored
Normal file
26
src/components/fields/Action/action.d.ts
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
type ActionUser = {
|
||||
timestamp: Date;
|
||||
displayName: string;
|
||||
email: string;
|
||||
uid: string;
|
||||
emailVerified: boolean;
|
||||
photoURL: string;
|
||||
roles: string[];
|
||||
};
|
||||
type ActionContext = {
|
||||
row: Row;
|
||||
ref: FirebaseFirestore.DocumentReference;
|
||||
storage: firebasestorage.Storage;
|
||||
db: FirebaseFirestore.Firestore;
|
||||
auth: firebaseauth.BaseAuth;
|
||||
actionParams: ActionParams;
|
||||
user: ActionUser;
|
||||
};
|
||||
|
||||
type ActionResult = {
|
||||
success: boolean;
|
||||
message?: any;
|
||||
status?: string | number | null | undefined;
|
||||
};
|
||||
|
||||
type Action = (context: ActionContext) => Promise<ActionResult> | ActionResult;
|
||||
@@ -29,6 +29,7 @@ export default function ContextMenuActions(
|
||||
const selectedRowIndex = selectedCell.rowIndex as number;
|
||||
const selectedColIndex = selectedCell?.colIndex;
|
||||
const selectedCol = _find(columns, { index: selectedColIndex });
|
||||
if (!selectedCol) return [];
|
||||
const selectedRow = rows?.[selectedRowIndex];
|
||||
const cellValue = _get(selectedRow, selectedCol.key);
|
||||
console.log({
|
||||
|
||||
@@ -11,10 +11,15 @@ import { FieldType } from "@src/constants/fields";
|
||||
import { useProjectContext } from "@src/contexts/ProjectContext";
|
||||
import { WIKI_LINKS } from "@src/constants/externalLinks";
|
||||
|
||||
import { getFieldProp } from "@src/components/fields";
|
||||
/* eslint-disable import/no-webpack-loader-syntax */
|
||||
import derivativeDefs from "!!raw-loader!./derivative.d.ts";
|
||||
|
||||
const CodeEditor = lazy(
|
||||
() =>
|
||||
import("@src/components/CodeEditor" /* webpackChunkName: "CodeEditor" */)
|
||||
);
|
||||
|
||||
const diagnosticsOptions = {
|
||||
noSemanticValidation: false,
|
||||
noSyntaxValidation: false,
|
||||
@@ -30,14 +35,15 @@ export default function Settings({
|
||||
}: ISettingsProps) {
|
||||
const { tableState } = useProjectContext();
|
||||
if (!tableState?.columns) return <></>;
|
||||
|
||||
const columnOptions = Object.values(tableState.columns)
|
||||
const columns = Object.values(tableState.columns);
|
||||
const returnType = getFieldProp("dataType", config.renderFieldType) ?? "any";
|
||||
console.log({ returnType, r: config.renderFieldType });
|
||||
const columnOptions = columns
|
||||
.filter((column) => column.fieldName !== fieldName)
|
||||
.filter((column) => column.type !== FieldType.subTable)
|
||||
.map((c) => ({ label: c.name, value: c.key }));
|
||||
console.log({ config });
|
||||
const code = config.code
|
||||
? config.code
|
||||
const code = config.derivativeFn
|
||||
? config.derivativeFn
|
||||
: config?.script
|
||||
? `const derivative:Derivative = async ({row,ref,db,storage,auth})=>{
|
||||
${config.script.replace(/utilFns.getSecret/g, "rowy.secrets.getSecret")}
|
||||
@@ -114,6 +120,12 @@ export default function Settings({
|
||||
<CodeEditor
|
||||
diagnosticsOptions={diagnosticsOptions}
|
||||
value={code}
|
||||
extraLibs={[
|
||||
derivativeDefs.replace(
|
||||
`"PLACEHOLDER_OUTPUT_TYPE"`,
|
||||
`${returnType} | Promise<${returnType}>`
|
||||
),
|
||||
]}
|
||||
onChange={onChange("code")}
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
@@ -7,4 +7,4 @@ type DerivativeContext = {
|
||||
change: any;
|
||||
};
|
||||
|
||||
type Derivative = (context: DerivativeContext) => Promise<any>;
|
||||
type Derivative = (context: DerivativeContext) => "PLACEHOLDER_OUTPUT_TYPE";
|
||||
@@ -18,8 +18,7 @@ export const config: IFieldConfig = {
|
||||
type: FieldType.image,
|
||||
name: "Image",
|
||||
group: "File",
|
||||
dataType:
|
||||
"{ downloadURL: string; lastModifiedTS: number; name: string; type: string; ref: string; }[]",
|
||||
dataType: "RowyFile[]",
|
||||
initialValue: [],
|
||||
icon: <ImageIcon />,
|
||||
description:
|
||||
|
||||
@@ -27,6 +27,7 @@ export default function BasicContextMenuActions(
|
||||
const selectedRowIndex = selectedCell.rowIndex as number;
|
||||
const selectedColIndex = selectedCell?.colIndex;
|
||||
const selectedCol = _find(columns, { index: selectedColIndex });
|
||||
if (!selectedCol) return [];
|
||||
const selectedRow = rows?.[selectedRowIndex];
|
||||
const cellValue = _get(selectedRow, selectedCol.key);
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ export const runRoutes = {
|
||||
firestoreRules: { path: "/firestoreRules", method: "GET" } as RunRoute,
|
||||
setFirestoreRules: { path: "/setFirestoreRules", method: "POST" } as RunRoute,
|
||||
listCollections: { path: "/listCollections", method: "GET" } as RunRoute,
|
||||
listSecrets: { path: "/listSecrets", method: "GET" } as RunRoute,
|
||||
serviceAccountAccess: {
|
||||
path: "/serviceAccountAccess",
|
||||
method: "GET",
|
||||
|
||||
@@ -17,7 +17,7 @@ export const rowyRun = async ({
|
||||
route,
|
||||
body,
|
||||
params,
|
||||
localhost = false,
|
||||
localhost = true,
|
||||
json = true,
|
||||
signal,
|
||||
}: IRowyRunRequestProps) => {
|
||||
|
||||
Reference in New Issue
Block a user