Compare commits

...

5 Commits

Author SHA1 Message Date
Andreas Gebhardt 177b1690ff
Merge 66bb643019 into 6e5aeb112d 2024-04-27 23:01:59 +02:00
Marcel Mraz 6e5aeb112d
feat: record freedraw tool selection to history (#7949) 2024-04-25 17:24:05 +00:00
Marcel Mraz 4d83d1c91e
fix: use Reflect API instead of Object.hasOwn (#7958) 2024-04-25 15:36:26 +02:00
Andreas Gebhardt 66bb643019 deps: update (container) Nginx to 1.24 2024-02-12 19:24:01 +01:00
Andreas Gebhardt 55cf2dd898 fix: docker build of Excalidraw app
Fixes #7403.
2024-02-12 19:19:56 +01:00
8 changed files with 1041 additions and 551 deletions

View File

@ -4,8 +4,15 @@
!.eslintrc.json !.eslintrc.json
!.npmrc !.npmrc
!.prettierrc !.prettierrc
!excalidraw-app/
!package.json !package.json
!public/ !public/
!packages/ !packages/
!tsconfig.json !tsconfig.json
!yarn.lock !yarn.lock
# keep (sub)sub directories at the end to exclude from explicit included
# e.g. ./packages/excalidraw/{dist,node_modules}
**/build
**/dist
**/node_modules

View File

@ -2,16 +2,18 @@ FROM node:18 AS build
WORKDIR /opt/node_app WORKDIR /opt/node_app
COPY package.json yarn.lock ./ COPY . .
RUN yarn --ignore-optional --network-timeout 600000
# do not ignore optional dependencies:
# Error: Cannot find module @rollup/rollup-linux-x64-gnu
RUN yarn --network-timeout 600000
ARG NODE_ENV=production ARG NODE_ENV=production
COPY . .
RUN yarn build:app:docker RUN yarn build:app:docker
FROM nginx:1.21-alpine FROM nginx:1.24-alpine
COPY --from=build /opt/node_app/build /usr/share/nginx/html COPY --from=build /opt/node_app/excalidraw-app/build /usr/share/nginx/html
HEALTHCHECK CMD wget -q -O /dev/null http://localhost || exit 1 HEALTHCHECK CMD wget -q -O /dev/null http://localhost || exit 1

View File

@ -60,9 +60,9 @@
"prettier": "@excalidraw/prettier-config", "prettier": "@excalidraw/prettier-config",
"scripts": { "scripts": {
"build-node": "node ./scripts/build-node.js", "build-node": "node ./scripts/build-node.js",
"build:app:docker": "cross-env VITE_APP_DISABLE_SENTRY=true VITE_APP_DISABLE_TRACKING=true vite build", "build:app:docker": "yarn --cwd ./excalidraw-app build:app:docker",
"build:app": "cross-env VITE_APP_GIT_SHA=$VERCEL_GIT_COMMIT_SHA vite build", "build:app": "yarn --cwd ./excalidraw-app build:app",
"build:version": "node ./scripts/build-version.js", "build:version": "yarn --cwd ./excalidraw-app build:version",
"build": "yarn --cwd ./excalidraw-app build", "build": "yarn --cwd ./excalidraw-app build",
"fix:code": "yarn test:code --fix", "fix:code": "yarn test:code --fix",
"fix:other": "yarn prettier --write", "fix:other": "yarn prettier --write",

View File

@ -4166,6 +4166,11 @@ class App extends React.Component<AppProps, AppState> {
originSnapOffset: null, originSnapOffset: null,
activeEmbeddable: null, activeEmbeddable: null,
} as const; } as const;
if (nextActiveTool.type === "freedraw") {
this.store.shouldCaptureIncrement();
}
if (nextActiveTool.type !== "selection") { if (nextActiveTool.type !== "selection") {
return { return {
...prevState, ...prevState,

View File

@ -22,7 +22,7 @@ export const getObservedAppState = (appState: AppState): ObservedAppState => {
selectedLinearElementId: appState.selectedLinearElement?.elementId || null, selectedLinearElementId: appState.selectedLinearElement?.elementId || null,
}; };
Object.defineProperty(observedAppState, hiddenObservedAppStateProp, { Reflect.defineProperty(observedAppState, hiddenObservedAppStateProp, {
value: true, value: true,
enumerable: false, enumerable: false,
}); });
@ -33,7 +33,7 @@ export const getObservedAppState = (appState: AppState): ObservedAppState => {
const isObservedAppState = ( const isObservedAppState = (
appState: AppState | ObservedAppState, appState: AppState | ObservedAppState,
): appState is ObservedAppState => ): appState is ObservedAppState =>
Object.hasOwn(appState, hiddenObservedAppStateProp); !!Reflect.get(appState, hiddenObservedAppStateProp);
export type StoreActionType = "capture" | "update" | "none"; export type StoreActionType = "capture" | "update" | "none";

File diff suppressed because it is too large Load Diff

View File

@ -6570,12 +6570,27 @@ History {
"delta": Delta { "delta": Delta {
"deleted": { "deleted": {
"selectedElementIds": {}, "selectedElementIds": {},
"selectedLinearElementId": null,
}, },
"inserted": { "inserted": {
"selectedElementIds": { "selectedElementIds": {
"id6": true, "id6": true,
}, },
},
},
},
"elementsChange": ElementsChange {
"added": Map {},
"removed": Map {},
"updated": Map {},
},
},
HistoryEntry {
"appStateChange": AppStateChange {
"delta": Delta {
"deleted": {
"selectedLinearElementId": null,
},
"inserted": {
"selectedLinearElementId": "id6", "selectedLinearElementId": "id6",
}, },
}, },

View File

@ -15,7 +15,11 @@ import { createUndoAction, createRedoAction } from "../actions/actionHistory";
import { EXPORT_DATA_TYPES, MIME_TYPES } from "../constants"; import { EXPORT_DATA_TYPES, MIME_TYPES } from "../constants";
import { AppState, ExcalidrawImperativeAPI } from "../types"; import { AppState, ExcalidrawImperativeAPI } from "../types";
import { arrayToMap, resolvablePromise } from "../utils"; import { arrayToMap, resolvablePromise } from "../utils";
import { COLOR_PALETTE } from "../colors"; import {
COLOR_PALETTE,
DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX,
DEFAULT_ELEMENT_STROKE_COLOR_INDEX,
} from "../colors";
import { KEYS } from "../keys"; import { KEYS } from "../keys";
import { newElementWith } from "../element/mutateElement"; import { newElementWith } from "../element/mutateElement";
import { import {
@ -67,10 +71,11 @@ const checkpoint = (name: string) => {
const renderStaticScene = vi.spyOn(StaticScene, "renderStaticScene"); const renderStaticScene = vi.spyOn(StaticScene, "renderStaticScene");
const transparent = COLOR_PALETTE.transparent; const transparent = COLOR_PALETTE.transparent;
const red = COLOR_PALETTE.red[1]; const black = COLOR_PALETTE.black;
const blue = COLOR_PALETTE.blue[1]; const red = COLOR_PALETTE.red[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX];
const yellow = COLOR_PALETTE.yellow[1]; const blue = COLOR_PALETTE.blue[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX];
const violet = COLOR_PALETTE.violet[1]; const yellow = COLOR_PALETTE.yellow[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX];
const violet = COLOR_PALETTE.violet[DEFAULT_ELEMENT_BACKGROUND_COLOR_INDEX];
describe("history", () => { describe("history", () => {
beforeEach(() => { beforeEach(() => {
@ -973,6 +978,69 @@ describe("history", () => {
]); ]);
}); });
it("should create entry when selecting freedraw", async () => {
await render(<Excalidraw handleKeyboardGlobally={true} />);
UI.clickTool("rectangle");
mouse.down(-10, -10);
mouse.up(10, 10);
UI.clickTool("freedraw");
mouse.down(40, -20);
mouse.up(50, 10);
const rectangle = h.elements[0];
const freedraw1 = h.elements[1];
expect(API.getUndoStack().length).toBe(3);
expect(API.getRedoStack().length).toBe(0);
expect(API.getSelectedElements().length).toBe(0);
expect(h.elements).toEqual([
expect.objectContaining({ id: rectangle.id }),
expect.objectContaining({ id: freedraw1.id, strokeColor: black }),
]);
Keyboard.undo();
expect(API.getUndoStack().length).toBe(2);
expect(API.getRedoStack().length).toBe(1);
expect(API.getSelectedElements().length).toBe(0);
expect(h.elements).toEqual([
expect.objectContaining({ id: rectangle.id }),
expect.objectContaining({
id: freedraw1.id,
strokeColor: black,
isDeleted: true,
}),
]);
togglePopover("Stroke");
UI.clickOnTestId("color-red");
mouse.down(40, -20);
mouse.up(50, 10);
const freedraw2 = h.elements[2];
expect(API.getUndoStack().length).toBe(3);
expect(API.getRedoStack().length).toBe(0);
expect(h.elements).toEqual([
expect.objectContaining({ id: rectangle.id }),
expect.objectContaining({
id: freedraw1.id,
strokeColor: black,
isDeleted: true,
}),
expect.objectContaining({
id: freedraw2.id,
strokeColor: COLOR_PALETTE.red[DEFAULT_ELEMENT_STROKE_COLOR_INDEX],
}),
]);
// ensure we don't end up with duplicated entries
UI.clickTool("freedraw");
expect(API.getUndoStack().length).toBe(3);
expect(API.getRedoStack().length).toBe(0);
});
it("should support duplication of groups, appstate group selection and editing group", async () => { it("should support duplication of groups, appstate group selection and editing group", async () => {
await render(<Excalidraw handleKeyboardGlobally={true} />); await render(<Excalidraw handleKeyboardGlobally={true} />);
const rect1 = API.createElement({ const rect1 = API.createElement({