Fix/Next.js-13/Circular Dependency in Routing Forms (#6321)

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
This commit is contained in:
Hariom Balhara
2023-01-07 15:50:28 +00:00
committed by GitHub
co-authored by Peer Richelsen
parent b1193eef1e
commit 364e187080
10 changed files with 100 additions and 88 deletions
@@ -1,8 +1,8 @@
import { App_RoutingForms_Form } from "@prisma/client";
import { Dispatch, SetStateAction } from "react";
import { getQueryBuilderConfig } from "../lib/getQueryBuilderConfig";
import isRouterLinkedField from "../lib/isRouterLinkedField";
import { getQueryBuilderConfig } from "../pages/route-builder/[...appPages]";
import { SerializableForm, Response } from "../types/types";
type Props = {
@@ -35,9 +35,9 @@ import {
VerticalDivider,
} from "@calcom/ui";
import { RoutingPages } from "../lib/RoutingPages";
import { getSerializableForm } from "../lib/getSerializableForm";
import { processRoute } from "../lib/processRoute";
import { RoutingPages } from "../pages/route-builder/[...appPages]";
import { Response, Route, SerializableForm } from "../types/types";
import { FormAction, FormActionsDropdown, FormActionsProvider } from "./FormActions";
import FormInputFields from "./FormInputFields";
@@ -0,0 +1,3 @@
import QueryBuilderInitialConfig from "../components/react-awesome-query-builder/config/config";
export const InitialConfig = QueryBuilderInitialConfig;
@@ -0,0 +1,16 @@
import { LocalRoute } from "../types/types";
export const RoutingPages: { label: string; value: NonNullable<LocalRoute["action"]>["type"] }[] = [
{
label: "Custom Page",
value: "customPageMessage",
},
{
label: "External Redirect",
value: "externalRedirectUrl",
},
{
label: "Event Redirect",
value: "eventTypeRedirectUrl",
},
];
@@ -0,0 +1,63 @@
import { FieldTypes } from "../pages/form-edit/[...appPages]";
import { QueryBuilderUpdatedConfig, RoutingForm } from "../types/types";
import { InitialConfig } from "./InitialConfig";
export function getQueryBuilderConfig(form: RoutingForm, forReporting = false) {
const fields: Record<
string,
{
label: string;
type: string;
valueSources: ["value"];
fieldSettings: {
listValues?: {
value: string;
title: string;
}[];
};
}
> = {};
form.fields?.forEach((field) => {
if ("routerField" in field) {
field = field.routerField;
}
if (FieldTypes.map((f) => f.value).includes(field.type)) {
const optionValues = field.selectText?.trim().split("\n");
const options = optionValues?.map((value) => {
const title = value;
return {
value,
title,
};
});
const widget = InitialConfig.widgets[field.type];
const widgetType = widget.type;
fields[field.id] = {
label: field.label,
type: widgetType,
valueSources: ["value"],
fieldSettings: {
listValues: options,
},
// preferWidgets: field.type === "textarea" ? ["textarea"] : [],
};
} else {
throw new Error("Unsupported field type:" + field.type);
}
});
const initialConfigCopy = { ...InitialConfig, operators: { ...InitialConfig.operators } };
if (forReporting) {
delete initialConfigCopy.operators.is_empty;
delete initialConfigCopy.operators.is_not_empty;
initialConfigCopy.operators.__calReporting = true;
}
// You need to provide your own config. See below 'Config format'
const config: QueryBuilderUpdatedConfig = {
...initialConfigCopy,
fields: fields,
};
return config;
}
@@ -2,9 +2,9 @@ import jsonLogic from "json-logic-js";
import { Utils as QbUtils } from "react-awesome-query-builder";
import { z } from "zod";
import { getQueryBuilderConfig } from "../pages/route-builder/[...appPages]";
import { Response, Route, SerializableForm } from "../types/types";
import { zodNonRouterRoute } from "../zod";
import { getQueryBuilderConfig } from "./getQueryBuilderConfig";
import { isFallbackRoute } from "./isFallbackRoute";
import isRouter from "./isRouter";
import { App_RoutingForms_Form } from ".prisma/client";
@@ -24,7 +24,7 @@ import SingleForm, {
import QueryBuilderInitialConfig from "../../components/react-awesome-query-builder/config/config";
import "../../components/react-awesome-query-builder/styles.css";
import { JsonLogicQuery } from "../../jsonLogicToPrisma";
import { getQueryBuilderConfig } from "../route-builder/[...appPages]";
import { getQueryBuilderConfig } from "../../lib/getQueryBuilderConfig";
export { getServerSideProps };
@@ -1,8 +1,7 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { App_RoutingForms_Form } from "@prisma/client";
import Link from "next/link";
import React, { useCallback, useState } from "react";
import { Query, Config, Builder, Utils as QbUtils } from "react-awesome-query-builder";
import { Query, Builder, Utils as QbUtils } from "react-awesome-query-builder";
// types
import { JsonTree, ImmutableTree, BuilderProps } from "react-awesome-query-builder";
@@ -21,83 +20,19 @@ import {
import SingleForm, {
getServerSidePropsForSingleFormView as getServerSideProps,
} from "../../components/SingleForm";
import QueryBuilderInitialConfig from "../../components/react-awesome-query-builder/config/config";
import "../../components/react-awesome-query-builder/styles.css";
import { RoutingPages } from "../../lib/RoutingPages";
import { createFallbackRoute } from "../../lib/createFallbackRoute";
import { getQueryBuilderConfig } from "../../lib/getQueryBuilderConfig";
import isRouter from "../../lib/isRouter";
import { GlobalRoute, LocalRoute, SerializableForm, SerializableRoute } from "../../types/types";
import { FieldTypes } from "../form-edit/[...appPages]";
import { GlobalRoute, LocalRoute, QueryBuilderUpdatedConfig, SerializableRoute } from "../../types/types";
export { getServerSideProps };
type RoutingForm = SerializableForm<App_RoutingForms_Form>;
const InitialConfig = QueryBuilderInitialConfig;
const hasRules = (route: Route) => {
if (isRouter(route)) return false;
route.queryValue.children1 && Object.keys(route.queryValue.children1).length;
};
type QueryBuilderUpdatedConfig = typeof QueryBuilderInitialConfig & { fields: Config["fields"] };
export function getQueryBuilderConfig(form: RoutingForm, forReporting = false) {
const fields: Record<
string,
{
label: string;
type: string;
valueSources: ["value"];
fieldSettings: {
listValues?: {
value: string;
title: string;
}[];
};
}
> = {};
form.fields?.forEach((field) => {
if ("routerField" in field) {
field = field.routerField;
}
if (FieldTypes.map((f) => f.value).includes(field.type)) {
const optionValues = field.selectText?.trim().split("\n");
const options = optionValues?.map((value) => {
const title = value;
return {
value,
title,
};
});
const widget = InitialConfig.widgets[field.type];
const widgetType = widget.type;
fields[field.id] = {
label: field.label,
type: widgetType,
valueSources: ["value"],
fieldSettings: {
listValues: options,
},
// preferWidgets: field.type === "textarea" ? ["textarea"] : [],
};
} else {
throw new Error("Unsupported field type:" + field.type);
}
});
const initialConfigCopy = { ...InitialConfig, operators: { ...InitialConfig.operators } };
if (forReporting) {
delete initialConfigCopy.operators.is_empty;
delete initialConfigCopy.operators.is_not_empty;
initialConfigCopy.operators.__calReporting = true;
}
// You need to provide your own config. See below 'Config format'
const config: QueryBuilderUpdatedConfig = {
...initialConfigCopy,
fields: fields,
};
return config;
}
const getEmptyRoute = (): Exclude<SerializableRoute, GlobalRoute> => {
const uuid = QbUtils.uuid();
return {
@@ -122,21 +57,6 @@ type Route =
})
| GlobalRoute;
export const RoutingPages: { label: string; value: NonNullable<LocalRoute["action"]>["type"] }[] = [
{
label: "Custom Page",
value: "customPageMessage",
},
{
label: "External Redirect",
value: "externalRedirectUrl",
},
{
label: "Event Redirect",
value: "eventTypeRedirectUrl",
},
];
const Route = ({
route,
routes,
@@ -92,6 +92,9 @@ test.describe("Routing Forms", () => {
// Expect F1 fields to be available in F2
await page.goto(`/apps/routing-forms/form-edit/${form2Id}`);
//FIXME: Figure out why this delay is required. Without it field count comes out to be 1 only
await new Promise((resolve) => setTimeout(resolve, 1000));
expect(await page.locator('[data-testid="field"]').count()).toBe(2);
await expectCurrentFormToHaveFields(page, { 1: { label: "F1 Field1", typeIndex: 1 } }, types);
// Add 1 more field in F1
@@ -103,6 +106,8 @@ test.describe("Routing Forms", () => {
});
await page.goto(`/apps/routing-forms/form-edit/${form2Id}`);
//FIXME: Figure out why this delay is required. Without it field count comes out to be 1 only
await new Promise((resolve) => setTimeout(resolve, 1000));
expect(await page.locator('[data-testid="field"]').count()).toBe(3);
await expectCurrentFormToHaveFields(page, { 2: { label: "F1 Field2", typeIndex: 1 } }, types);
});
+5
View File
@@ -3,8 +3,13 @@ import z from "zod";
import { RoutingFormSettings } from "@calcom/prisma/zod-utils";
import QueryBuilderInitialConfig from "../components/react-awesome-query-builder/config/config";
import { zodRouterRouteView, zodNonRouterRoute, zodFieldsView, zodRoutesView } from "../zod";
export type RoutingForm = SerializableForm<App_RoutingForms_Form>;
export type QueryBuilderUpdatedConfig = typeof QueryBuilderInitialConfig & { fields: Config["fields"] };
export type Response = Record<
// Field ID
string,