-
{{ result }}
+
{{ $t('msg.info.computedFieldEditWarning') }}
diff --git a/packages/nc-gui/package.json b/packages/nc-gui/package.json
index bf9026a3d2..b7fe21a906 100644
--- a/packages/nc-gui/package.json
+++ b/packages/nc-gui/package.json
@@ -66,6 +66,7 @@
"emoji-mart-vue-fast": "^15.0.2",
"file-saver": "^2.0.5",
"fuse.js": "^6.6.2",
+ "html-entities": "^2.5.2",
"httpsnippet": "^2.0.0",
"inflection": "^1.13.4",
"jsbarcode": "^3.11.6",
@@ -75,7 +76,7 @@
"leaflet.markercluster": "^1.5.3",
"locale-codes": "^1.3.1",
"marked": "^4.3.0",
- "monaco-editor": "^0.45.0",
+ "monaco-editor": "^0.50.0",
"monaco-sql-languages": "^0.11.0",
"nocodb-sdk": "workspace:^",
"papaparse": "^5.4.1",
diff --git a/packages/nc-gui/plugins/monaco.ts b/packages/nc-gui/plugins/monaco.ts
new file mode 100644
index 0000000000..073dc1a67b
--- /dev/null
+++ b/packages/nc-gui/plugins/monaco.ts
@@ -0,0 +1,23 @@
+import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker&inline'
+import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker&inline'
+
+export default defineNuxtPlugin(() => {
+ /**
+ * Adding monaco editor to Vite
+ *
+ * @ts-expect-error */
+ self.MonacoEnvironment = window.MonacoEnvironment = {
+ async getWorker(_: any, label: string) {
+ switch (label) {
+ case 'json': {
+ const workerBlob = new Blob([JsonWorker], { type: 'text/javascript' })
+ return await initWorker(URL.createObjectURL(workerBlob))
+ }
+ default: {
+ const workerBlob = new Blob([EditorWorker], { type: 'text/javascript' })
+ return await initWorker(URL.createObjectURL(workerBlob))
+ }
+ }
+ },
+ }
+})
diff --git a/packages/nc-gui/utils/urlUtils.ts b/packages/nc-gui/utils/urlUtils.ts
index 9d13496b1c..0607a8cc17 100644
--- a/packages/nc-gui/utils/urlUtils.ts
+++ b/packages/nc-gui/utils/urlUtils.ts
@@ -1,35 +1,36 @@
import isURL from 'validator/lib/isURL'
+import { decode } from 'html-entities'
+
export const replaceUrlsWithLink = (text: string): boolean | string => {
if (!text) {
return false
}
const rawText = text.toString()
- // Create a temporary element to sanitize the string by encoding any HTML code
- const tempEl = document.createElement('div')
- tempEl.textContent = rawText
- const sanitisedText = tempEl.innerHTML
-
const protocolRegex = /^(https?|ftp|mailto|file):\/\//
+ let isUrl
- const out = sanitisedText.replace(/URI::\(([^)]*)\)(?: LABEL::\(([^)]*)\))?/g, (_, url, label) => {
+ const out = rawText.replace(/URI::\(([^)]*)\)(?: LABEL::\(([^)]*)\))?/g, (_, url, label) => {
if (!url.trim() && !label) {
return ' '
}
const fullUrl = protocolRegex.test(url) ? url : url.trim() ? `http://${url}` : ''
+
+ isUrl = isURL(fullUrl)
+
const anchorLabel = label || url || ''
const a = document.createElement('a')
a.textContent = anchorLabel
- a.setAttribute('href', fullUrl)
+ a.setAttribute('href', decode(fullUrl))
a.setAttribute('class', ' nc-cell-field-link')
a.setAttribute('target', '_blank')
a.setAttribute('rel', 'noopener,noreferrer')
return a.outerHTML
})
- return out
+ return isUrl ? out : false
}
export const isValidURL = (str: string, extraProps?) => {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 16f1da21e7..3d82101f35 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -127,6 +127,9 @@ importers:
fuse.js:
specifier: ^6.6.2
version: 6.6.2
+ html-entities:
+ specifier: ^2.5.2
+ version: 2.5.2
httpsnippet:
specifier: ^2.0.0
version: 2.0.0(mkdirp@2.1.6)
@@ -155,8 +158,8 @@ importers:
specifier: ^4.3.0
version: 4.3.0
monaco-editor:
- specifier: ^0.45.0
- version: 0.45.0
+ specifier: ^0.50.0
+ version: 0.50.0
monaco-sql-languages:
specifier: ^0.11.0
version: 0.11.0
@@ -430,7 +433,7 @@ importers:
version: 0.26.0(vue@3.4.34)
vite-plugin-monaco-editor:
specifier: ^1.1.0
- version: 1.1.0(monaco-editor@0.45.0)
+ version: 1.1.0(monaco-editor@0.50.0)
vite-plugin-purge-icons:
specifier: ^0.10.0
version: 0.10.0(vite@4.5.3)
@@ -18136,6 +18139,10 @@ packages:
resolution: {integrity: sha512-Cc/RSOGlojr7NDw1oXamUQenYBB0f/SISO8QWtRdZkDOmlO/hvbGZMjgyl+6+mh2PKPRrGXUKH4JhCU18LNS2g==}
dev: false
+ /html-entities@2.5.2:
+ resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==}
+ dev: false
+
/html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
dev: true
@@ -21362,8 +21369,8 @@ packages:
resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==}
dev: false
- /monaco-editor@0.45.0:
- resolution: {integrity: sha512-mjv1G1ZzfEE3k9HZN0dQ2olMdwIfaeAAjFiwNprLfYNRSz7ctv9XuCT7gPtBGrMUeV1/iZzYKj17Khu1hxoHOA==}
+ /monaco-editor@0.50.0:
+ resolution: {integrity: sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA==}
/monaco-sql-languages@0.11.0:
resolution: {integrity: sha512-OoTQVLT6ldBXPEbQPw43hOy+u16dO+HkY/rCADXPM5NfRBQ1m9+04NdaQ94WcF2R6MPeansxW8AveIdjEhxqfw==}
@@ -25925,9 +25932,6 @@ packages:
/sqlite3@5.1.6:
resolution: {integrity: sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==}
requiresBuild: true
- peerDependenciesMeta:
- node-gyp:
- optional: true
dependencies:
'@mapbox/node-pre-gyp': 1.0.11
node-addon-api: 4.3.0
@@ -25942,9 +25946,6 @@ packages:
/sqlite3@5.1.7:
resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==}
requiresBuild: true
- peerDependenciesMeta:
- node-gyp:
- optional: true
dependencies:
bindings: 1.5.0
node-addon-api: 7.0.0
@@ -28205,12 +28206,12 @@ packages:
- supports-color
dev: true
- /vite-plugin-monaco-editor@1.1.0(monaco-editor@0.45.0):
+ /vite-plugin-monaco-editor@1.1.0(monaco-editor@0.50.0):
resolution: {integrity: sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==}
peerDependencies:
monaco-editor: '>=0.33.0'
dependencies:
- monaco-editor: 0.45.0
+ monaco-editor: 0.50.0
dev: true
/vite-plugin-purge-icons@0.10.0(vite@4.5.3):
diff --git a/tests/playwright/pages/Dashboard/Grid/Column/index.ts b/tests/playwright/pages/Dashboard/Grid/Column/index.ts
index 02eb2e1b84..2d3b1595e5 100644
--- a/tests/playwright/pages/Dashboard/Grid/Column/index.ts
+++ b/tests/playwright/pages/Dashboard/Grid/Column/index.ts
@@ -143,7 +143,7 @@ export class ColumnPageObject extends BasePage {
await this.rootPage.locator('.ant-select-item').locator(`text="${timeFormat}"`).click();
break;
case 'Formula':
- await this.get().locator('.nc-formula-input').fill(formula);
+ await this.get().locator('.inputarea').fill(formula);
break;
case 'QrCode':
await this.get().locator('.ant-select-single').nth(1).click();
@@ -222,7 +222,6 @@ export class ColumnPageObject extends BasePage {
await this.ltarOption.addFilters(ltarFilters);
}
-
if (custom) {
// enable advance options
await this.get().locator('.nc-ltar-relation-type >> .ant-radio').nth(1).dblclick();
@@ -387,9 +386,18 @@ export class ColumnPageObject extends BasePage {
await this.defaultValueBtn().click();
switch (type) {
- case 'Formula':
- await this.get().locator('.nc-formula-input').fill(formula);
+ case 'Formula': {
+ const element = this.get().locator('.inputarea');
+ await element.focus();
+
+ await this.rootPage.keyboard.press('Control+A');
+ await this.rootPage.waitForTimeout(200);
+
+ await this.rootPage.keyboard.press('Backspace');
+ await this.rootPage.waitForTimeout(200);
+ await element.fill(formula);
break;
+ }
case 'Duration':
await this.get().locator('.ant-select-single').nth(1).click();
await this.rootPage.locator(`.ant-select-item`).getByTestId(format).click();
diff --git a/tests/playwright/tests/db/columns/columnFormula.spec.ts b/tests/playwright/tests/db/columns/columnFormula.spec.ts
index 29053a016b..4d5876f4d0 100644
--- a/tests/playwright/tests/db/columns/columnFormula.spec.ts
+++ b/tests/playwright/tests/db/columns/columnFormula.spec.ts
@@ -145,13 +145,7 @@ const formulaDataByDbType = (context: NcContext, index: number) => {
},
{
formula: 'URLENCODE({City})',
- result: [
- 'A%20Corua%20(La%20Corua)',
- 'Abha',
- 'Abu%20Dhabi',
- 'Acua',
- 'Adana',
- ],
+ result: ['A%20Corua%20(La%20Corua)', 'Abha', 'Abu%20Dhabi', 'Acua', 'Adana'],
},
];
else