Skip to content

Commit

Permalink
Merge branch 'main' into barrel-utils
Browse files Browse the repository at this point in the history
  • Loading branch information
fungairino authored Nov 15, 2024
2 parents eb39325 + 55db8d3 commit fb236a3
Show file tree
Hide file tree
Showing 51 changed files with 1,209 additions and 298 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ test("can save a new trigger mod", async ({

test("#9349: can save new mod with multiple components", async ({
page,
extensionId,
newPageEditorPage,
}) => {
await page.goto("/");
Expand Down
3 changes: 2 additions & 1 deletion applications/browser-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@rjsf/core": "^5.22.3",
"@rjsf/utils": "^5.22.3",
"@szhsin/react-menu": "^4.2.2",
"@tiptap/extension-image": "^2.9.1",
"@tiptap/extension-link": "^2.9.1",
"@tiptap/extension-underline": "^2.9.1",
"@tiptap/pm": "^2.9.1",
Expand Down Expand Up @@ -105,7 +106,7 @@
"kbar": "^0.1.0-beta.45",
"lodash-es": "^4.17.21",
"mark.js": "^8.11.1",
"marked": "^14.1.3",
"marked": "^15.0.0",
"memoize-one": "^6.0.0",
"mustache": "^4.2.0",
"nunjucks": "^3.2.4",
Expand Down
2 changes: 1 addition & 1 deletion applications/browser-extension/public/mockServiceWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* tslint:disable */

/**
* Mock Service Worker (1.3.4).
* Mock Service Worker (1.3.5).
* @see https://github.com/mswjs/msw
* - Please do NOT modify this file.
* - Please do NOT serve this file on production.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import React, { Suspense, useMemo } from "react";
import { Stylesheets } from "@/components/Stylesheets";
import EmotionShadowRoot from "@/components/EmotionShadowRoot";
import isolatedComponentList from "./isolatedComponentList";
import { Provider } from "react-redux";
import { configureStore } from "@reduxjs/toolkit";
import { appApi } from "@/data/service/api";

const MODE = process.env.SHADOW_DOM as "open" | "closed";

Expand Down Expand Up @@ -110,6 +113,17 @@ type Props<T> = React.DetailedHTMLProps<
noStyle?: boolean;
};

const store = configureStore({
reducer: {
[appApi.reducerPath]: appApi.reducer,
},
middleware(getDefaultMiddleware) {
/* eslint-disable unicorn/prefer-spread -- It's not Array#concat, can't use spread */
return getDefaultMiddleware().concat(appApi.middleware);
/* eslint-enable unicorn/prefer-spread */
},
});

/**
* Isolate component loaded via React.lazy() in a shadow DOM, including its styles.
*
Expand Down Expand Up @@ -151,8 +165,10 @@ export default function IsolatedComponent<T>({
<EmotionShadowRoot mode={MODE} pb-name={name} {...props}>
<style>{cssText}</style>
<Stylesheets href={stylesheetUrl ?? []}>
{/* Must call the factory on each render to pick up changes to the component props */}
<Suspense fallback={null}>{factory(LazyComponent)}</Suspense>
<Provider store={store}>
{/* Must call the factory on each render to pick up changes to the component props */}
<Suspense fallback={null}>{factory(LazyComponent)}</Suspense>
</Provider>
</Stylesheets>
</EmotionShadowRoot>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
type SelectStringOption,
type SetActiveField,
} from "@/components/formBuilder/formBuilderTypes";
import FieldEditor from "./fieldEditor/FieldEditor";
import {
moveStringInArray,
getNormalizedUiOrder,
Expand All @@ -13,6 +12,7 @@ import FieldTemplate from "@/components/form/FieldTemplate";
import LayoutWidget from "@/components/LayoutWidget";
import { findLast } from "lodash";
import { type FormikErrors } from "formik";
import FieldEditor from "@/components/formBuilder/edit/fieldEditor/FieldEditor";

export const ActiveField: React.FC<{
name: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,11 @@ const RichTextFields: React.FunctionComponent<{ uiOptionsPath: string }> = ({
return (
<SchemaField
name={configName("database")}
isRequired
schema={{
$ref: "https://app.pixiebrix.com/schemas/database#",
title: "Asset Database",
description:
"Asset database to use for image upload. Asset databases are a specific kind of database that" +
" can be created in the Admin Console.",
"Asset database to use for image upload. If not specified, image support will be disabled.",
}}
uiSchema={{
"ui:widget": "database",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ const FormPreview: React.FC<FormPreviewProps> = ({
propertySchema.oneOf = [{ const: "" }];
}
}

if (value[UI_WIDGET] === "richText") {
propertySchema.readOnly = true;
}
}
}),
[rjsfSchema, activeField],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,24 @@ import CustomFormComponent, {
type CustomFormComponentProps,
} from "@/bricks/renderers/CustomFormComponent";
import { type Schema } from "@/types/schemaTypes";
import { Provider } from "react-redux";
import { configureStore } from "@reduxjs/toolkit";
import { appApi } from "@/data/service/api";

describe("RichTextWidget", () => {
const user = userEvent.setup({
// 20ms delay between key presses to allow the editor state to update
// before the next key press
delay: 20,
});

const createTestStore = () =>
configureStore({
reducer: {
appApi: appApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(appApi.middleware),
});

const createSchema = (properties: Record<string, any>): Schema => ({
type: "object",
properties,
Expand All @@ -48,15 +58,19 @@ describe("RichTextWidget", () => {
}: Pick<CustomFormComponentProps, "schema" | "uiSchema" | "formData"> & {
onSubmit?: jest.Mock;
}) => {
const store = createTestStore();

render(
<CustomFormComponent
schema={schema}
formData={formData}
uiSchema={uiSchema}
submitCaption="Submit"
autoSave={false}
onSubmit={onSubmit}
/>,
<Provider store={store}>
<CustomFormComponent
schema={schema}
formData={formData}
uiSchema={uiSchema}
submitCaption="Submit"
autoSave={false}
onSubmit={onSubmit}
/>
</Provider>,
);
return { onSubmit };
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
*/

import React from "react";
import { type ErrorSchema, type WidgetProps } from "@rjsf/utils";
import { type WidgetProps } from "@rjsf/utils";
import RichTextEditor from "@/components/richTextEditor/RichTextEditor";
import { validateUUID } from "@/types/helpers";

const RichTextWidget: React.FunctionComponent<WidgetProps> = ({
id,
Expand All @@ -27,19 +28,9 @@ const RichTextWidget: React.FunctionComponent<WidgetProps> = ({
disabled,
readonly,
options,
value,
}) => {
const { database } = options;

if (!database) {
// TODO: Can't figure out how to satisfy this type without casting, but this is how it's done in the docs
// https://rjsf-team.github.io/react-jsonschema-form/docs/advanced-customization/custom-widgets-fields/#raising-errors-from-within-a-custom-widget-or-field
const databaseConfigurationError = {
__errors: ["Rich text field asset database is required"],
} as ErrorSchema;
onChange(value, databaseConfigurationError);
}

return (
<RichTextEditor
onUpdate={({ editor }) => {
Expand All @@ -53,6 +44,7 @@ const RichTextWidget: React.FunctionComponent<WidgetProps> = ({
onBlur(id, editor.getHTML());
}}
editable={!(disabled || readonly)}
assetDatabaseId={validateUUID(database)}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2024 PixieBrix, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { createContext, useContext } from "react";

type ErrorContextType = {
error: string | null;
setError: (error: string | null) => void;
};

const ErrorContext = createContext<ErrorContextType | null>(null);

export function useShowError() {
const context = useContext(ErrorContext);
if (!context) {
throw new Error("useRichTextError must be used within a RichTextEditor");
}

return context;
}

export default ErrorContext;
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2024 PixieBrix, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import React from "react";
import { Toast, Button } from "react-bootstrap";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faExclamationCircle, faTimes } from "@fortawesome/free-solid-svg-icons";
import styles from "./RichTextEditor.module.scss";

interface ErrorToastProps {
error: string | null;
onClose: () => void;
}

const ErrorToast: React.FC<ErrorToastProps> = ({ error, onClose }) => (
<Toast
show={Boolean(error)}
onClose={onClose}
className={styles.error}
autohide
animation={false}
delay={5000}
>
<span>
<FontAwesomeIcon className="mr-2" icon={faExclamationCircle} /> {error}
<Button variant="outline-danger" onClick={onClose}>
<FontAwesomeIcon icon={faTimes} />
</Button>
</span>
</Toast>
);

export default ErrorToast;
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
transition:
border-color 0.15s ease-in-out,
box-shadow 0.15s ease-in-out;
position: relative;

&:focus-within {
border-color: #80bdff;
Expand All @@ -41,3 +42,34 @@
outline: 0;
}
}

.error {
color: #dc3545;
padding: 4px 8px;
font-size: 0.875rem;
position: absolute;
bottom: 4px;
left: 4px;

span {
display: flex;
align-items: center;
}

:global(.btn) {
margin-left: 8px;
color: #dc3545;
padding: 0;
border: none;
background-color: transparent;

&:focus,
&:active,
&:hover,
&:active:focus {
color: #dc3545;
background-color: transparent;
box-shadow: none !important;
}
}
}
Loading

0 comments on commit fb236a3

Please sign in to comment.