diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 88fe00b4..92de0540 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -21,6 +21,8 @@ const buildEditorContextMenu = require('browser/lib/contextMenuBuilder') import { createTurndownService } from '../lib/turndown' import { languageMaps } from '../lib/CMLanguageList' import snippetManager from '../lib/SnippetManager' +import { findStorage } from 'browser/lib/findStorage' +import { sendWakatimeHeartBeat } from 'browser/lib/wakatime-plugin' import { generateInEditor, tocExistsInEditor @@ -113,6 +115,16 @@ export default class CodeEditor extends React.Component { this.editorActivityHandler = () => this.handleEditorActivity() this.turndownService = createTurndownService() + + // wakatime + const { storageKey, noteKey } = this.props + const storage = findStorage(storageKey) + if (storage) + sendWakatimeHeartBeat(storage.path, noteKey, storage.name, { + isWrite: false, + hasFileChanges: false, + isFileChange: true + }) } handleSearch(msg) { @@ -801,9 +813,23 @@ export default class CodeEditor extends React.Component { this.updateHighlight(editor, changeObject) this.value = editor.getValue() + + const { storageKey, noteKey } = this.props + const storage = findStorage(storageKey) if (this.props.onChange) { this.props.onChange(editor) } + + const isWrite = !!this.props.onChange + const hasFileChanges = isWrite + + if (storage) { + sendWakatimeHeartBeat(storage.path, noteKey, storage.name, { + isWrite, + hasFileChanges, + isFileChange: false + }) + } } linePossibleContainsHeadline(currentLine) { @@ -931,6 +957,16 @@ export default class CodeEditor extends React.Component { this.restartHighlighting() this.editor.on('change', this.changeHandler) this.editor.refresh() + + // wakatime + const { storageKey, noteKey } = this.props + const storage = findStorage(storageKey) + if (storage) + sendWakatimeHeartBeat(storage.path, noteKey, storage.name, { + isWrite: false, + hasFileChanges: false, + isFileChange: true + }) } setValue(value) { diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index 9ddea318..96b7e065 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -1192,7 +1192,10 @@ class MarkdownPreview extends React.Component { e.preventDefault() e.stopPropagation() - const rawHref = e.target.getAttribute('href') + const el = e.target.closest('a[href]') + if (!el) return + + const rawHref = el.getAttribute('href') const { dispatch } = this.props if (!rawHref) return // not checked href because parser will create file://... string for [empty link]() diff --git a/browser/components/render/MermaidRender.js b/browser/components/render/MermaidRender.js index d397d03b..4f0e774a 100644 --- a/browser/components/render/MermaidRender.js +++ b/browser/components/render/MermaidRender.js @@ -1,4 +1,4 @@ -import mermaidAPI from 'mermaid' +import mermaidAPI from 'mermaid/dist/mermaid.min.js' import uiThemes from 'browser/lib/ui-themes' // fixes bad styling in the mermaid dark theme @@ -61,7 +61,6 @@ function render(element, content, theme, enableHTMLLabel) { el.setAttribute('ratio', ratio) el.setAttribute('height', el.parentNode.clientWidth / ratio) - console.log(el) } }) } catch (e) { diff --git a/browser/lib/wakatime-plugin.js b/browser/lib/wakatime-plugin.js new file mode 100644 index 00000000..9b1233df --- /dev/null +++ b/browser/lib/wakatime-plugin.js @@ -0,0 +1,49 @@ +import config from 'browser/main/lib/ConfigManager' +const exec = require('child_process').exec +const path = require('path') +let lastHeartbeat = 0 + +function sendWakatimeHeartBeat( + storagePath, + noteKey, + storageName, + { isWrite, hasFileChanges, isFileChange } +) { + if ( + config.get().wakatime.isActive && + !!config.get().wakatime.key && + (new Date().getTime() - lastHeartbeat > 120000 || isFileChange) + ) { + const notePath = path.join(storagePath, 'notes', noteKey + '.cson') + + if (!isWrite && !hasFileChanges && !isFileChange) { + return + } + + lastHeartbeat = new Date() + const wakatimeKey = config.get().wakatime.key + if (wakatimeKey) { + exec( + `wakatime --file ${notePath} --project '${storageName}' --key ${wakatimeKey} --plugin Boostnote-wakatime`, + (error, stdOut, stdErr) => { + if (error) { + console.log(error) + lastHeartbeat = 0 + } else { + console.log( + 'wakatime', + 'isWrite', + isWrite, + 'hasChanges', + hasFileChanges, + 'isFileChange', + isFileChange + ) + } + } + ) + } + } +} + +export { sendWakatimeHeartBeat } diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index 612308ba..ca7a8b3e 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -871,6 +871,8 @@ class SnippetNoteDetail extends React.Component { hotkey={config.hotkey} autoDetect={autoDetect} dateFormatISO8601={config.editor.dateFormatISO8601} + storageKey={storageKey} + noteKey={note.key} /> )} diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js index 84994028..4b6342d2 100644 --- a/browser/main/lib/ConfigManager.js +++ b/browser/main/lib/ConfigManager.js @@ -139,7 +139,10 @@ export const DEFAULT_CONFIG = { username: '', password: '' }, - coloredTags: {} + coloredTags: {}, + wakatime: { + key: null + } } function validate(config) { @@ -255,6 +258,12 @@ function assignConfigValues(originalConfig, rcConfig) { originalConfig.hotkey, rcConfig.hotkey ) + config.wakatime = Object.assign( + {}, + DEFAULT_CONFIG.wakatime, + originalConfig.wakatime, + rcConfig.wakatime + ) config.blog = Object.assign( {}, DEFAULT_CONFIG.blog, diff --git a/browser/main/lib/ThemeManager.js b/browser/main/lib/ThemeManager.js index a1b090e9..599a61f2 100644 --- a/browser/main/lib/ThemeManager.js +++ b/browser/main/lib/ThemeManager.js @@ -1,4 +1,5 @@ import ConfigManager from 'browser/main/lib/ConfigManager' +import uiThemes from 'browser/lib/ui-themes' const saveChanges = newConfig => { ConfigManager.set(newConfig) @@ -40,14 +41,7 @@ const chooseTheme = config => { } const applyTheme = theme => { - const supportedThemes = [ - 'dark', - 'white', - 'solarized-dark', - 'monokai', - 'dracula' - ] - if (supportedThemes.indexOf(theme) !== -1) { + if (uiThemes.some(item => item.name === theme)) { document.body.setAttribute('data-theme', theme) if (document.body.querySelector('.MarkdownPreview')) { document.body diff --git a/browser/main/modals/PreferencesModal/PluginsTab.js b/browser/main/modals/PreferencesModal/PluginsTab.js new file mode 100644 index 00000000..ceaa383a --- /dev/null +++ b/browser/main/modals/PreferencesModal/PluginsTab.js @@ -0,0 +1,207 @@ +import PropTypes from 'prop-types' +import React from 'react' +import CSSModules from 'browser/lib/CSSModules' +import styles from './ConfigTab.styl' +import ConfigManager from 'browser/main/lib/ConfigManager' +import { store } from 'browser/main/store' +import _ from 'lodash' +import i18n from 'browser/lib/i18n' +import { sync as commandExists } from 'command-exists' +const electron = require('electron') +const ipc = electron.ipcRenderer +const { remote } = electron +const { dialog } = remote +class PluginsTab extends React.Component { + constructor(props) { + super(props) + + this.state = { + config: props.config + } + } + + componentDidMount() { + this.handleSettingDone = () => { + this.setState({ + pluginsAlert: { + type: 'success', + message: i18n.__('Successfully applied!') + } + }) + } + this.handleSettingError = err => { + this.setState({ + pluginsAlert: { + type: 'error', + message: + err.message != null ? err.message : i18n.__('An error occurred!') + } + }) + } + this.oldWakatimeConfig = this.state.config.wakatime + ipc.addListener('APP_SETTING_DONE', this.handleSettingDone) + ipc.addListener('APP_SETTING_ERROR', this.handleSettingError) + } + + componentWillUnmount() { + ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone) + ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError) + } + + checkWakatimePluginRequirement() { + const { wakatime } = this.state.config + if (wakatime.isActive && !commandExists('wakatime')) { + this.setState({ + wakatimePluginAlert: { + type: i18n.__('Warning'), + message: i18n.__('Missing wakatime cli') + } + }) + + const alertConfig = { + type: 'warning', + message: i18n.__('Missing Wakatime CLI'), + detail: i18n.__( + `Please install Wakatime CLI to use Wakatime tracker feature.` + ), + buttons: [i18n.__('OK')] + } + dialog.showMessageBox(remote.getCurrentWindow(), alertConfig) + } else { + this.setState({ + wakatimePluginAlert: null + }) + } + } + + handleSaveButtonClick(e) { + const newConfig = { + wakatime: { + isActive: this.state.config.wakatime.isActive, + key: this.state.config.wakatime.key + } + } + + ConfigManager.set(newConfig) + + store.dispatch({ + type: 'SET_CONFIG', + config: newConfig + }) + this.clearMessage() + this.props.haveToSave() + this.checkWakatimePluginRequirement() + } + + handleIsWakatimePluginActiveChange(e) { + const { config } = this.state + config.wakatime.isActive = !config.wakatime.isActive + this.setState({ + config + }) + if (_.isEqual(this.oldWakatimeConfig.isActive, config.wakatime.isActive)) { + this.props.haveToSave() + } else { + this.props.haveToSave({ + tab: 'Plugins', + type: 'warning', + message: i18n.__('Unsaved Changes!') + }) + } + } + + handleWakatimeKeyChange(e) { + const { config } = this.state + config.wakatime = { + isActive: true, + key: this.refs.wakatimeKey.value + } + this.setState({ + config + }) + if (_.isEqual(this.oldWakatimeConfig.key, config.wakatime.key)) { + this.props.haveToSave() + } else { + this.props.haveToSave({ + tab: 'Plugins', + type: 'warning', + message: i18n.__('Unsaved Changes!') + }) + } + } + + clearMessage() { + _.debounce(() => { + this.setState({ + pluginsAlert: null + }) + }, 2000)() + } + + render() { + const pluginsAlert = this.state.pluginsAlert + const pluginsAlertElement = + pluginsAlert != null ? ( +

{pluginsAlert.message}

+ ) : null + + const wakatimeAlert = this.state.wakatimePluginAlert + const wakatimePluginAlertElement = + wakatimeAlert != null ? ( +

{wakatimeAlert.message}

+ ) : null + + const { config } = this.state + + return ( +
+
+
{i18n.__('Plugins')}
+
{i18n.__('Wakatime')}
+
+ +
+
+
{i18n.__('Wakatime key')}
+
+ this.handleWakatimeKeyChange(e)} + disabled={!config.wakatime.isActive} + ref='wakatimeKey' + value={config.wakatime.key} + type='text' + /> + {wakatimePluginAlertElement} +
+
+
+ + {pluginsAlertElement} +
+
+
+ ) + } +} + +PluginsTab.propTypes = { + dispatch: PropTypes.func, + haveToSave: PropTypes.func +} + +export default CSSModules(PluginsTab, styles) diff --git a/browser/main/modals/PreferencesModal/index.js b/browser/main/modals/PreferencesModal/index.js index 2c14e6c7..36abd734 100644 --- a/browser/main/modals/PreferencesModal/index.js +++ b/browser/main/modals/PreferencesModal/index.js @@ -7,6 +7,7 @@ import InfoTab from './InfoTab' import Crowdfunding from './Crowdfunding' import StoragesTab from './StoragesTab' import SnippetTab from './SnippetTab' +import PluginsTab from './PluginsTab' import Blog from './Blog' import ModalEscButton from 'browser/components/ModalEscButton' import CSSModules from 'browser/lib/CSSModules' @@ -82,6 +83,14 @@ class Preferences extends React.Component { ) case 'SNIPPET': return + case 'PLUGINS': + return ( + this.setState({ PluginsAlert: alert })} + /> + ) case 'STORAGES': default: return ( @@ -122,7 +131,8 @@ class Preferences extends React.Component { { target: 'INFO', label: i18n.__('About') }, { target: 'CROWDFUNDING', label: i18n.__('Crowdfunding') }, { target: 'BLOG', label: i18n.__('Blog'), Blog: this.state.BlogAlert }, - { target: 'SNIPPET', label: i18n.__('Snippets') } + { target: 'SNIPPET', label: i18n.__('Snippets') }, + { target: 'PLUGINS', label: i18n.__('Plugins') } ] const navButtons = tabs.map(tab => { diff --git a/package.json b/package.json index 0682c1bb..ae848053 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "chart.js": "^2.7.2", "codemirror": "^5.40.2", "codemirror-mode-elixir": "^1.1.1", + "command-exists": "^1.2.9", "connected-react-router": "^6.4.0", "electron-config": "^1.0.0", "electron-gh-releases": "^2.0.4", @@ -79,7 +80,7 @@ "js-yaml": "^3.13.1", "jsonlint-mod": "^1.7.4", "katex": "^0.10.1", - "lodash": "^4.17.13", + "lodash": "^4.17.19", "lodash-move": "^1.1.1", "markdown-it": "^6.0.1", "markdown-it-abbr": "^1.0.4", @@ -95,7 +96,7 @@ "markdown-it-sup": "^1.0.0", "markdown-toc": "^1.2.0", "mdurl": "^1.0.1", - "mermaid": "^8.4.2", + "mermaid": "^8.5.2", "moment": "^2.10.3", "mousetrap": "^1.6.2", "mousetrap-global-bind": "^1.1.0", diff --git a/prettier.config b/prettier.config index 66e7e941..515c6cd5 100644 --- a/prettier.config +++ b/prettier.config @@ -1,6 +1,5 @@ { - "trailingComma": "es5", - "tabWidth": 2, + "singleQuote": true, "semi": false, - "singleQuote": true + "jsxSingleQuote": true } \ No newline at end of file diff --git a/readme.md b/readme.md index 63c78f19..dffd9676 100644 --- a/readme.md +++ b/readme.md @@ -1,10 +1,10 @@ > [We've launched desktop and mobile app of the new Boost Note now.](https://github.com/BoostIO/BoostNote.next) -> ### [Boost Note for Teams](https://hub.boostio.co/) +> ### [Boost Note for Teams](https://boosthub.io/) > -> We'll launch the clean and simple wiki specially optimized for developers called "Boost Hub" at June 2020! +> We've developed a collaborative workspace app called "Boost Hub" for developer teams. > -> Boost Hub will aim to be a collaborative wiki tool for teams to centralize and amplify the availability and search ability of both first-party and third-party information. +> It's customizable and easy to optimize for your team like rego blocks and even lets you edit documents together in real-time! ![Boostnote app screenshot](./resources/repository/top.png) @@ -53,6 +53,10 @@ Issues on Boostnote can be funded by anyone and the money will be distributed to - [Blog](https://medium.com/boostnote) - [Reddit](https://www.reddit.com/r/Boostnote/) +### Boostnote mobile +A community project developing a mobile cross-platform version of boostnote for iOS and Android can be found here: [NoteApp](https://github.com/T0M0F/NoteApp) + + #### More Information - Website: https://boostnote.io diff --git a/yarn.lock b/yarn.lock index 27221ff9..df0fdf70 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1966,6 +1966,11 @@ combined-stream@1.0.6, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" +command-exists@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" + integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== + commander@2: version "2.16.0" resolved "http://registry.npm.taobao.org/commander/download/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" @@ -2583,7 +2588,44 @@ d3-zoom@1: d3-selection "1" d3-transition "1" -d3@^5.12, d3@^5.7.0: +d3@^5.14: + version "5.16.0" + resolved "https://registry.yarnpkg.com/d3/-/d3-5.16.0.tgz#9c5e8d3b56403c79d4ed42fbd62f6113f199c877" + integrity sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw== + dependencies: + d3-array "1" + d3-axis "1" + d3-brush "1" + d3-chord "1" + d3-collection "1" + d3-color "1" + d3-contour "1" + d3-dispatch "1" + d3-drag "1" + d3-dsv "1" + d3-ease "1" + d3-fetch "1" + d3-force "1" + d3-format "1" + d3-geo "1" + d3-hierarchy "1" + d3-interpolate "1" + d3-path "1" + d3-polygon "1" + d3-quadtree "1" + d3-random "1" + d3-scale "2" + d3-scale-chromatic "1" + d3-selection "1" + d3-shape "1" + d3-time "1" + d3-time-format "2" + d3-timer "1" + d3-transition "1" + d3-voronoi "1" + d3-zoom "1" + +d3@^5.7.0: version "5.12.0" resolved "https://registry.yarnpkg.com/d3/-/d3-5.12.0.tgz#0ddeac879c28c882317cd439b495290acd59ab61" integrity sha512-flYVMoVuhPFHd9zVCe2BxIszUWqBcd5fvQGMNRmSiBrgdnh6Vlruh60RJQTouAK9xPbOB0plxMvBm4MoyODXNg== @@ -2626,13 +2668,14 @@ d@1: dependencies: es5-ext "^0.10.9" -dagre-d3@dagrejs/dagre-d3: - version "0.6.4-pre" - resolved "https://codeload.github.com/dagrejs/dagre-d3/tar.gz/e1a00e5cb518f5d2304a35647e024f31d178e55b" +dagre-d3@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/dagre-d3/-/dagre-d3-0.6.4.tgz#0728d5ce7f177ca2337df141ceb60fbe6eeb7b29" + integrity sha512-e/6jXeCP7/ptlAM48clmX4xTZc5Ek6T6kagS7Oz2HrYSdqcLZFLqpAfh7ldbZRFfxCZVyh61NEPR08UQRVxJzQ== dependencies: - d3 "^5.12" - dagre "^0.8.4" - graphlib "^2.1.7" + d3 "^5.14" + dagre "^0.8.5" + graphlib "^2.1.8" lodash "^4.17.15" dagre@^0.8.4: @@ -2643,6 +2686,14 @@ dagre@^0.8.4: graphlib "^2.1.7" lodash "^4.17.4" +dagre@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/dagre/-/dagre-0.8.5.tgz#ba30b0055dac12b6c1fcc247817442777d06afee" + integrity sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw== + dependencies: + graphlib "^2.1.8" + lodash "^4.17.15" + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -3130,6 +3181,13 @@ entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" +entity-decode@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/entity-decode/-/entity-decode-2.0.2.tgz#e4f807e52c3294246e9347d1f2b02b07fd5f92e7" + integrity sha512-5CCY/3ci4MC1m2jlumNjWd7VBFt4VfFnmSqSNmVcXq4gxM3Vmarxtt+SvmBnzwLS669MWdVuXboNVj1qN2esVg== + dependencies: + he "^1.1.1" + env-paths@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0" @@ -4302,6 +4360,13 @@ graphlib@^2.1.7: dependencies: lodash "^4.17.5" +graphlib@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da" + integrity sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A== + dependencies: + lodash "^4.17.15" + gray-matter@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-2.1.1.tgz#3042d9adec2a1ded6a7707a9ed2380f8a17a430e" @@ -4490,7 +4555,7 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" -he@^1.2.0: +he@^1.1.1, he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== @@ -6108,15 +6173,10 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash@^4.0.0, lodash@^4.0.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.13, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1: - version "4.17.13" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93" - integrity sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA== - -lodash@^4.13.0, lodash@^4.17.11, lodash@^4.17.15: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +lodash@^4.0.0, lodash@^4.0.1, lodash@^4.12.0, lodash@^4.13.0, lodash@^4.13.1, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1: + version "4.17.19" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" + integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== lodash@~0.9.2: version "0.9.2" @@ -6400,22 +6460,21 @@ merge@^1.1.3: resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== -mermaid@^8.4.2: - version "8.4.2" - resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-8.4.2.tgz#91d3d8e9541e72eed7a78d0e882db11564fab3bb" - integrity sha512-vYSCP2u4XkOnjliWz/QIYwvzF/znQAq22vWJJ3YV40SnwV2JQyHblnwwNYXCprkXw7XfwBKDpSNaJ3HP4WfnZw== +mermaid@^8.5.2: + version "8.5.2" + resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-8.5.2.tgz#0f1914cda53d4ea5377380e5ce07a38bef2ea7e8" + integrity sha512-I+s+8/RzlazF3dGOhDUfU/ERkUV4zfIlTWb3703jNx+2lfACs+4AdY9ULQaw6BPWzW3gB+XlXFOOX/m/vqujIA== dependencies: "@braintree/sanitize-url" "^3.1.0" crypto-random-string "^3.0.1" d3 "^5.7.0" dagre "^0.8.4" - dagre-d3 dagrejs/dagre-d3 + dagre-d3 "^0.6.4" + entity-decode "^2.0.2" graphlib "^2.1.7" he "^1.2.0" - lodash "^4.17.11" minify "^4.1.1" moment-mini "^2.22.1" - prettier "^1.18.2" scope-css "^1.2.1" methods@~1.1.2: @@ -10027,8 +10086,9 @@ websocket-driver@>=0.5.1: websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== well-known-symbols@^1.0.0: version "1.0.0"