Merge pull request #2834 from Bilb/update-electron
chore: update node version, electron and deps
This commit is contained in:
commit
940c3f622a
|
@ -10,6 +10,9 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- clearnet
|
- clearnet
|
||||||
- unstable
|
- unstable
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -50,7 +53,6 @@ jobs:
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
run: |
|
run: |
|
||||||
npm install --global yarn node-gyp@latest
|
npm install --global yarn node-gyp@latest
|
||||||
npm config set msvs_version 2022
|
|
||||||
|
|
||||||
- name: Install Desktop node_modules
|
- name: Install Desktop node_modules
|
||||||
if: steps.cache-desktop-modules.outputs.cache-hit != 'true'
|
if: steps.cache-desktop-modules.outputs.cache-hit != 'true'
|
||||||
|
|
|
@ -6,6 +6,11 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- clearnet
|
- clearnet
|
||||||
- unstable
|
- unstable
|
||||||
|
- unstable1
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -31,7 +36,8 @@ jobs:
|
||||||
|
|
||||||
- name: Cache Desktop node_modules
|
- name: Cache Desktop node_modules
|
||||||
id: cache-desktop-modules
|
id: cache-desktop-modules
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
|
if: runner.os != 'Windows'
|
||||||
with:
|
with:
|
||||||
path: node_modules
|
path: node_modules
|
||||||
key: ${{ runner.os }}-${{ hashFiles('package.json', 'yarn.lock', 'patches/**') }}
|
key: ${{ runner.os }}-${{ hashFiles('package.json', 'yarn.lock', 'patches/**') }}
|
||||||
|
@ -45,7 +51,6 @@ jobs:
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
run: |
|
run: |
|
||||||
npm install --global node-gyp@latest
|
npm install --global node-gyp@latest
|
||||||
npm config set msvs_version 2022
|
|
||||||
|
|
||||||
- name: Install Desktop node_modules
|
- name: Install Desktop node_modules
|
||||||
if: steps.cache-desktop-modules.outputs.cache-hit != 'true'
|
if: steps.cache-desktop-modules.outputs.cache-hit != 'true'
|
||||||
|
|
|
@ -30,7 +30,7 @@ jobs:
|
||||||
|
|
||||||
- name: Cache Desktop node_modules
|
- name: Cache Desktop node_modules
|
||||||
id: cache-desktop-modules
|
id: cache-desktop-modules
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
if: runner.os != 'Windows'
|
if: runner.os != 'Windows'
|
||||||
with:
|
with:
|
||||||
path: node_modules
|
path: node_modules
|
||||||
|
@ -45,7 +45,6 @@ jobs:
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
run: |
|
run: |
|
||||||
npm install --global node-gyp@latest
|
npm install --global node-gyp@latest
|
||||||
npm config set msvs_version 2022
|
|
||||||
|
|
||||||
- name: Install Desktop node_modules
|
- name: Install Desktop node_modules
|
||||||
if: steps.cache-desktop-modules.outputs.cache-hit != 'true'
|
if: steps.cache-desktop-modules.outputs.cache-hit != 'true'
|
||||||
|
|
|
@ -49,7 +49,7 @@ base64 -i certificate.p12 -o encoded.txt
|
||||||
|
|
||||||
### Node version
|
### Node version
|
||||||
|
|
||||||
You will need node `16.13.0`.
|
You will need node `18.15.0`.
|
||||||
This can be done by using [nvm](https://github.com/nvm-sh/nvm) and running `nvm use` or you can install it manually.
|
This can be done by using [nvm](https://github.com/nvm-sh/nvm) and running `nvm use` or you can install it manually.
|
||||||
Once nvm is installed, just run `nvm install` to install the version from the `.nvmrc` file and then `nvm use` to use it.
|
Once nvm is installed, just run `nvm install` to install the version from the `.nvmrc` file and then `nvm use` to use it.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const { notarize } = require('electron-notarize');
|
const { notarize } = require('@electron/notarize');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Pre-requisites: https://github.com/electron/electron-notarize#prerequisites
|
Pre-requisites: https://github.com/electron/electron-notarize#prerequisites
|
||||||
|
|
23
package.json
23
package.json
|
@ -22,7 +22,6 @@
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"ini": "^1.3.6",
|
"ini": "^1.3.6",
|
||||||
"ejs": "^3.1.7",
|
"ejs": "^3.1.7",
|
||||||
"electron": "^17.2.0",
|
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"@types/react": "17.0.2",
|
"@types/react": "17.0.2",
|
||||||
"glob-parent": "^6.0.1",
|
"glob-parent": "^6.0.1",
|
||||||
|
@ -75,11 +74,11 @@
|
||||||
"@emoji-mart/data": "^1.0.6",
|
"@emoji-mart/data": "^1.0.6",
|
||||||
"@emoji-mart/react": "^1.0.1",
|
"@emoji-mart/react": "^1.0.1",
|
||||||
"@reduxjs/toolkit": "1.8.5",
|
"@reduxjs/toolkit": "1.8.5",
|
||||||
|
"@signalapp/better-sqlite3": "^8.4.3",
|
||||||
"@types/react-mentions": "^4.1.8",
|
"@types/react-mentions": "^4.1.8",
|
||||||
"abort-controller": "3.0.0",
|
"abort-controller": "3.0.0",
|
||||||
"auto-bind": "^4.0.0",
|
"auto-bind": "^4.0.0",
|
||||||
"backbone": "1.3.3",
|
"backbone": "1.3.3",
|
||||||
"better-sqlite3": "https://github.com/oxen-io/session-better-sqlite3#af47530acea25800d22b5e1ae834b709d2bfca40",
|
|
||||||
"blob-util": "2.0.2",
|
"blob-util": "2.0.2",
|
||||||
"blueimp-canvas-to-blob": "^3.29.0",
|
"blueimp-canvas-to-blob": "^3.29.0",
|
||||||
"blueimp-load-image": "5.14.0",
|
"blueimp-load-image": "5.14.0",
|
||||||
|
@ -92,7 +91,6 @@
|
||||||
"country-code-lookup": "^0.0.19",
|
"country-code-lookup": "^0.0.19",
|
||||||
"curve25519-js": "https://github.com/oxen-io/curve25519-js",
|
"curve25519-js": "https://github.com/oxen-io/curve25519-js",
|
||||||
"dompurify": "^2.0.7",
|
"dompurify": "^2.0.7",
|
||||||
"electron-is-dev": "^1.1.0",
|
|
||||||
"electron-localshortcut": "^3.2.1",
|
"electron-localshortcut": "^3.2.1",
|
||||||
"electron-updater": "^4.2.2",
|
"electron-updater": "^4.2.2",
|
||||||
"emoji-mart": "^5.2.2",
|
"emoji-mart": "^5.2.2",
|
||||||
|
@ -102,7 +100,7 @@
|
||||||
"glob": "7.1.2",
|
"glob": "7.1.2",
|
||||||
"image-type": "^4.1.0",
|
"image-type": "^4.1.0",
|
||||||
"ip2country": "1.0.1",
|
"ip2country": "1.0.1",
|
||||||
"libsession_util_nodejs": "https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.2.2/libsession_util_nodejs-v0.2.2.tar.gz",
|
"libsession_util_nodejs": "https://github.com/oxen-io/libsession-util-nodejs/releases/download/v0.2.5/libsession_util_nodejs-v0.2.5.tar.gz",
|
||||||
"libsodium-wrappers-sumo": "^0.7.9",
|
"libsodium-wrappers-sumo": "^0.7.9",
|
||||||
"linkify-it": "^4.0.1",
|
"linkify-it": "^4.0.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
@ -142,9 +140,9 @@
|
||||||
"uuid": "8.3.2"
|
"uuid": "8.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@electron/notarize": "^2.1.0",
|
||||||
"@playwright/test": "1.16.3",
|
"@playwright/test": "1.16.3",
|
||||||
"@types/backbone": "1.4.2",
|
"@types/backbone": "1.4.2",
|
||||||
"@types/better-sqlite3": "7.4.0",
|
|
||||||
"@types/blueimp-load-image": "5.14.4",
|
"@types/blueimp-load-image": "5.14.4",
|
||||||
"@types/buffer-crc32": "^0.2.0",
|
"@types/buffer-crc32": "^0.2.0",
|
||||||
"@types/bunyan": "^1.8.8",
|
"@types/bunyan": "^1.8.8",
|
||||||
|
@ -190,15 +188,14 @@
|
||||||
"cross-env": "^6.0.3",
|
"cross-env": "^6.0.3",
|
||||||
"css-loader": "^6.7.2",
|
"css-loader": "^6.7.2",
|
||||||
"dmg-builder": "23.6.0",
|
"dmg-builder": "23.6.0",
|
||||||
"electron": "^17.2.0",
|
"electron": "25.3.0",
|
||||||
"electron-builder": "22.8.0",
|
"electron-builder": "23.0.8",
|
||||||
"electron-notarize": "^0.2.0",
|
|
||||||
"esbuild": "^0.14.29",
|
"esbuild": "^0.14.29",
|
||||||
"eslint": "^8.15.0",
|
"eslint": "^8.15.0",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eslint-plugin-mocha": "^10.0.4",
|
"eslint-plugin-mocha": "^10.1.0",
|
||||||
"eslint-plugin-more": "^1.0.5",
|
"eslint-plugin-more": "^1.0.5",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"jsdom": "^19.0.0",
|
"jsdom": "^19.0.0",
|
||||||
|
@ -230,7 +227,7 @@
|
||||||
"webpack-cli": "^5.0.1"
|
"webpack-cli": "^5.0.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "16.13.0"
|
"node": "18.15.0"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "com.loki-project.messenger-desktop",
|
"appId": "com.loki-project.messenger-desktop",
|
||||||
|
@ -285,7 +282,7 @@
|
||||||
"icon": "build/icon-linux.icns"
|
"icon": "build/icon-linux.icns"
|
||||||
},
|
},
|
||||||
"asarUnpack": [
|
"asarUnpack": [
|
||||||
"node_modules/better-sqlite3/build/Release/better_sqlite3.node",
|
"node_modules/@signalapp/better-sqlite3/build/Release/better_sqlite3.node",
|
||||||
"node_modules/libsession_util_nodejs/build/Release/libsession_util_nodejs.node",
|
"node_modules/libsession_util_nodejs/build/Release/libsession_util_nodejs.node",
|
||||||
"ts/webworker/workers/node/libsession/*.node",
|
"ts/webworker/workers/node/libsession/*.node",
|
||||||
"ts/mains/main_node.js"
|
"ts/mains/main_node.js"
|
||||||
|
|
|
@ -193,7 +193,7 @@ function prepareURL(pathSegments: Array<string>, moreKeys?: { theme: any }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUrl(event: any, target: string) {
|
function handleUrl(event: any, target: string) {
|
||||||
event.preventDefault();
|
event?.preventDefault();
|
||||||
const { protocol } = url.parse(target);
|
const { protocol } = url.parse(target);
|
||||||
// tslint:disable-next-line: no-http-string
|
// tslint:disable-next-line: no-http-string
|
||||||
if (protocol === 'http:' || protocol === 'https:') {
|
if (protocol === 'http:' || protocol === 'https:') {
|
||||||
|
@ -203,7 +203,11 @@ function handleUrl(event: any, target: string) {
|
||||||
|
|
||||||
function captureClicks(window: BrowserWindow) {
|
function captureClicks(window: BrowserWindow) {
|
||||||
window.webContents.on('will-navigate', handleUrl);
|
window.webContents.on('will-navigate', handleUrl);
|
||||||
window.webContents.on('new-window', handleUrl);
|
|
||||||
|
window.webContents.setWindowOpenHandler(({ url: urlToOpen }) => {
|
||||||
|
handleUrl(undefined, urlToOpen);
|
||||||
|
return { action: 'deny' };
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultWindowSize() {
|
function getDefaultWindowSize() {
|
||||||
|
@ -909,9 +913,7 @@ app.on('web-contents-created', (_createEvent, contents) => {
|
||||||
contents.on('will-attach-webview', attachEvent => {
|
contents.on('will-attach-webview', attachEvent => {
|
||||||
attachEvent.preventDefault();
|
attachEvent.preventDefault();
|
||||||
});
|
});
|
||||||
contents.on('new-window', newEvent => {
|
contents.setWindowOpenHandler(() => ({ action: 'deny' }));
|
||||||
newEvent.preventDefault();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ingested in preload.js via a sendSync call
|
// Ingested in preload.js via a sendSync call
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import electronIsDev from 'electron-is-dev';
|
import { app } from 'electron';
|
||||||
// tslint:disable: no-console
|
// tslint:disable: no-console
|
||||||
|
|
||||||
let environment;
|
let environment;
|
||||||
|
const isPackaged = app.isPackaged;
|
||||||
|
|
||||||
// In production mode, NODE_ENV cannot be customized by the user
|
// In production mode, NODE_ENV cannot be customized by the user
|
||||||
if (electronIsDev) {
|
if (isPackaged) {
|
||||||
environment = process.env.NODE_ENV || 'development';
|
|
||||||
} else {
|
|
||||||
environment = 'production';
|
environment = 'production';
|
||||||
|
// We could be running against production but still be in dev mode, we need to handle that
|
||||||
|
process.env.NODE_APP_INSTANCE = '';
|
||||||
|
} else {
|
||||||
|
environment = process.env.NODE_ENV || 'development';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set environment vars to configure node-config before requiring it
|
// Set environment vars to configure node-config before requiring it
|
||||||
|
@ -19,15 +22,10 @@ process.env.NODE_CONFIG_DIR = path.join(__dirname, '..', '..', 'config');
|
||||||
if (environment === 'production') {
|
if (environment === 'production') {
|
||||||
// harden production config against the local env
|
// harden production config against the local env
|
||||||
process.env.NODE_CONFIG = '';
|
process.env.NODE_CONFIG = '';
|
||||||
process.env.NODE_CONFIG_STRICT_MODE = `${!electronIsDev}`;
|
process.env.NODE_CONFIG_STRICT_MODE = `${isPackaged ? 1 : 0}`; // we want to force strict mode when we are packaged
|
||||||
process.env.HOSTNAME = '';
|
process.env.HOSTNAME = '';
|
||||||
process.env.ALLOW_CONFIG_MUTATIONS = '';
|
process.env.ALLOW_CONFIG_MUTATIONS = '';
|
||||||
process.env.SUPPRESS_NO_CONFIG_WARNING = '';
|
process.env.SUPPRESS_NO_CONFIG_WARNING = '';
|
||||||
|
|
||||||
// We could be running against production but still be in dev mode, we need to handle that
|
|
||||||
if (!electronIsDev) {
|
|
||||||
process.env.NODE_APP_INSTANCE = '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We load config after we've made our modifications to NODE_ENV
|
// We load config after we've made our modifications to NODE_ENV
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
CONVERSATION_PRIORITIES,
|
CONVERSATION_PRIORITIES,
|
||||||
} from '../models/conversationAttributes';
|
} from '../models/conversationAttributes';
|
||||||
|
|
||||||
import * as BetterSqlite3 from 'better-sqlite3';
|
import * as BetterSqlite3 from '@signalapp/better-sqlite3';
|
||||||
|
|
||||||
export const CONVERSATIONS_TABLE = 'conversations';
|
export const CONVERSATIONS_TABLE = 'conversations';
|
||||||
export const MESSAGES_TABLE = 'messages';
|
export const MESSAGES_TABLE = 'messages';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import * as BetterSqlite3 from 'better-sqlite3';
|
import * as BetterSqlite3 from '@signalapp/better-sqlite3';
|
||||||
import {
|
import {
|
||||||
ContactsConfigWrapperNode,
|
ContactsConfigWrapperNode,
|
||||||
ConvoInfoVolatileWrapperNode,
|
ConvoInfoVolatileWrapperNode,
|
||||||
|
@ -497,8 +497,8 @@ function updateToSessionSchemaVersion15(currentVersion: number, db: BetterSqlite
|
||||||
db.transaction(() => {
|
db.transaction(() => {
|
||||||
db.exec(`
|
db.exec(`
|
||||||
DROP TABLE pairingAuthorisations;
|
DROP TABLE pairingAuthorisations;
|
||||||
DROP TRIGGER messages_on_delete;
|
DROP TRIGGER IF EXISTS messages_on_delete;
|
||||||
DROP TRIGGER messages_on_update;
|
DROP TRIGGER IF EXISTS messages_on_update;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
writeSessionSchemaVersion(targetVersion, db);
|
writeSessionSchemaVersion(targetVersion, db);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import * as BetterSqlite3 from 'better-sqlite3';
|
import * as BetterSqlite3 from '@signalapp/better-sqlite3';
|
||||||
import { isNumber } from 'lodash';
|
import { isNumber } from 'lodash';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ const openDbOptions = {
|
||||||
nativeBinding: path.join(
|
nativeBinding: path.join(
|
||||||
getAppRootPath(),
|
getAppRootPath(),
|
||||||
'node_modules',
|
'node_modules',
|
||||||
|
'@signalapp',
|
||||||
'better-sqlite3',
|
'better-sqlite3',
|
||||||
'build',
|
'build',
|
||||||
'Release',
|
'Release',
|
||||||
|
@ -343,7 +344,7 @@ function updateToSchemaVersion7(currentVersion: number, db: BetterSqlite3.Databa
|
||||||
number
|
number
|
||||||
) WHERE number IS NOT NULL;
|
) WHERE number IS NOT NULL;
|
||||||
INSERT INTO sessions(id, number, json)
|
INSERT INTO sessions(id, number, json)
|
||||||
SELECT "+" || id, number, json FROM sessions_old;
|
SELECT id, number, json FROM sessions_old;
|
||||||
DROP TABLE sessions_old;
|
DROP TABLE sessions_old;
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import * as BetterSqlite3 from 'better-sqlite3';
|
import * as BetterSqlite3 from '@signalapp/better-sqlite3';
|
||||||
import { app, clipboard, dialog, Notification } from 'electron';
|
import { app, clipboard, dialog, Notification } from 'electron';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import * as BetterSqlite3 from 'better-sqlite3';
|
import * as BetterSqlite3 from '@signalapp/better-sqlite3';
|
||||||
|
|
||||||
let globalInstance: BetterSqlite3.Database | null = null;
|
let globalInstance: BetterSqlite3.Database | null = null;
|
||||||
|
|
||||||
|
|
|
@ -338,7 +338,7 @@ const handleMessagesResponseV4 = async (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
window?.log?.warn('handleNewMessages failed:', e);
|
window?.log?.warn('handleNewMessages failed:', e.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ export async function showDownloadUpdateDialog(
|
||||||
const DOWNLOAD_BUTTON = 0;
|
const DOWNLOAD_BUTTON = 0;
|
||||||
const LATER_BUTTON = 1;
|
const LATER_BUTTON = 1;
|
||||||
const options = {
|
const options = {
|
||||||
type: 'info',
|
type: 'info' as const,
|
||||||
buttons: [messages.autoUpdateDownloadButtonLabel, messages.autoUpdateLaterButtonLabel],
|
buttons: [messages.autoUpdateDownloadButtonLabel, messages.autoUpdateLaterButtonLabel],
|
||||||
title: messages.autoUpdateNewVersionTitle,
|
title: messages.autoUpdateNewVersionTitle,
|
||||||
message: messages.autoUpdateNewVersionMessage,
|
message: messages.autoUpdateNewVersionMessage,
|
||||||
|
@ -43,7 +43,7 @@ export async function showUpdateDialog(
|
||||||
const RESTART_BUTTON = 0;
|
const RESTART_BUTTON = 0;
|
||||||
const LATER_BUTTON = 1;
|
const LATER_BUTTON = 1;
|
||||||
const options = {
|
const options = {
|
||||||
type: 'info',
|
type: 'info' as const,
|
||||||
buttons: [messages.autoUpdateRestartButtonLabel, messages.autoUpdateLaterButtonLabel],
|
buttons: [messages.autoUpdateRestartButtonLabel, messages.autoUpdateLaterButtonLabel],
|
||||||
title: messages.autoUpdateNewVersionTitle,
|
title: messages.autoUpdateNewVersionTitle,
|
||||||
message: messages.autoUpdateDownloadedMessage,
|
message: messages.autoUpdateDownloadedMessage,
|
||||||
|
@ -58,7 +58,7 @@ export async function showUpdateDialog(
|
||||||
|
|
||||||
export async function showCannotUpdateDialog(mainWindow: BrowserWindow, messages: MessagesType) {
|
export async function showCannotUpdateDialog(mainWindow: BrowserWindow, messages: MessagesType) {
|
||||||
const options = {
|
const options = {
|
||||||
type: 'error',
|
type: 'error' as const,
|
||||||
buttons: [messages.ok],
|
buttons: [messages.ok],
|
||||||
title: messages.cannotUpdate,
|
title: messages.cannotUpdate,
|
||||||
message: messages.cannotUpdateDetail,
|
message: messages.cannotUpdateDetail,
|
||||||
|
|
Loading…
Reference in New Issue