mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
Use BlockNote in open project
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
<%#-- copyright
|
||||
OpenProject is an open source project management software.
|
||||
Copyright (C) the OpenProject GmbH
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 3.
|
||||
|
||||
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
Copyright (C) 2010-2013 the ChiliProject Team
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
++#%>
|
||||
|
||||
<%=
|
||||
render(
|
||||
Primer::BaseComponent.new(
|
||||
tag: :div,
|
||||
border: true, border_radius: 2, mt: 1, mb: 1,
|
||||
data: {
|
||||
controller: "block-note",
|
||||
block_note_target: "blockNoteEditor",
|
||||
block_note_input_name_value: input_name,
|
||||
block_note_input_text_value: value
|
||||
}
|
||||
)
|
||||
)
|
||||
%>
|
||||
@@ -0,0 +1,39 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
class BlockNoteEditor < ApplicationComponent
|
||||
attr_reader :input_name, :value
|
||||
|
||||
def initialize(input_name, value, **)
|
||||
super(**)
|
||||
@input_name = input_name
|
||||
@value = value
|
||||
end
|
||||
end
|
||||
@@ -46,3 +46,6 @@ OpenProject::FeatureDecisions.add :built_in_oauth_applications,
|
||||
|
||||
OpenProject::FeatureDecisions.add :calculated_value_project_attribute,
|
||||
description: "Allows the use of calculated values as a project attribute."
|
||||
|
||||
OpenProject::FeatureDecisions.add :block_note_editor,
|
||||
description: "Enables the block note editor for rich text fields where available."
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
"bundleName": "backlogs"
|
||||
},
|
||||
"src/styles.scss",
|
||||
"node_modules/@blocknote/mantine/dist/style.css",
|
||||
"node_modules/codemirror/lib/codemirror.css",
|
||||
"node_modules/jquery-ui/themes/base/core.css",
|
||||
"node_modules/jquery-ui/themes/base/datepicker.css",
|
||||
|
||||
Generated
+4587
-58
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,8 @@
|
||||
"@types/mime": "^2.0.3",
|
||||
"@types/mousetrap": "^1.6.3",
|
||||
"@types/pako": "^1.0.1",
|
||||
"@types/react": "^19.1.5",
|
||||
"@types/react-dom": "^19.1.5",
|
||||
"@types/resize-observer-browser": "^0.1.4",
|
||||
"@types/urijs": "^1.19.6",
|
||||
"@types/uuid": "^8.3.4",
|
||||
@@ -52,8 +54,6 @@
|
||||
"karma-jasmine": "~3.3.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"karma-spec-reporter": "^0.0.32",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"source-map-explorer": "^2.5.2",
|
||||
"theo": "^8.1.5",
|
||||
"ts-node": "~8.3.0",
|
||||
@@ -77,6 +77,9 @@
|
||||
"@appsignal/javascript": "^1.3.28",
|
||||
"@appsignal/plugin-breadcrumbs-console": "^1.1.29",
|
||||
"@appsignal/plugin-breadcrumbs-network": "^1.1.22",
|
||||
"@blocknote/core": "^0.31.0",
|
||||
"@blocknote/mantine": "^0.31.0",
|
||||
"@blocknote/react": "^0.31.0",
|
||||
"@braintree/sanitize-url": "^7.1.1",
|
||||
"@datorama/akita": "^8.0.1",
|
||||
"@floating-ui/dom": "^1.2.1",
|
||||
@@ -149,8 +152,11 @@
|
||||
"ng2-dragula": "^5.1.0",
|
||||
"ngx-cookie-service": "^14.0.0",
|
||||
"observable-array": "0.0.4",
|
||||
"op-blocknote-extensions": "github:opf/op-blocknote-extensions",
|
||||
"pako": "^2.0.3",
|
||||
"qr-creator": "^1.0.0",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rxjs": "^7.8.0",
|
||||
"screenfull": "^4.2.1",
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* -- copyright
|
||||
* OpenProject is an open source project management software.
|
||||
* Copyright (C) 2023 the OpenProject GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 3.
|
||||
*
|
||||
* OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
* Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
* Copyright (C) 2010-2013 the ChiliProject Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* See COPYRIGHT and LICENSE files for more details.
|
||||
* ++
|
||||
*/
|
||||
|
||||
import { BlockNoteSchema, defaultBlockSpecs, filterSuggestionItems } from "@blocknote/core";
|
||||
import { BlockNoteView } from "@blocknote/mantine";
|
||||
import { getDefaultReactSlashMenuItems, SuggestionMenuController, useCreateBlockNote } from "@blocknote/react";
|
||||
import { dummyBlockSpec, getDefaultOpenProjectSlashMenuItems, openProjectWorkPackageBlockSpec } from "op-blocknote-extensions";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface OpBlockNoteContainerProps {
|
||||
inputName?: string;
|
||||
inputText?: string;
|
||||
}
|
||||
|
||||
const schema = BlockNoteSchema.create({
|
||||
blockSpecs: {
|
||||
...defaultBlockSpecs,
|
||||
openProjectWorkPackage: openProjectWorkPackageBlockSpec,
|
||||
dummy: dummyBlockSpec,
|
||||
},
|
||||
});
|
||||
|
||||
export default function OpBlockNoteContainer({ inputName, inputText }: OpBlockNoteContainerProps) {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [editorContent, setEditorContent] = useState(inputText || "");
|
||||
|
||||
const editor = useCreateBlockNote({ schema });
|
||||
type EditorType = typeof editor;
|
||||
|
||||
const getCustomSlashMenuItems = (editor: EditorType) => {
|
||||
return [
|
||||
...getDefaultReactSlashMenuItems(editor),
|
||||
...getDefaultOpenProjectSlashMenuItems(editor),
|
||||
];
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function loadInitialContent() {
|
||||
const blocks = await editor.tryParseMarkdownToBlocks(inputText || "");
|
||||
editor.replaceBlocks(editor.document, blocks);
|
||||
setEditorContent(await editor.blocksToMarkdownLossy());
|
||||
setIsLoading(false);
|
||||
}
|
||||
loadInitialContent();
|
||||
}, [editor]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<input type="hidden" name={inputName} value={editorContent} />
|
||||
{isLoading ? <div>Loading...</div>
|
||||
:
|
||||
<BlockNoteView
|
||||
editor={editor}
|
||||
onChange={async (editor) => {
|
||||
const content = await editor.blocksToMarkdownLossy();
|
||||
setEditorContent(content);
|
||||
}}
|
||||
>
|
||||
<SuggestionMenuController
|
||||
triggerCharacter="/"
|
||||
getItems={async (query: string) => filterSuggestionItems(getCustomSlashMenuItems(editor), query)}
|
||||
/>
|
||||
</BlockNoteView>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* -- copyright
|
||||
* OpenProject is an open source project management software.
|
||||
* Copyright (C) 2023 the OpenProject GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 3.
|
||||
*
|
||||
* OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
* Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
* Copyright (C) 2010-2013 the ChiliProject Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* See COPYRIGHT and LICENSE files for more details.
|
||||
* ++
|
||||
*/
|
||||
|
||||
import { Controller } from '@hotwired/stimulus';
|
||||
import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import OpBlockNoteContainer from 'react/OpBlockNoteContainer';
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ['blockNoteEditor'];
|
||||
static values = {
|
||||
inputName: String,
|
||||
inputText: String,
|
||||
};
|
||||
|
||||
declare readonly blockNoteEditorTarget:HTMLElement;
|
||||
declare readonly inputNameValue:string;
|
||||
declare readonly inputTextValue:string;
|
||||
|
||||
connect() {
|
||||
const root = createRoot(this.blockNoteEditorTarget);
|
||||
root.render(this.BlockNoteReactContainer());
|
||||
}
|
||||
|
||||
BlockNoteReactContainer() {
|
||||
return React.createElement(OpBlockNoteContainer, {
|
||||
inputName: this.inputNameValue,
|
||||
inputText: this.inputTextValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,10 @@
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"stimulus/**/*.ts",
|
||||
"**/*.d.ts",
|
||||
"**/*.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"**/*.stories.*"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
"node_modules/@types",
|
||||
"src/types"
|
||||
],
|
||||
"types": [
|
||||
"node",
|
||||
"react"
|
||||
],
|
||||
"jsx": "react-jsx",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
|
||||
@@ -38,13 +38,17 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
<div class="form--field -required">
|
||||
<%= f.text_field :title, required: true, container_class: "-wide" %>
|
||||
</div>
|
||||
<div class="form--field -visible-overflow">
|
||||
<%= f.text_area :description,
|
||||
container_class: "-xxwide",
|
||||
label_options: {
|
||||
class: "-top"
|
||||
},
|
||||
with_text_formatting: true,
|
||||
resource: api_v3_document_resource(f.object),
|
||||
preview_context: preview_context(f.object.project) %>
|
||||
</div>
|
||||
<% if OpenProject::FeatureDecisions.block_note_editor_active? %>
|
||||
<%= render BlockNoteEditor.new("#{f.object_name}[description]", f.object.description) %>
|
||||
<% else %>
|
||||
<div class="form--field -visible-overflow">
|
||||
<%= f.text_area :description,
|
||||
container_class: "-xxwide",
|
||||
label_options: {
|
||||
class: "-top"
|
||||
},
|
||||
with_text_formatting: true,
|
||||
resource: api_v3_document_resource(f.object),
|
||||
preview_context: preview_context(f.object.project) %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
Reference in New Issue
Block a user