From b9a8a7f7ec90e527c62c439abb57bcb873bd6035 Mon Sep 17 00:00:00 2001 From: Alf Eaton Date: Mon, 17 Jun 2024 11:34:09 +0100 Subject: [PATCH] Move AI provider usage to the backend (#18562) GitOrigin-RevId: 4f66c6576571c4fbb7381d8d0e34f2e468d6f34f --- package-lock.json | 132 ++---------------- .../src/Features/Project/ProjectController.js | 1 + .../Features/Tutorial/TutorialController.js | 1 + .../web/app/views/project/editor/meta.pug | 1 + services/web/config/settings.defaults.js | 1 + .../pdf-preview/components/pdf-log-entry.jsx | 25 +++- .../components/pdf-logs-entries.jsx | 1 + .../features/pdf-preview/util/output-files.js | 8 +- .../source-editor/extensions/annotations.ts | 66 +++++++-- .../source-editor/extensions/theme.ts | 9 ++ .../js/ide/log-parser/latex-log-parser.js | 12 +- .../shared/context/local-compile-context.tsx | 12 ++ .../js/shared/context/project-context.tsx | 4 + .../bootstrap-5/components/button.scss | 4 + .../stylesheets/components/buttons.less | 3 + services/web/package.json | 3 +- services/web/test/frontend/bootstrap.js | 2 +- services/web/types/annotation.ts | 3 + 18 files changed, 147 insertions(+), 141 deletions(-) diff --git a/package-lock.json b/package-lock.json index a9f9b51945..8b398e8b1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14708,17 +14708,6 @@ "node": ">= 6.0.0" } }, - "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -21858,6 +21847,14 @@ "resolved": "https://registry.npmjs.org/events-listener/-/events-listener-1.1.0.tgz", "integrity": "sha512-Kd3EgYfODHueq6GzVfs/VUolh2EgJsS8hkO3KpnDrxVjU3eq63eXM2ujXkhPP+OkeUOhL8CxdfZbQXzryb5C4g==" }, + "node_modules/eventsource-parser": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.1.2.tgz", + "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==", + "engines": { + "node": ">=14.18" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -25275,14 +25272,6 @@ "node": ">=8.12.0" } }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dependencies": { - "ms": "^2.0.0" - } - }, "node_modules/hyphenate-style-name": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", @@ -28840,23 +28829,6 @@ "micromark-util-types": "^2.0.0" } }, - "node_modules/micromark-extension-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", - "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", - "dev": true, - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/micromark-factory-destination": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", @@ -30897,32 +30869,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openai": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.36.0.tgz", - "integrity": "sha512-AtYrhhWY64LhB9P6f3H0nV8nTSaQJ89mWPnfNU5CnYg81zlYaV8nkyO+aTNfprdqP/9xv10woNNUgefXINT4Dg==", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7", - "web-streams-polyfill": "^3.2.1" - }, - "bin": { - "openai": "bin/cli" - } - }, - "node_modules/openai/node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } - }, "node_modules/openapi3-ts": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-3.1.2.tgz", @@ -44630,6 +44576,7 @@ "east": "^2.0.2", "ejs": "^3.1.10", "email-addresses": "^5.0.0", + "eventsource-parser": "^1.1.2", "express": "^4.19.2", "express-bearer-token": "^2.4.0", "express-http-proxy": "^1.6.0", @@ -44661,7 +44608,6 @@ "nodemailer": "^6.7.0", "nodemailer-ses-transport": "^1.5.1", "on-headers": "^1.0.2", - "openai": "^4.36.0", "otplib": "^12.0.1", "p-limit": "^2.3.0", "p-props": "4.0.0", @@ -44833,7 +44779,6 @@ "mathjax": "^3.2.2", "mensch": "^0.3.4", "micromark": "^4.0.0", - "micromark-extension-gfm-table": "^2.0.0", "mini-css-extract-plugin": "^2.7.6", "mocha": "^10.2.0", "mocha-each": "^2.0.1", @@ -53295,6 +53240,7 @@ "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", "events": "^3.3.0", + "eventsource-parser": "^1.1.2", "expose-loader": "^4.1.0", "express": "^4.19.2", "express-bearer-token": "^2.4.0", @@ -53331,7 +53277,6 @@ "mensch": "^0.3.4", "method-override": "^2.3.3", "micromark": "^4.0.0", - "micromark-extension-gfm-table": "^2.0.0", "mini-css-extract-plugin": "^2.7.6", "minimatch": "^7.4.2", "minimist": "^1.2.7", @@ -53349,7 +53294,6 @@ "nodemailer-ses-transport": "^1.5.1", "nvd3": "^1.8.6", "on-headers": "^1.0.2", - "openai": "^4.36.0", "otplib": "^12.0.1", "p-limit": "^2.3.0", "p-props": "4.0.0", @@ -59198,14 +59142,6 @@ "debug": "4" } }, - "agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "requires": { - "humanize-ms": "^1.2.1" - } - }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -64617,6 +64553,11 @@ "resolved": "https://registry.npmjs.org/events-listener/-/events-listener-1.1.0.tgz", "integrity": "sha512-Kd3EgYfODHueq6GzVfs/VUolh2EgJsS8hkO3KpnDrxVjU3eq63eXM2ujXkhPP+OkeUOhL8CxdfZbQXzryb5C4g==" }, + "eventsource-parser": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.1.2.tgz", + "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==" + }, "execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -67268,14 +67209,6 @@ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true }, - "humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "requires": { - "ms": "^2.0.0" - } - }, "hyphenate-style-name": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", @@ -70942,19 +70875,6 @@ "micromark-util-types": "^2.0.0" } }, - "micromark-extension-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", - "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", - "dev": true, - "requires": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, "micromark-factory-destination": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", @@ -72380,28 +72300,6 @@ "is-wsl": "^2.2.0" } }, - "openai": { - "version": "4.36.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.36.0.tgz", - "integrity": "sha512-AtYrhhWY64LhB9P6f3H0nV8nTSaQJ89mWPnfNU5CnYg81zlYaV8nkyO+aTNfprdqP/9xv10woNNUgefXINT4Dg==", - "requires": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7", - "web-streams-polyfill": "^3.2.1" - }, - "dependencies": { - "web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==" - } - } - }, "openapi3-ts": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-3.1.2.tgz", diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js index 1d0af6f488..35b167eec3 100644 --- a/services/web/app/src/Features/Project/ProjectController.js +++ b/services/web/app/src/Features/Project/ProjectController.js @@ -670,6 +670,7 @@ const _ProjectController = { debugPdfDetach, showSymbolPalette, symbolPaletteAvailable: Features.hasFeature('symbol-palette'), + showAiErrorAssistant: user.alphaProgram, // TODO: labs experiment detachRole, metadata: { viewport: false }, showUpgradePrompt, diff --git a/services/web/app/src/Features/Tutorial/TutorialController.js b/services/web/app/src/Features/Tutorial/TutorialController.js index 1390e18931..d64c33df0c 100644 --- a/services/web/app/src/Features/Tutorial/TutorialController.js +++ b/services/web/app/src/Features/Tutorial/TutorialController.js @@ -8,6 +8,7 @@ const VALID_KEYS = [ 'writefull-integration', 'writefull-oauth-promotion', 'bib-file-tpr-prompt', + 'ai-error-assistant-consent', ] async function completeTutorial(req, res, next) { diff --git a/services/web/app/views/project/editor/meta.pug b/services/web/app/views/project/editor/meta.pug index f161fd81a4..3210d65537 100644 --- a/services/web/app/views/project/editor/meta.pug +++ b/services/web/app/views/project/editor/meta.pug @@ -21,6 +21,7 @@ meta(name="ol-pdfjsVariant" content=pdfjsVariant) meta(name="ol-debugPdfDetach" data-type="boolean" content=debugPdfDetach) meta(name="ol-showSymbolPalette" data-type="boolean" content=showSymbolPalette) meta(name="ol-symbolPaletteAvailable" data-type="boolean" content=symbolPaletteAvailable) +meta(name="ol-showAiErrorAssistant" data-type="boolean" content=showAiErrorAssistant) meta(name="ol-detachRole" data-type="string" content=detachRole) meta(name="ol-allowedImageNames" data-type="json" content=allowedImageNames) meta(name="ol-languages" data-type="json" content=languages) diff --git a/services/web/config/settings.defaults.js b/services/web/config/settings.defaults.js index a9db3a1344..4254a41611 100644 --- a/services/web/config/settings.defaults.js +++ b/services/web/config/settings.defaults.js @@ -876,6 +876,7 @@ module.exports = { sourceEditorExtensions: [], sourceEditorComponents: [], pdfLogEntryComponents: [], + diagnosticActions: [], sourceEditorCompletionSources: [], sourceEditorSymbolPalette: [], sourceEditorToolbarComponents: [], diff --git a/services/web/frontend/js/features/pdf-preview/components/pdf-log-entry.jsx b/services/web/frontend/js/features/pdf-preview/components/pdf-log-entry.jsx index 4eee462eaa..8ee421ad7c 100644 --- a/services/web/frontend/js/features/pdf-preview/components/pdf-log-entry.jsx +++ b/services/web/frontend/js/features/pdf-preview/components/pdf-log-entry.jsx @@ -5,6 +5,7 @@ import PreviewLogEntryHeader from '../../preview/components/preview-log-entry-he import PdfLogEntryContent from './pdf-log-entry-content' import HumanReadableLogsHints from '../../../ide/human-readable-logs/HumanReadableLogsHints' import { sendMB } from '@/infrastructure/event-tracking' +import getMeta from '@/utils/meta' function PdfLogEntry({ ruleId, @@ -25,7 +26,10 @@ function PdfLogEntry({ onClose, index, logEntry, + id, }) { + const showAiErrorAssistant = getMeta('ol-showAiErrorAssistant') + if (ruleId && HumanReadableLogsHints[ruleId]) { const hint = HumanReadableLogsHints[ruleId] formattedContent = hint.formattedContent(contentDetails) @@ -44,11 +48,29 @@ function PdfLogEntry({ [level, onSourceLocationClick, ruleId, sourceLocation] ) + const logEntryRef = useCallback( + element => { + if (element) { + window.addEventListener('editor:view-compile-log-entry', event => { + if (event.detail.id === id) { + element.scrollIntoView({ block: 'start', inline: 'nearest' }) + } + + if (event.detail.suggestFix) { + element.querySelector('button[data-action="suggest-fix"]')?.click() + } + }) + } + }, + [id] + ) + return (
- {(rawContent || formattedContent || window.user.alphaProgram) && ( + {(rawContent || formattedContent || showAiErrorAssistant) && ( { @@ -140,6 +140,7 @@ export function buildLogEntryAnnotations(entries, fileTreeData, rootDocId) { const rootDocDirname = dirname(fileTreeData, rootDocId) const logEntryAnnotations = {} + const seenLine = {} for (const entry of entries) { if (entry.file) { @@ -153,12 +154,17 @@ export function buildLogEntryAnnotations(entries, fileTreeData, rootDocId) { } logEntryAnnotations[entity._id].push({ + id: entry.key, + entryIndex: logEntryAnnotations[entity._id].length, // used for maintaining the order of items on the same line row: entry.line - 1, type: entry.level === 'error' ? 'error' : 'warning', text: entry.message, source: 'compile', // NOTE: this is used in Ace for filtering the annotations ruleId: entry.ruleId, + firstOnLine: !seenLine[entry.line], }) + + seenLine[entry.line] = true } } } diff --git a/services/web/frontend/js/features/source-editor/extensions/annotations.ts b/services/web/frontend/js/features/source-editor/extensions/annotations.ts index eb03ac94ef..1f8521e9a7 100644 --- a/services/web/frontend/js/features/source-editor/extensions/annotations.ts +++ b/services/web/frontend/js/features/source-editor/extensions/annotations.ts @@ -12,6 +12,34 @@ import { import { Annotation } from '../../../../../types/annotation' import { debugConsole } from '@/utils/debugging' import { sendMB } from '@/infrastructure/event-tracking' +import importOverleafModules from '../../../../macros/import-overleaf-module.macro' + +interface CompileLogDiagnostic extends Diagnostic { + compile?: true + ruleId?: string + id?: string + entryIndex: number + firstOnLine?: boolean +} + +type RenderedDiagnostic = Pick< + CompileLogDiagnostic, + | 'message' + | 'severity' + | 'ruleId' + | 'compile' + | 'source' + | 'id' + | 'firstOnLine' +> + +export type DiagnosticAction = ( + diagnostic: RenderedDiagnostic +) => HTMLButtonElement | null + +const diagnosticActions = importOverleafModules('diagnosticActions') as { + import: { default: DiagnosticAction } +}[] const compileLintSourceConf = new Compartment() @@ -56,7 +84,8 @@ export const lintSourceConfig = { */ const compileLogLintSource = (): Extension => linter(view => { - const items: Diagnostic[] = [] + const items: CompileLogDiagnostic[] = [] + // NOTE: iter() changes the order of diagnostics on the same line const cursor = view.state.field(compileDiagnosticsState).iter() while (cursor.value !== null) { const { diagnostic } = cursor.value @@ -68,14 +97,11 @@ const compileLogLintSource = (): Extension => }) cursor.next() } + // restore the original order of items + items.sort((a, b) => a.from - b.from || a.entryIndex - b.entryIndex) return items }, lintSourceConfig) -interface CompileLogDiagnostic extends Diagnostic { - compile?: true - ruleId?: string -} - class CompileLogDiagnosticRangeValue extends RangeValue { constructor(public diagnostic: CompileLogDiagnostic) { super() @@ -117,7 +143,7 @@ export const compileDiagnosticsState = StateField.define< }) export const setAnnotations = (doc: Text, annotations: Annotation[]) => { - const diagnostics: Diagnostic[] = [] + const diagnostics: CompileLogDiagnostic[] = [] for (const annotation of annotations) { // ignore "whole document" (row: -1) annotations @@ -162,19 +188,31 @@ const convertAnnotationToDiagnostic = ( message: annotation.text, ruleId: annotation.ruleId, compile: true, + id: annotation.id, + entryIndex: annotation.entryIndex, + source: annotation.source, + firstOnLine: annotation.firstOnLine, } } -export const renderMessage = ( - diagnostic: Pick< - CompileLogDiagnostic, - 'message' | 'severity' | 'ruleId' | 'compile' - > -) => { +export const renderMessage = (diagnostic: RenderedDiagnostic) => { const { message, severity, ruleId, compile = false } = diagnostic const div = document.createElement('div') - div.textContent = message + div.classList.add('ol-cm-diagnostic-message') + + div.append(message) + + const activeDiagnosticActions = diagnosticActions + .map(m => m.import.default(diagnostic)) + .filter(Boolean) as HTMLButtonElement[] + + if (activeDiagnosticActions.length) { + const actions = document.createElement('div') + actions.classList.add('ol-cm-diagnostic-actions') + actions.append(...activeDiagnosticActions) + div.append(actions) + } window.setTimeout(() => { if (div.isConnected) { diff --git a/services/web/frontend/js/features/source-editor/extensions/theme.ts b/services/web/frontend/js/features/source-editor/extensions/theme.ts index f3694fd82e..6a60fd6a09 100644 --- a/services/web/frontend/js/features/source-editor/extensions/theme.ts +++ b/services/web/frontend/js/features/source-editor/extensions/theme.ts @@ -155,6 +155,15 @@ const baseTheme = EditorView.baseTheme({ boxShadow: '0 1px 1px rgba(255, 255, 255, 0.7)', backgroundColor: 'rgba(255, 255, 255, 0.2)', }, + '.cm-diagnosticSource': { + display: 'none', + }, + '.ol-cm-diagnostic-actions': { + marginTop: '4px', + }, + '.cm-diagnostic:last-of-type .ol-cm-diagnostic-actions': { + marginBottom: '4px', + }, }) /** diff --git a/services/web/frontend/js/ide/log-parser/latex-log-parser.js b/services/web/frontend/js/ide/log-parser/latex-log-parser.js index 2a64340101..52733d274c 100644 --- a/services/web/frontend/js/ide/log-parser/latex-log-parser.js +++ b/services/web/frontend/js/ide/log-parser/latex-log-parser.js @@ -211,7 +211,7 @@ export default class LatexParser { // Check if we're entering or leaving a new file in this line parseParensForFilenames() { - const pos = this.currentLine.search(/\(|\)/) + const pos = this.currentLine.search(/[()]/) if (pos !== -1) { const token = this.currentLine[pos] this.currentLine = this.currentLine.slice(pos + 1) @@ -251,12 +251,14 @@ export default class LatexParser { consumeFilePath() { // Our heuristic for detecting file names are rather crude - // A file may not contain a ')' in it - // To be a file path it must have at least one / - if (!this.currentLine.match(/^\/?([^ )]+\/)+/)) { + + // To contain a file path this line must have at least one / before any '(', ')' or '\' + if (!this.currentLine.match(/^\/?([^ ()\\]+\/)+/)) { return false } - let endOfFilePath = this.currentLine.search(/ |\)/) + + // A file may not contain a '(', ')' or '\' + let endOfFilePath = this.currentLine.search(/[ ()\\]/) // handle the case where there is a space in a filename while (endOfFilePath !== -1 && this.currentLine[endOfFilePath] === ' ') { diff --git a/services/web/frontend/js/shared/context/local-compile-context.tsx b/services/web/frontend/js/shared/context/local-compile-context.tsx index 0848217f75..ece79901a7 100644 --- a/services/web/frontend/js/shared/context/local-compile-context.tsx +++ b/services/web/frontend/js/shared/context/local-compile-context.tsx @@ -596,6 +596,18 @@ export const LocalCompileProvider: FC = ({ children }) => { // used for that compile. const lastCompileOptions = useMemo(() => data?.options || {}, [data]) + useEffect(() => { + const listener = (event: Event) => { + setShowLogs((event as CustomEvent).detail as boolean) + } + + window.addEventListener('editor:show-logs', listener) + + return () => { + window.removeEventListener('editor:show-logs', listener) + } + }, []) + const value = useMemo( () => ({ animateCompileDropdownArrow, diff --git a/services/web/frontend/js/shared/context/project-context.tsx b/services/web/frontend/js/shared/context/project-context.tsx index e473955f5d..11e4e67386 100644 --- a/services/web/frontend/js/shared/context/project-context.tsx +++ b/services/web/frontend/js/shared/context/project-context.tsx @@ -10,6 +10,7 @@ const ProjectContext = createContext< _id: string name: string rootDocId?: string + compiler: string members: { _id: UserId; email: string; privileges: string }[] invites: { _id: UserId }[] features: { @@ -66,6 +67,7 @@ export const ProjectProvider: FC = ({ children }) => { const { _id, + compiler, name, rootDoc_id: rootDocId, members, @@ -87,6 +89,7 @@ export const ProjectProvider: FC = ({ children }) => { const value = useMemo(() => { return { _id, + compiler, name, rootDocId, members, @@ -99,6 +102,7 @@ export const ProjectProvider: FC = ({ children }) => { } }, [ _id, + compiler, name, rootDocId, members, diff --git a/services/web/frontend/stylesheets/bootstrap-5/components/button.scss b/services/web/frontend/stylesheets/bootstrap-5/components/button.scss index dbfcefe101..593b376e65 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/components/button.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/components/button.scss @@ -85,6 +85,10 @@ ); background: var(--premium-gradient); + transition: none; + &:hover { + background: var(--blue-70); + } } } diff --git a/services/web/frontend/stylesheets/components/buttons.less b/services/web/frontend/stylesheets/components/buttons.less index 8d70e1e191..3d1fbd7ad7 100755 --- a/services/web/frontend/stylesheets/components/buttons.less +++ b/services/web/frontend/stylesheets/components/buttons.less @@ -127,6 +127,9 @@ .btn-premium { .premium-background; color: @white; + &:hover { + background: @blue-70; + } } .reset-btns { diff --git a/services/web/package.json b/services/web/package.json index d1df083192..8fe65fd3ca 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -109,6 +109,7 @@ "east": "^2.0.2", "ejs": "^3.1.10", "email-addresses": "^5.0.0", + "eventsource-parser": "^1.1.2", "express": "^4.19.2", "express-bearer-token": "^2.4.0", "express-http-proxy": "^1.6.0", @@ -140,7 +141,6 @@ "nodemailer": "^6.7.0", "nodemailer-ses-transport": "^1.5.1", "on-headers": "^1.0.2", - "openai": "^4.36.0", "otplib": "^12.0.1", "p-limit": "^2.3.0", "p-props": "4.0.0", @@ -312,7 +312,6 @@ "mathjax": "^3.2.2", "mensch": "^0.3.4", "micromark": "^4.0.0", - "micromark-extension-gfm-table": "^2.0.0", "mini-css-extract-plugin": "^2.7.6", "mocha": "^10.2.0", "mocha-each": "^2.0.1", diff --git a/services/web/test/frontend/bootstrap.js b/services/web/test/frontend/bootstrap.js index 676d8ad2f3..6bb483b69c 100644 --- a/services/web/test/frontend/bootstrap.js +++ b/services/web/test/frontend/bootstrap.js @@ -1,6 +1,6 @@ // Run babel on tests to allow support for import/export statements in Node require('@babel/register')({ - extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs'], + extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.svg'], plugins: [['module-resolver', { alias: { '^@/(.+)': './frontend/js/\\1' } }]], }) diff --git a/services/web/types/annotation.ts b/services/web/types/annotation.ts index 9d5f974b6f..1eacda21c5 100644 --- a/services/web/types/annotation.ts +++ b/services/web/types/annotation.ts @@ -4,4 +4,7 @@ export type Annotation = { text: string source?: string ruleId?: string + id: string + entryIndex: number + firstOnLine: boolean }