mirror of
https://github.com/outline/outline.git
synced 2026-02-05 10:09:55 -06:00
fix: Restore uuid package on frontend (#10491)
* fix: Restore uuid package on frontend * Remove legacy moduleNameMapper * Add lint rule * lint - getRandomValues can be used without SSL * Update Comment.ts
This commit is contained in:
@@ -20,8 +20,7 @@
|
||||
"moduleNameMapper": {
|
||||
"^~/(.*)$": "<rootDir>/app/$1",
|
||||
"^@shared/(.*)$": "<rootDir>/shared/$1",
|
||||
"^.*[.](gif|ttf|eot|svg)$": "<rootDir>/__test__/fileMock.js",
|
||||
"^uuid$": "<rootDir>/node_modules/uuid/dist/index.js"
|
||||
"^.*[.](gif|ttf|eot|svg)$": "<rootDir>/__test__/fileMock.js"
|
||||
},
|
||||
"modulePaths": ["<rootDir>/app"],
|
||||
"setupFiles": ["<rootDir>/__mocks__/window.js"],
|
||||
@@ -48,8 +47,7 @@
|
||||
"moduleNameMapper": {
|
||||
"^~/(.*)$": "<rootDir>/app/$1",
|
||||
"^@shared/(.*)$": "<rootDir>/shared/$1",
|
||||
"^.*[.](gif|ttf|eot|svg)$": "<rootDir>/__test__/fileMock.js",
|
||||
"^uuid$": "<rootDir>/node_modules/uuid/dist/index.js"
|
||||
"^.*[.](gif|ttf|eot|svg)$": "<rootDir>/__test__/fileMock.js"
|
||||
},
|
||||
"setupFiles": ["<rootDir>/__mocks__/window.js"],
|
||||
"testEnvironment": "jsdom",
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
{
|
||||
"files": ["**/*.{jsx,tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-globals": [
|
||||
"error",
|
||||
{
|
||||
"name": "crypto",
|
||||
"message": "Do not use, does not work in environments without SSL."
|
||||
}
|
||||
],
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { LocationDescriptor } from "history";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import flattenDeep from "lodash/flattenDeep";
|
||||
import { toast } from "sonner";
|
||||
import { Optional } from "utility-types";
|
||||
@@ -45,7 +46,7 @@ export function createAction(definition: Optional<Action, "id">): Action {
|
||||
return definition.perform?.(context);
|
||||
}
|
||||
: undefined,
|
||||
id: definition.id ?? crypto.randomUUID(),
|
||||
id: definition.id ?? uuidv4(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -201,7 +202,7 @@ export function createActionV2(
|
||||
return definition.perform(context);
|
||||
}
|
||||
: () => {},
|
||||
id: definition.id ?? crypto.randomUUID(),
|
||||
id: definition.id ?? uuidv4(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -212,7 +213,7 @@ export function createInternalLinkActionV2(
|
||||
...definition,
|
||||
type: "action",
|
||||
variant: "internal_link",
|
||||
id: definition.id ?? crypto.randomUUID(),
|
||||
id: definition.id ?? uuidv4(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -223,7 +224,7 @@ export function createExternalLinkActionV2(
|
||||
...definition,
|
||||
type: "action",
|
||||
variant: "external_link",
|
||||
id: definition.id ?? crypto.randomUUID(),
|
||||
id: definition.id ?? uuidv4(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -234,7 +235,7 @@ export function createActionV2WithChildren(
|
||||
...definition,
|
||||
type: "action",
|
||||
variant: "action_with_children",
|
||||
id: definition.id ?? crypto.randomUUID(),
|
||||
id: definition.id ?? uuidv4(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -251,7 +252,7 @@ export function createRootMenuAction(
|
||||
actions: (ActionV2Variant | ActionV2Group | TActionV2Separator)[]
|
||||
): ActionV2WithChildren {
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
type: "action",
|
||||
variant: "action_with_children",
|
||||
name: "root_action",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { isEmail } from "class-validator";
|
||||
import { observer } from "mobx-react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { DocumentIcon, PlusIcon, CollectionIcon } from "outline-icons";
|
||||
import { useState, useCallback, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -99,7 +100,7 @@ function MentionMenu({ search, isActive, ...rest }: Props) {
|
||||
section: UserSection,
|
||||
appendSpace: true,
|
||||
attrs: {
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
type: MentionType.User,
|
||||
modelId: user.id,
|
||||
actorId,
|
||||
@@ -125,7 +126,7 @@ function MentionMenu({ search, isActive, ...rest }: Props) {
|
||||
section: GroupSection,
|
||||
appendSpace: true,
|
||||
attrs: {
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
type: MentionType.Group,
|
||||
modelId: group.id,
|
||||
actorId,
|
||||
@@ -157,7 +158,7 @@ function MentionMenu({ search, isActive, ...rest }: Props) {
|
||||
section: DocumentsSection,
|
||||
appendSpace: true,
|
||||
attrs: {
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
type: MentionType.Document,
|
||||
modelId: doc.id,
|
||||
actorId,
|
||||
@@ -185,7 +186,7 @@ function MentionMenu({ search, isActive, ...rest }: Props) {
|
||||
section: CollectionsSection,
|
||||
appendSpace: true,
|
||||
attrs: {
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
type: MentionType.Collection,
|
||||
modelId: collection.id,
|
||||
actorId,
|
||||
@@ -205,9 +206,9 @@ function MentionMenu({ search, isActive, ...rest }: Props) {
|
||||
priority: -1,
|
||||
appendSpace: true,
|
||||
attrs: {
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
type: MentionType.Document,
|
||||
modelId: crypto.randomUUID(),
|
||||
modelId: uuidv4(),
|
||||
actorId,
|
||||
label: search,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { observer } from "mobx-react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { EmailIcon, LinkIcon } from "outline-icons";
|
||||
import React, { useCallback } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -101,11 +102,11 @@ function useItems({
|
||||
icon: <EmailIcon />,
|
||||
visible: !!mentionType,
|
||||
attrs: {
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
type: mentionType,
|
||||
label: pastedText,
|
||||
href: pastedText,
|
||||
modelId: crypto.randomUUID(),
|
||||
modelId: uuidv4(),
|
||||
actorId: user?.id,
|
||||
},
|
||||
appendSpace: true,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { action, observable } from "mobx";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { toggleMark } from "prosemirror-commands";
|
||||
import { Node, Slice } from "prosemirror-model";
|
||||
import {
|
||||
@@ -143,7 +144,7 @@ export default class PasteHandler extends Extension {
|
||||
type: MentionType.Document,
|
||||
modelId: document.id,
|
||||
label: document.titleWithDefault,
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
})
|
||||
)
|
||||
);
|
||||
@@ -188,7 +189,7 @@ export default class PasteHandler extends Extension {
|
||||
type: MentionType.Collection,
|
||||
modelId: collection.id,
|
||||
label: collection.name,
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as VisuallyHidden from "@radix-ui/react-visually-hidden";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { m } from "framer-motion";
|
||||
import { action } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
@@ -160,7 +161,7 @@ function CommentForm({
|
||||
comments
|
||||
);
|
||||
|
||||
comment.id = crypto.randomUUID();
|
||||
comment.id = uuidv4();
|
||||
comments.add(comment);
|
||||
|
||||
comment
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { observer } from "mobx-react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import queryString from "query-string";
|
||||
import * as React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -104,7 +105,7 @@ function Search() {
|
||||
// without a flash of loading.
|
||||
if (query) {
|
||||
searches.add({
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
query,
|
||||
createdAt: new Date().toISOString(),
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { observable, action } from "mobx";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import * as React from "react";
|
||||
|
||||
type DialogDefinition = {
|
||||
@@ -65,7 +66,7 @@ export default class DialogsStore {
|
||||
this.modalStack.clear();
|
||||
}
|
||||
|
||||
this.modalStack.set(id ?? replaceId ?? crypto.randomUUID(), {
|
||||
this.modalStack.set(id ?? replaceId ?? uuidv4(), {
|
||||
title,
|
||||
content,
|
||||
style,
|
||||
|
||||
@@ -262,6 +262,7 @@
|
||||
"ukkonen": "^2.2.0",
|
||||
"umzug": "^3.8.2",
|
||||
"utility-types": "^3.11.0",
|
||||
"uuid": "^11.1.0",
|
||||
"validator": "13.15.20",
|
||||
"vaul": "^1.1.2",
|
||||
"vite": "npm:rolldown-vite@latest",
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
{
|
||||
"files": ["**/*.{js,jsx,ts,tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-globals": [
|
||||
"error",
|
||||
{
|
||||
"name": "crypto",
|
||||
"message": "Do not use, does not work in environments without SSL."
|
||||
}
|
||||
],
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Attrs } from "prosemirror-model";
|
||||
import { Command, NodeSelection, TextSelection } from "prosemirror-state";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { isMarkActive } from "../queries/isMarkActive";
|
||||
import { chainTransactions } from "../lib/chainTransactions";
|
||||
import { addMark } from "./addMark";
|
||||
@@ -20,7 +21,7 @@ const addCommentNodeSelection =
|
||||
const newMark = {
|
||||
type: "comment",
|
||||
attrs: {
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
userId: attrs.userId,
|
||||
draft: true,
|
||||
},
|
||||
@@ -54,7 +55,7 @@ const addCommentTextSelection =
|
||||
|
||||
chainTransactions(
|
||||
addMark(state.schema.marks.comment, {
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
userId: attrs.userId,
|
||||
draft: true,
|
||||
}),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { EditorView } from "prosemirror-view";
|
||||
import { toast } from "sonner";
|
||||
import type { Dictionary } from "~/hooks/useDictionary";
|
||||
@@ -71,7 +72,7 @@ const insertFiles = async function (
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
id: `upload-${crypto.randomUUID()}`,
|
||||
id: `upload-${uuidv4()}`,
|
||||
dimensions: await getDimensions?.(file),
|
||||
isImage,
|
||||
isVideo,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import debounce from "lodash/debounce";
|
||||
import last from "lodash/last";
|
||||
import sortBy from "lodash/sortBy";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import type MermaidUnsafe from "mermaid";
|
||||
import { Node } from "prosemirror-model";
|
||||
import {
|
||||
@@ -53,7 +54,7 @@ class MermaidRenderer {
|
||||
readonly editor: Editor;
|
||||
|
||||
constructor(editor: Editor) {
|
||||
this.diagramId = crypto.randomUUID();
|
||||
this.diagramId = uuidv4();
|
||||
this.elementId = `mermaid-diagram-wrapper-${this.diagramId}`;
|
||||
this.element =
|
||||
document.getElementById(this.elementId) || document.createElement("div");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Node, Schema } from "prosemirror-model";
|
||||
import { Primitive } from "utility-types";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { isList } from "../queries/isList";
|
||||
|
||||
export function transformListToMentions(
|
||||
@@ -33,11 +34,11 @@ function transformListItemToMentions(
|
||||
node.type.create(
|
||||
node.attrs,
|
||||
schema.nodes.mention.create({
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
type: mentionType,
|
||||
label: link,
|
||||
href: link,
|
||||
modelId: crypto.randomUUID(),
|
||||
modelId: uuidv4(),
|
||||
actorId: attrs.actorId,
|
||||
})
|
||||
)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { toggleMark } from "prosemirror-commands";
|
||||
import { MarkSpec, MarkType, Mark as PMMark } from "prosemirror-model";
|
||||
import { Command, Plugin } from "prosemirror-state";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { collapseSelection } from "../commands/collapseSelection";
|
||||
import { addComment } from "../commands/comment";
|
||||
import { chainTransactions } from "../lib/chainTransactions";
|
||||
import { isMarkActive } from "../queries/isMarkActive";
|
||||
import { EditorStyleHelper } from "../styles/EditorStyleHelper";
|
||||
import Mark from "./Mark";
|
||||
import { addComment } from "../commands/comment";
|
||||
|
||||
export default class Comment extends Mark {
|
||||
get name() {
|
||||
@@ -81,7 +82,7 @@ export default class Comment extends Mark {
|
||||
|
||||
chainTransactions(
|
||||
toggleMark(type, {
|
||||
id: crypto.randomUUID(),
|
||||
id: uuidv4(),
|
||||
userId: this.options.userId,
|
||||
draft: true,
|
||||
}),
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
sinkListItem,
|
||||
liftListItem,
|
||||
} from "prosemirror-schema-list";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import toggleCheckboxItem from "../commands/toggleCheckboxItem";
|
||||
import { MarkdownSerializerState } from "../lib/markdown/serializer";
|
||||
import checkboxRule from "../rules/checkboxes";
|
||||
@@ -34,7 +35,7 @@ export default class CheckboxItem extends Node {
|
||||
},
|
||||
],
|
||||
toDOM: (node) => {
|
||||
const id = `checkbox-${crypto.randomUUID()}`;
|
||||
const id = `checkbox-${uuidv4()}`;
|
||||
const checked = node.attrs.checked.toString();
|
||||
let input;
|
||||
if (typeof document !== "undefined") {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
TextSelection,
|
||||
} from "prosemirror-state";
|
||||
import { Primitive } from "utility-types";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import env from "../../env";
|
||||
import { MentionType, UnfurlResourceType, UnfurlResponse } from "../../types";
|
||||
import {
|
||||
@@ -178,7 +179,7 @@ export default class Mention extends Node {
|
||||
node.type.name === this.name &&
|
||||
(!nodeId || existingIds.has(nodeId))
|
||||
) {
|
||||
nodeId = crypto.randomUUID();
|
||||
nodeId = uuidv4();
|
||||
modified = true;
|
||||
tr.setNodeAttribute(pos, "id", nodeId);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ export const randomString = (options: number | RandomStringOptions) => {
|
||||
: lowercase + uppercase + numeric;
|
||||
|
||||
const array = new Uint8Array(length);
|
||||
// oxlint-disable-next-line no-restricted-globals
|
||||
crypto.getRandomValues(array);
|
||||
return Array.from(array, (x) => chars[x % chars.length]).join("");
|
||||
};
|
||||
|
||||
32
yarn.lock
32
yarn.lock
@@ -753,20 +753,7 @@
|
||||
lru-cache "^5.1.1"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.27.1", "@babel/helper-create-class-features-plugin@^7.28.3":
|
||||
version "7.28.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz#3e747434ea007910c320c4d39a6b46f20f371d46"
|
||||
integrity sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure" "^7.27.3"
|
||||
"@babel/helper-member-expression-to-functions" "^7.27.1"
|
||||
"@babel/helper-optimise-call-expression" "^7.27.1"
|
||||
"@babel/helper-replace-supers" "^7.27.1"
|
||||
"@babel/helper-skip-transparent-expression-wrappers" "^7.27.1"
|
||||
"@babel/traverse" "^7.28.3"
|
||||
semver "^6.3.1"
|
||||
|
||||
"@babel/helper-create-class-features-plugin@^7.28.5":
|
||||
"@babel/helper-create-class-features-plugin@^7.27.1", "@babel/helper-create-class-features-plugin@^7.28.3", "@babel/helper-create-class-features-plugin@^7.28.5":
|
||||
version "7.28.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz#472d0c28028850968979ad89f173594a6995da46"
|
||||
integrity sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==
|
||||
@@ -818,15 +805,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674"
|
||||
integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz#ea1211276be93e798ce19037da6f06fbb994fa44"
|
||||
integrity sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==
|
||||
dependencies:
|
||||
"@babel/traverse" "^7.27.1"
|
||||
"@babel/types" "^7.27.1"
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.28.5":
|
||||
"@babel/helper-member-expression-to-functions@^7.27.1", "@babel/helper-member-expression-to-functions@^7.28.5":
|
||||
version "7.28.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz#f3e07a10be37ed7a63461c63e6929575945a6150"
|
||||
integrity sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==
|
||||
@@ -894,12 +873,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
|
||||
integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.27.1":
|
||||
version "7.27.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8"
|
||||
integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.28.5":
|
||||
"@babel/helper-validator-identifier@^7.27.1", "@babel/helper-validator-identifier@^7.28.5":
|
||||
version "7.28.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4"
|
||||
integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==
|
||||
|
||||
Reference in New Issue
Block a user