diff --git a/apps/server-web/src/locales/i18n/bg/translation.json b/apps/server-web/src/locales/i18n/bg/translation.json index 95b7f55a2..1ca895f37 100644 --- a/apps/server-web/src/locales/i18n/bg/translation.json +++ b/apps/server-web/src/locales/i18n/bg/translation.json @@ -10,7 +10,9 @@ "APP_QUIT": "Откажете се", "GENERAL": "Общ", "SERVER_STATUS_STOPPED": "Статус: Спряна", - "SERVER_STATUS_STARTED": "Статус: започна" + "SERVER_STATUS_STARTED": "Статус: започна", + "OPEN_WEB": "Отворете уеб в браузъра", + "SERVER_WINDOW": "Прозорец на сървъра" }, "FORM": { "FIELDS": { @@ -22,7 +24,15 @@ }, "BUTTON": { "SAVE_SETTING": "Запазване на настройката", - "OK": "Добре" + "OK": "Добре", + "YES": "да", + "NO": "Не", + "DOWNLOAD_NOW": "Свали сега", + "LATER": "По късно", + "CANCEL": "Отказ", + "CLOSE": "Близо", + "START": "Започнете", + "STOP": "Спри се" }, "LABELS": { "CHECKING": "Проверка", @@ -42,11 +52,21 @@ "AUTO_UPDATE_SUBTITLE": "Активирайте автоматичната проверка на актуализацията, за да стартирате заявка за проверка дали е налична нова версия и да уведомите", "AUTO_UPDATE_TOGLE": "Автоматична актуализация", "CHECK_UPDATE_TITLE": "Проверете и актуализирайте версията на приложението си", - "CHECK_UPDATE_SUBTITLE": "Налична е нова актуализация! Моля, щракнете върху бутона Изтегляне сега по-долу." + "CHECK_UPDATE_SUBTITLE": "Налична е нова актуализация! Моля, щракнете върху бутона Изтегляне сега по-долу.", + "LANGUAGES": "Езици" } }, "MESSAGE": { "SUCCESS": "Успех", - "ERROR": "Грешка" + "ERROR": "Грешка", + "WARNING": "Warning", + "INFO": "Информация", + "UPDATE_AVAILABLE": "Налична е нова актуализация! Моля, щракнете върху бутона Изтегляне сега по-долу.", + "EXIT_MESSAGE": "Мрежата на сървъра все още работи, сигурни ли сте, че ще излезете от приложението?", + "UPDATE_SUCCESS": "Актуализирайте успешно" + }, + "LANGUAGES": { + "en": "Английски", + "bg": "България" } } diff --git a/apps/server-web/src/locales/i18n/en/translation.json b/apps/server-web/src/locales/i18n/en/translation.json index 2e9d94f58..91ba9f7d5 100644 --- a/apps/server-web/src/locales/i18n/en/translation.json +++ b/apps/server-web/src/locales/i18n/en/translation.json @@ -10,7 +10,9 @@ "APP_QUIT": "Quit", "GENERAL": "General", "SERVER_STATUS_STOPPED": "Status: Stopped", - "SERVER_STATUS_STARTED": "Status: Started" + "SERVER_STATUS_STARTED": "Status: Started", + "OPEN_WEB": "Open Web In Browser", + "SERVER_WINDOW": "Server Window" }, "FORM": { "FIELDS": { @@ -27,7 +29,10 @@ "NO": "No", "DOWNLOAD_NOW": "Download Now", "LATER": "Later", - "CANCEL": "Cancel" + "CANCEL": "Cancel", + "CLOSE": "Close", + "START": "Start", + "STOP": "Stop" }, "LABELS": { "CHECKING": "Checking", @@ -47,7 +52,8 @@ "AUTO_UPDATE_SUBTITLE": "Enable automatice update check, in order to run a request to check if new version is available and notify", "AUTO_UPDATE_TOGLE": "Automatic Update", "CHECK_UPDATE_TITLE": "Check & Update your app version", - "CHECK_UPDATE_SUBTITLE": "New Update is available! Please click button Download Now below." + "CHECK_UPDATE_SUBTITLE": "New Update is available! Please click button Download Now below.", + "LANGUAGES": "Languages" } }, "MESSAGE": { @@ -56,6 +62,11 @@ "WARNING": "Warning", "INFO": "Info", "UPDATE_AVAILABLE": "New Update is available! Please click button Download Now below.", - "EXIT_MESSAGE": "Server web still running, Are you sure to exit the app ?" + "EXIT_MESSAGE": "Server web still running, Are you sure to exit the app ?", + "UPDATE_SUCCESS": "Update Successfully" + }, + "LANGUAGES": { + "en": "English", + "bg": "Bulgaria" } } diff --git a/apps/server-web/src/main/helpers/constant.ts b/apps/server-web/src/main/helpers/constant.ts index cab7ffd1e..2885630d1 100644 --- a/apps/server-web/src/main/helpers/constant.ts +++ b/apps/server-web/src/main/helpers/constant.ts @@ -1,3 +1,4 @@ +import { Channels } from './interfaces' export const EventLists = { webServerStarted: 'WEB_SERVER_STARTED', webServerStopped: 'WEB_SERVER_STOPPED', @@ -11,7 +12,9 @@ export const EventLists = { UPDATE_PROGRESS: 'UPDATE_PROGRESS', UPDATE_DOWNLOADED: 'UPDATE_DOWNLOADED', UPDATE_CANCELLED: 'UPDATE_CANCELLED', - CHANGE_LANGUAGE: 'CHANGE_LANGUAGE' + CHANGE_LANGUAGE: 'CHANGE_LANGUAGE', + OPEN_WEB: 'OPEN_WEB', + SERVER_WINDOW: 'SERVER_WINDOW' } export const SettingPageTypeMessage = { @@ -32,3 +35,23 @@ export const SettingPageTypeMessage = { updateSettingResponse: 'update-setting-response', updateCancel: 'update-cancel' } + +export const ServerPageTypeMessage = { + SERVER_STATUS: 'server-status', + SERVER_EXEC: 'server-exec' +} + +export const LOG_TYPES = { + UPDATE_LOG: 'UPDATE-LOG', + SERVER_LOG: 'SERVER-LOG' +} + +export const IPC_TYPES: { + SETTING_PAGE: Channels, + UPDATER_PAGE: Channels, + SERVER_PAGE: Channels +} = { + SETTING_PAGE: 'setting-page', + UPDATER_PAGE: 'updater-page', + SERVER_PAGE: 'server-page' +} diff --git a/apps/server-web/src/main/helpers/desktop-server.ts b/apps/server-web/src/main/helpers/desktop-server.ts index 0788f3816..06507071c 100644 --- a/apps/server-web/src/main/helpers/desktop-server.ts +++ b/apps/server-web/src/main/helpers/desktop-server.ts @@ -3,6 +3,7 @@ import { DesktopServerFactory } from './services/desktop-server-factory'; import EventEmitter from 'events'; import { Observer } from './services/utils'; import NotificationDesktop from '../windows/desktop-notifier'; +import { LOG_TYPES } from './constant'; // Define server states export enum ServerState { STOPPED = 'stopped', @@ -34,7 +35,7 @@ export class DesktopServer { mainWindow?: BrowserWindow, signal?: AbortSignal, ): Promise { - console.log('DesktopServer -> start'); + console.log(LOG_TYPES.SERVER_LOG, 'DesktopServer -> start'); try { if (this.state !== ServerState.STOPPED) { diff --git a/apps/server-web/src/main/helpers/interfaces/i-constant.ts b/apps/server-web/src/main/helpers/interfaces/i-constant.ts new file mode 100644 index 000000000..64cdc0211 --- /dev/null +++ b/apps/server-web/src/main/helpers/interfaces/i-constant.ts @@ -0,0 +1 @@ +export type Channels = 'setting-page' | 'ipc-renderer' | 'language-set' | 'updater-page' | 'server-page'; diff --git a/apps/server-web/src/main/helpers/interfaces/i-setting.ts b/apps/server-web/src/main/helpers/interfaces/i-setting.ts new file mode 100644 index 000000000..e69de29bb diff --git a/apps/server-web/src/main/helpers/interfaces/index.ts b/apps/server-web/src/main/helpers/interfaces/index.ts index f7a793501..8f45b8de0 100644 --- a/apps/server-web/src/main/helpers/interfaces/index.ts +++ b/apps/server-web/src/main/helpers/interfaces/index.ts @@ -1,2 +1,3 @@ export * from './i-server'; export * from './i-desktop-dialog'; +export * from './i-constant'; diff --git a/apps/server-web/src/main/helpers/services/libs/server-task.ts b/apps/server-web/src/main/helpers/services/libs/server-task.ts index 370cdb746..be4eae744 100644 --- a/apps/server-web/src/main/helpers/services/libs/server-task.ts +++ b/apps/server-web/src/main/helpers/services/libs/server-task.ts @@ -2,7 +2,7 @@ import { ChildProcessFactory, Observer } from '../utils'; import { BrowserWindow } from 'electron'; import { ServerConfig } from './server-config'; import EventEmitter from 'events'; -import { EventLists } from '../../constant'; +import { EventLists, LOG_TYPES } from '../../constant'; // import { Timeout } from '../../decorators'; export abstract class ServerTask { @@ -72,7 +72,7 @@ export abstract class ServerTask { const service = ChildProcessFactory.createProcess(this.processPath, this.args, signal); - console.log('Service created', service.pid); + console.log(LOG_TYPES.SERVER_LOG, 'Service created', service.pid); service.stdout?.on('data', (data: any) => { const msg = data.toString(); @@ -93,12 +93,12 @@ export abstract class ServerTask { }); service.stderr?.on('data', (data: any) => { - console.log('stderr:', data.toString()); + console.log(LOG_TYPES.SERVER_LOG, 'stderr:', data.toString()); this.loggerObserver.notify(data.toString()); }); service.on('disconnect', () => { - console.log('Webserver disconnected'); + console.log(LOG_TYPES.SERVER_LOG, 'Webserver disconnected'); if (this.eventEmmitter) { this.eventEmmitter.emit(EventLists.webServerStopped); } diff --git a/apps/server-web/src/main/main.ts b/apps/server-web/src/main/main.ts index c3b1cadfc..ebefb4b77 100644 --- a/apps/server-web/src/main/main.ts +++ b/apps/server-web/src/main/main.ts @@ -4,13 +4,18 @@ import { DesktopServer } from './helpers/desktop-server'; import { LocalStore } from './helpers/services/libs/desktop-store'; import { EventEmitter } from 'events'; import { defaultTrayMenuItem, _initTray, updateTrayMenu } from './tray'; -import { EventLists, SettingPageTypeMessage } from './helpers/constant'; +import { EventLists, SettingPageTypeMessage, ServerPageTypeMessage, LOG_TYPES, IPC_TYPES } from './helpers/constant'; import { resolveHtmlPath } from './util'; import Updater from './updater'; import { mainBindings } from 'i18next-electron-fs-backend'; import i18nextMainBackend from '../configs/i18n.mainconfig'; import fs from 'fs'; import { WebServer } from './helpers/interfaces'; +import Log from 'electron-log'; +console.log = Log.log; +Object.assign(console, Log.functions); + + const eventEmitter = new EventEmitter(); @@ -26,6 +31,48 @@ let isServerRun: boolean; let intervalUpdate: NodeJS.Timeout; let tray: Tray; let settingWindow: BrowserWindow | null = null; +let logWindow: BrowserWindow | null = null; + +Log.hooks.push((message:any, transport) => { + if (transport !== Log.transports.file) { + return message; + } + + // if (message[0]) { + // message[0] = `LOGS - ${message[0]}` + // } + + message.data = message.data.map((i: any) => { + if (typeof i === 'object') { + return JSON.stringify(i) + } + return i; + }) + + if (message.data[0] === LOG_TYPES.SERVER_LOG) { + if (logWindow) { + const msg = message.data.join(' '); + logWindow.webContents.send(IPC_TYPES.SERVER_PAGE, { + type: LOG_TYPES.SERVER_LOG, + msg + }); + } + } + + if (message.data[0] === LOG_TYPES.UPDATE_LOG) { + if (settingWindow) { + const msg = `${message.data.join(' ')}`; + settingWindow.webContents.send(IPC_TYPES.UPDATER_PAGE, { + type: LOG_TYPES.UPDATE_LOG, + msg + }) + } + } + + + return message; +}) + const updater = new Updater(eventEmitter, i18nextMainBackend); i18nextMainBackend.on('initialized', () => { const config = LocalStore.getStore('config'); @@ -92,12 +139,12 @@ const installExtensions = async () => { }; -const createWindow = async () => { +const createWindow = async (type: 'SETTING_WINDOW' | 'LOG_WINDOW') => { if (isDebug) { await installExtensions(); } - settingWindow = new BrowserWindow({ + const defaultOptionWindow = { show: false, width: 1024, height: 728, @@ -109,15 +156,31 @@ const createWindow = async () => { ? path.join(__dirname, 'preload.js') : path.join(__dirname, '../../.erb/dll/preload.js'), }, - }); - const url = resolveHtmlPath('index.html', 'setting'); - settingWindow.loadURL(url); - - mainBindings(ipcMain, settingWindow, fs); - settingWindow.on('closed', () => { - settingWindow = null; - }); - + } + let url = ''; + switch (type) { + case 'SETTING_WINDOW': + settingWindow = new BrowserWindow(defaultOptionWindow); + url = resolveHtmlPath('index.html', 'setting'); + settingWindow.loadURL(url); + + mainBindings(ipcMain, settingWindow, fs); + settingWindow.on('closed', () => { + settingWindow = null; + }); + break; + case 'LOG_WINDOW': + logWindow = new BrowserWindow(defaultOptionWindow); + url = resolveHtmlPath('index.html', 'history-console') + logWindow.loadURL(url); + mainBindings(ipcMain, logWindow, fs); + logWindow.on('closed', () => { + logWindow = null; + }) + break; + default: + break; + } }; const runServer = async () => { @@ -182,7 +245,16 @@ const onInitApplication = () => { console.log(EventLists.webServerStarted) updateTrayMenu('SERVER_START', { enabled: false }, eventEmitter, tray, trayMenuItems, i18nextMainBackend); updateTrayMenu('SERVER_STOP', { enabled: true }, eventEmitter, tray, trayMenuItems, i18nextMainBackend); + updateTrayMenu('OPEN_WEB', { enabled: true}, eventEmitter, tray, trayMenuItems, i18nextMainBackend); updateTrayMenu('SERVER_STATUS', { label: 'MENU.SERVER_STATUS_STARTED' }, eventEmitter, tray, trayMenuItems, i18nextMainBackend); + if (logWindow) { + logWindow.webContents.send(IPC_TYPES.SERVER_PAGE, { + type: ServerPageTypeMessage.SERVER_STATUS, + data: { + isRun: true + } + }) + } isServerRun = true; }) @@ -190,13 +262,22 @@ const onInitApplication = () => { console.log(EventLists.webServerStopped); updateTrayMenu('SERVER_STOP', { enabled: false }, eventEmitter, tray, trayMenuItems, i18nextMainBackend); updateTrayMenu('SERVER_START', { enabled: true }, eventEmitter, tray, trayMenuItems, i18nextMainBackend); + updateTrayMenu('OPEN_WEB', { enabled: false}, eventEmitter, tray, trayMenuItems, i18nextMainBackend); updateTrayMenu('SERVER_STATUS', { label: 'MENU.SERVER_STATUS_STOPPED' }, eventEmitter, tray, trayMenuItems, i18nextMainBackend); + if (logWindow) { + logWindow.webContents.send(IPC_TYPES.SERVER_PAGE, { + type: ServerPageTypeMessage.SERVER_STATUS, + data: { + isRun: false + } + }) + } isServerRun = false; }) eventEmitter.on(EventLists.gotoSetting, async () => { if (!settingWindow) { - await createWindow() + await createWindow('SETTING_WINDOW'); } const serverSetting: WebServer = LocalStore.getStore('config'); console.log('setting data', serverSetting); @@ -210,32 +291,32 @@ const onInitApplication = () => { }) eventEmitter.on(EventLists.UPDATE_AVAILABLE, (data) => { - console.log('UPDATE_AVAILABLE', data); + console.log(LOG_TYPES.UPDATE_LOG, 'UPDATE_AVAILABLE', data); SendMessageToSettingWindow(SettingPageTypeMessage.updateAvailable, data); }) eventEmitter.on(EventLists.UPDATE_ERROR, (data) => { - console.log('UPDATE_ERROR', data); + console.log(LOG_TYPES.UPDATE_LOG, 'UPDATE_ERROR', data); SendMessageToSettingWindow(SettingPageTypeMessage.updateError, { message: JSON.stringify(data) }); }) eventEmitter.on(EventLists.UPDATE_NOT_AVAILABLE, (data) => { - console.log('UPDATE_NOT_AVAILABLE', data); + console.log(LOG_TYPES.UPDATE_LOG, 'UPDATE_NOT_AVAILABLE', data); SendMessageToSettingWindow(SettingPageTypeMessage.upToDate, data); }) eventEmitter.on(EventLists.UPDATE_PROGRESS, (data) => { - console.log('UPDATE_PROGRESS', data.percent); + console.log(LOG_TYPES.UPDATE_LOG, 'UPDATE_PROGRESS', data.percent); SendMessageToSettingWindow(SettingPageTypeMessage.downloadingUpdate, { percent: Math.floor(data.percent || 0) }); }) eventEmitter.on(EventLists.UPDATE_DOWNLOADED, (data) => { - console.log('UPDATE_DOWNLOADED', data); + console.log(LOG_TYPES.UPDATE_LOG, 'UPDATE_DOWNLOADED', data); SendMessageToSettingWindow(SettingPageTypeMessage.downloaded, data); }) eventEmitter.on(EventLists.UPDATE_CANCELLED, (data) => { - console.log('UPDATE_CANCELLED', data); + console.log(LOG_TYPES.UPDATE_LOG, 'UPDATE_CANCELLED', data); SendMessageToSettingWindow(SettingPageTypeMessage.updateCancel, data); }) @@ -250,7 +331,7 @@ const onInitApplication = () => { eventEmitter.on(EventLists.gotoAbout, async () => { if (!settingWindow) { - await createWindow(); + await createWindow('SETTING_WINDOW'); } const serverSetting = LocalStore.getStore('config'); settingWindow?.show(); @@ -262,6 +343,32 @@ const onInitApplication = () => { }, 100) }) }) + + eventEmitter.on(EventLists.SERVER_WINDOW, async () => { + if (!logWindow) { + await createWindow('LOG_WINDOW'); + } + const serverSetting = LocalStore.getStore('config'); + logWindow?.show(); + logWindow?.webContents.once('did-finish-load', () => { + setTimeout(() => { + logWindow?.webContents.send('languageSignal', serverSetting.general?.lang); + // SendMessageToSettingWindow(SettingPageTypeMessage.selectMenu, { key: 'about' }); + logWindow?.webContents.send(IPC_TYPES.SERVER_PAGE, { + type: ServerPageTypeMessage.SERVER_STATUS, + data: { + isRun: isServerRun + } + }) + }, 100) + }) + }) + + eventEmitter.on(EventLists.OPEN_WEB, () => { + const envConfig = getEnvApi(); + const url = `http://127.0.0.1:${envConfig?.PORT}` + shell.openExternal(url) + }) } (async () => { @@ -278,14 +385,14 @@ ipcMain.on('message', async (event, arg) => { event.reply('message', `${arg} World!`) }) -ipcMain.on('setting-page', (event, arg) => { +ipcMain.on(IPC_TYPES.SETTING_PAGE, (event, arg) => { console.log('main setting page', arg); switch (arg.type) { case SettingPageTypeMessage.saveSetting: LocalStore.updateConfigSetting({ server: arg.data }); - event.sender.send('setting-page', { type: SettingPageTypeMessage.mainResponse, data: true }); + event.sender.send(IPC_TYPES.SETTING_PAGE, { type: SettingPageTypeMessage.mainResponse, data: true }); break; case SettingPageTypeMessage.checkUpdate: updater.checkUpdate(); @@ -295,12 +402,19 @@ ipcMain.on('setting-page', (event, arg) => { break; case SettingPageTypeMessage.showVersion: const currentVersion = app.getVersion(); - event.sender.send('setting-page', { type: SettingPageTypeMessage.showVersion, data: currentVersion }) + event.sender.send(IPC_TYPES.SETTING_PAGE, { type: SettingPageTypeMessage.showVersion, data: currentVersion }) break; case SettingPageTypeMessage.langChange: event.sender.send('languageSignal', arg.data); eventEmitter.emit(EventLists.CHANGE_LANGUAGE, { code: arg.data }) break; + default: + break; + } +}) + +ipcMain.on(IPC_TYPES.UPDATER_PAGE, (event, arg) => { + switch (arg.type) { case SettingPageTypeMessage.updateSetting: LocalStore.updateConfigSetting({ general: { @@ -309,8 +423,24 @@ ipcMain.on('setting-page', (event, arg) => { } }) createIntervalAutoUpdate() - event.sender.send('setting-page', { type: SettingPageTypeMessage.updateSettingResponse, data: true }) + event.sender.send(IPC_TYPES.UPDATER_PAGE, { type: SettingPageTypeMessage.updateSettingResponse, data: true }) + break; + + default: break; + } +}) + +ipcMain.on(IPC_TYPES.SERVER_PAGE, (_, arg) => { + switch (arg.type) { + case ServerPageTypeMessage.SERVER_EXEC: + if (arg.data.isRun) { + eventEmitter.emit(EventLists.webServerStart) + } else { + eventEmitter.emit(EventLists.webServerStop) + } + break; + default: break; } diff --git a/apps/server-web/src/main/preload.ts b/apps/server-web/src/main/preload.ts index 7ab4c0903..a7989b0cb 100644 --- a/apps/server-web/src/main/preload.ts +++ b/apps/server-web/src/main/preload.ts @@ -1,8 +1,7 @@ // Disable no-unused-vars, broken for spread args /* eslint no-unused-vars: off */ -import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'; - -export type Channels = 'setting-page' | 'ipc-renderer' | 'language-set'; +import { contextBridge, IpcRenderer, ipcRenderer, IpcRendererEvent } from 'electron'; +import { Channels } from './helpers/interfaces'; const electronHandler = { ipcRenderer: { @@ -24,6 +23,9 @@ const electronHandler = { once(channel: Channels, func: (...args: unknown[]) => void) { ipcRenderer.once(channel, (_event, ...args) => func(...args)); }, + removeEventListener(channel: Channels) { + ipcRenderer.removeAllListeners(channel) + } }, }; diff --git a/apps/server-web/src/main/tray.ts b/apps/server-web/src/main/tray.ts index 41fadb44d..11596d69c 100644 --- a/apps/server-web/src/main/tray.ts +++ b/apps/server-web/src/main/tray.ts @@ -1,5 +1,4 @@ import { app, NativeImage, nativeImage, Menu, Tray } from 'electron'; -import path from 'path'; import { EventEmitter } from 'events'; import { EventLists } from './helpers/constant'; import i18n from 'i18next'; @@ -14,6 +13,14 @@ export const _initTray = (contextMenu:any, icon:string): Tray => { export const defaultTrayMenuItem = (eventEmitter: EventEmitter) => { const contextMenu = [ + { + id: 'OPEN_WEB', + label: 'MENU.OPEN_WEB', + // enabled: false, + click () { + eventEmitter.emit(EventLists.OPEN_WEB) + } + }, { id: 'SERVER_STATUS', label: 'MENU.SERVER_STATUS_STOPPED', @@ -33,6 +40,13 @@ export const defaultTrayMenuItem = (eventEmitter: EventEmitter) => { eventEmitter.emit(EventLists.webServerStop); } }, + { + id: 'SERVER_WINDOW', + label: 'MENU.SERVER_WINDOW', + click () { + eventEmitter.emit(EventLists.SERVER_WINDOW); + } + }, { id: 'APP_SETTING', label: 'MENU.APP_SETTING', diff --git a/apps/server-web/src/main/updater.ts b/apps/server-web/src/main/updater.ts index 77539d78b..37e437b8f 100644 --- a/apps/server-web/src/main/updater.ts +++ b/apps/server-web/src/main/updater.ts @@ -1,5 +1,4 @@ import { autoUpdater } from 'electron-updater'; -import log from 'electron-log'; import EventEmitter from 'events'; import { EventLists } from './helpers/constant'; import { InfoMessagesBox } from './windows/dialog'; @@ -7,8 +6,7 @@ import i18n from 'i18next'; class AppUpdater { constructor(eventEmitter: EventEmitter, i18nextMainBackend: typeof i18n) { - log.transports.file.level = 'info'; - autoUpdater.logger = log; + autoUpdater.logger = console; autoUpdater.on('update-available', (info) => { eventEmitter.emit(EventLists.UPDATE_AVAILABLE, info); if (!autoUpdater.autoDownload) { @@ -48,6 +46,8 @@ class AppUpdater { autoUpdater.on('update-cancelled', (info) => { eventEmitter.emit(EventLists.UPDATE_CANCELLED, info); }) + + // autoUpdater.on('') // autoUpdater.checkForUpdatesAndNotify(); } diff --git a/apps/server-web/src/renderer/App.tsx b/apps/server-web/src/renderer/App.tsx index 40c981536..1718ea52c 100644 --- a/apps/server-web/src/renderer/App.tsx +++ b/apps/server-web/src/renderer/App.tsx @@ -3,6 +3,7 @@ import { HashRouter as Router, Routes, Route } from 'react-router-dom'; import './App.css'; import { Setting } from './pages/Setting'; import i18next from 'i18next'; +import { ServerPage } from './pages/Server'; export default function App() { const [language, setLanguage] = useState('en'); @@ -16,6 +17,7 @@ export default function App() { } /> + } /> ); diff --git a/apps/server-web/src/renderer/components/About.tsx b/apps/server-web/src/renderer/components/About.tsx index be7030117..d95bb3f44 100644 --- a/apps/server-web/src/renderer/components/About.tsx +++ b/apps/server-web/src/renderer/components/About.tsx @@ -1,8 +1,7 @@ import { EverTeamsLogo } from './svgs'; -type Props = { - version: string; -}; -export const AboutComponent = (props: Props) => { +import { IAbout } from '../libs/interfaces'; + +export const AboutComponent = (props: IAbout) => { return (
diff --git a/apps/server-web/src/renderer/components/General.tsx b/apps/server-web/src/renderer/components/General.tsx index dc03bfe3b..a237ddc6e 100644 --- a/apps/server-web/src/renderer/components/General.tsx +++ b/apps/server-web/src/renderer/components/General.tsx @@ -1,15 +1,10 @@ import { Link } from 'react-router-dom'; -interface Languages { - code: string; - label: string; -} -type Props = { - langs: Languages[]; - onChange: (lang: any) => void; - lang: string; -}; -export function GeneralComponent(props: Props) { - const language = props.langs.find((lg) => lg.code === props.lang) || { +import { ILanguages, IGeneralSetting } from '../libs/interfaces'; + +export function GeneralComponent(props: IGeneralSetting) { + const language: ILanguages = props.langs.find( + (lg) => lg.code === props.lang, + ) || { code: 'en', label: 'English', }; diff --git a/apps/server-web/src/renderer/components/Popup.tsx b/apps/server-web/src/renderer/components/Popup.tsx index 0aead7aa0..f1d51c782 100644 --- a/apps/server-web/src/renderer/components/Popup.tsx +++ b/apps/server-web/src/renderer/components/Popup.tsx @@ -1,11 +1,7 @@ import { useTranslation } from 'react-i18next'; -type Props = { - isShowPopup: boolean; - modalAction: () => void; - type: 'success' | 'error' | 'none'; - message: string; -}; -export function Popup(props: Props) { +import { IPopupComponent } from '../libs/interfaces'; + +export function Popup(props: IPopupComponent) { const { t } = useTranslation(); return (
void; -}; +import { ISelectComponent } from '../libs/interfaces'; const SelectItem = forwardRef( ({ children, className, ...props }: any, forwardedRef) => { @@ -43,7 +32,7 @@ export const SelectComponent = ({ value, disabled, onValueChange, -}: Props) => { +}: ISelectComponent) => { const { t } = useTranslation(); return ( {items.map((item) => ( - {t(`FORM.LABELS.UPDATE_OPTIONS.${item.label}`)} + {t(`${item.label}`)} ))} diff --git a/apps/server-web/src/renderer/components/Server.tsx b/apps/server-web/src/renderer/components/Server.tsx index f72589144..1ec1d0b8e 100644 --- a/apps/server-web/src/renderer/components/Server.tsx +++ b/apps/server-web/src/renderer/components/Server.tsx @@ -1,24 +1,12 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { IServerSetting, IServerComponent } from '../libs/interfaces'; -interface IServerSetting { - PORT: number; - GAUZY_API_SERVER_URL: string; - NEXT_PUBLIC_GAUZY_API_SERVER_URL: string; -} - -type Props = { - serverSetting: IServerSetting; - saveSetting: (data: IServerSetting) => void; - Popup: JSX.Element; -}; - -export const ServerComponent = (props: Props) => { +export const ServerComponent = (props: IServerComponent) => { const { t } = useTranslation(); const [serverSetting, setServerSetting] = useState( props.serverSetting, ); - // useEffect(() => {}, []); const saveSetting = (e: any) => { e.preventDefault(); diff --git a/apps/server-web/src/renderer/components/SideBar.tsx b/apps/server-web/src/renderer/components/SideBar.tsx index ce543deef..09ee5b4df 100644 --- a/apps/server-web/src/renderer/components/SideBar.tsx +++ b/apps/server-web/src/renderer/components/SideBar.tsx @@ -1,24 +1,7 @@ import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -interface SideMenu { - displayName: string; - key: string; - isActive: boolean; -} - -interface Languages { - code: string; - label: string; -} - -type Props = { - children: string | JSX.Element | JSX.Element[]; - menus: SideMenu[]; - menuChange: (key: string) => void; - langs: Languages[]; - onLangChange: (lang: any) => void; - lang: string; -}; +import { ISidebarComponent } from '../libs/interfaces'; +import { SelectComponent } from './Select'; export function SideBar({ children, @@ -27,7 +10,7 @@ export function SideBar({ langs, lang, onLangChange, -}: Props) { +}: ISidebarComponent) { const { t } = useTranslation(); const language = langs.find((lg) => lg.code === lang) || { code: 'en', @@ -58,7 +41,20 @@ export function SideBar({
-
+ ({ + value: i.code, + label: `LANGUAGES.${i.code}`, + }))} + title={t('FORM.LABELS.LANGUAGES')} + defaultValue={language.code} + onValueChange={(lang) => { + onLangChange({ code: lang }); + }} + disabled={false} + value={language.code} + /> + {/*
-
+
*/}
{children}
diff --git a/apps/server-web/src/renderer/components/Toast.tsx b/apps/server-web/src/renderer/components/Toast.tsx index e63287440..11081c7b0 100644 --- a/apps/server-web/src/renderer/components/Toast.tsx +++ b/apps/server-web/src/renderer/components/Toast.tsx @@ -1,13 +1,7 @@ import * as React from 'react'; import * as Toast from '@radix-ui/react-toast'; -type Props = { - title: string; - message: string; - show: boolean; - autoClose: boolean; - timeout: number; - onClose: () => void; -}; +import { IToastComponent } from '../libs/interfaces'; +import { useTranslation } from 'react-i18next'; export const ToastComponent = ({ title, message, @@ -15,10 +9,10 @@ export const ToastComponent = ({ autoClose, timeout, onClose, -}: Props) => { +}: IToastComponent) => { const timerRef = React.useRef(0); + const { t } = useTranslation(); React.useEffect(() => { - // return () => clearTimeout(timerRef.current); if (autoClose) { clearTimeout(timerRef.current); timerRef.current = window.setTimeout(() => { @@ -35,10 +29,10 @@ export const ToastComponent = ({ duration={timeout} > - {title} + {t(title)} - {message} + {t(message)} - Close + {t('FORM.BUTTON.CLOSE')} diff --git a/apps/server-web/src/renderer/components/Updater.tsx b/apps/server-web/src/renderer/components/Updater.tsx index 5b6c2dd16..ada3401ff 100644 --- a/apps/server-web/src/renderer/components/Updater.tsx +++ b/apps/server-web/src/renderer/components/Updater.tsx @@ -4,37 +4,15 @@ import { SelectComponent } from './Select'; import { useEffect, useState } from 'react'; import { ToastComponent } from './Toast'; import { SettingPageTypeMessage } from '../../main/helpers/constant'; +import { DefaultRangeUpdateTimes } from '../libs/constant'; +import { IPC_TYPES, LOG_TYPES } from '../../main/helpers/constant'; +import { + IProgressComponent, + IRangeUpdates, + IUpdaterComponent, +} from '../libs/interfaces'; -interface UpdaterStates { - state: - | 'check-update' - | 'update-available' - | 'downloading' - | 'downloaded' - | 'error' - | 'not-started' - | 'up-to-date' - | 'cancel' - ; - data: any; - label: - | 'CHECKING' - | 'DOWNLOADING' - | 'QUIT_N_INSTALL' - | 'UP_TO_DATE' - | 'UPDATE_AVAILABLE' - | 'CHECK_FOR_UPDATE'; -} -type PropsProgress = { - updateStates: UpdaterStates; -}; - -type UpdateSetting = { - autoUpdate: boolean; - updateCheckPeriode: string; -}; - -const ProgressComponent = (props: PropsProgress) => { +const ProgressComponent = (props: IProgressComponent) => { const { t } = useTranslation(); return (
@@ -70,40 +48,11 @@ const ProgressComponent = (props: PropsProgress) => { ); }; -type Props = { - checkForUpdate: () => void; - loading: boolean; - updateStates: UpdaterStates; - Popup: JSX.Element; - data: UpdateSetting; - changeAutoUpdate: (data: UpdateSetting) => void; - saveSettingUpdate: (data: UpdateSetting) => void; -}; - -type RangeUpdates = { - value: string; - label: string; -}; -export const UpdaterComponent = (props: Props) => { +export const UpdaterComponent = (props: IUpdaterComponent) => { const { t } = useTranslation(); - const [rangeUpdate, setRangeUpdate] = useState([ - { - value: '30', - label: `30_MINUTES`, - }, - { - value: '60', - label: `A_HOURS`, - }, - { - value: '180', - label: `3_HOURS`, - }, - { - value: '1140', - label: `A_DAY`, - }, - ]); + const [rangeUpdate, _] = useState(DefaultRangeUpdateTimes); + + const [updateLogs, setUpdateLogs] = useState([]); const [toastShow, setToastShow] = useState(false); @@ -129,17 +78,22 @@ export const UpdaterComponent = (props: Props) => { }); }; - useEffect(() => { - window.electron.ipcRenderer.once('setting-page', (arg: any) => { - switch (arg.type) { - case SettingPageTypeMessage.updateSettingResponse: - setOpen(); - break; + const updaterEvent = (arg: any) => { + switch (arg.type) { + case SettingPageTypeMessage.updateSettingResponse: + setOpen(); + break; + case LOG_TYPES.UPDATE_LOG: + setUpdateLogs((prev) => [...prev, arg.msg]); + break; + default: + break; + } + }; - default: - break; - } - }); + useEffect(() => { + window.electron.ipcRenderer.removeEventListener(IPC_TYPES.UPDATER_PAGE); + window.electron.ipcRenderer.on(IPC_TYPES.UPDATER_PAGE, updaterEvent); }, []); return ( @@ -191,7 +145,10 @@ export const UpdaterComponent = (props: Props) => {
({ + ...i, + label: `FORM.LABELS.UPDATE_OPTIONS.${i.label}`, + }))} value={props.data.updateCheckPeriode} defaultValue={props.data.updateCheckPeriode} disabled={!props.data.autoUpdate} @@ -224,12 +181,53 @@ export const UpdaterComponent = (props: Props) => { )} {!props.loading && t(`FORM.LABELS.${props.updateStates.label}`)} +
+
+
+ + Update Logs + + + + + + +
+
+ {updateLogs.length > 0 && + updateLogs.map((ulog, i) => ( +
+ {ulog} +
+ ))} +
+
+
+
+
{props.Popup} void; +}; + +type IPopupComponent = { + isShowPopup: boolean; + modalAction: () => void; + type: 'success' | 'error' | 'none'; + message: string; +}; + +type IProgressComponent = { + updateStates: IUpdaterStates; +}; + +type IUpdaterComponent = { + checkForUpdate: () => void; + loading: boolean; + updateStates: IUpdaterStates; + Popup: JSX.Element; + data: IUpdateSetting; + changeAutoUpdate: (data: IUpdateSetting) => void; + saveSettingUpdate: (data: IUpdateSetting) => void; +}; + +type ISelectComponent = { + title: string; + items: ISelectItems[]; + defaultValue: string; + value: string; + disabled: boolean; + onValueChange: (val: string) => void; +}; + +type IServerComponent = { + serverSetting: IServerSetting; + saveSetting: (data: IServerSetting) => void; + Popup: JSX.Element; +}; + +type ISidebarComponent = { + children: string | JSX.Element | JSX.Element[]; + menus: ISideMenu[]; + menuChange: (key: string) => void; + langs: ILanguages[]; + onLangChange: (lang: any) => void; + lang: string; +}; + +export { + IToastComponent, + IProgressComponent, + IUpdaterComponent, + ISelectComponent, + IServerComponent, + ISidebarComponent, + IPopupComponent +} diff --git a/apps/server-web/src/renderer/libs/interfaces/i-setting.ts b/apps/server-web/src/renderer/libs/interfaces/i-setting.ts new file mode 100644 index 000000000..4b47dd5e5 --- /dev/null +++ b/apps/server-web/src/renderer/libs/interfaces/i-setting.ts @@ -0,0 +1,80 @@ +interface ISideMenu { + displayName: string; + key: string; + isActive: boolean; +} + +interface IUpdaterStates { + state: + | 'check-update' + | 'update-available' + | 'downloading' + | 'downloaded' + | 'error' + | 'not-started' + | 'up-to-date' + | 'cancel' + ; + data: any; + label: + | 'CHECKING' + | 'DOWNLOADING' + | 'QUIT_N_INSTALL' + | 'UP_TO_DATE' + | 'UPDATE_AVAILABLE' + | 'CHECK_FOR_UPDATE'; +} + +interface IServerSetting { + PORT: number; + GAUZY_API_SERVER_URL: string; + NEXT_PUBLIC_GAUZY_API_SERVER_URL: string; +} + +interface IPopup { + type: 'success' | 'error' | 'none'; + isShow: boolean; +} + +interface ILanguages { + code: string; + label: string; +} + +type IUpdateSetting = { + autoUpdate: boolean; + updateCheckPeriode: string; +}; + +type IAbout = { + version: string; +}; + +type IGeneralSetting = { + langs: ILanguages[]; + onChange: (lang: any) => void; + lang: string; +}; + +type ISelectItems = { + label: string; + value: string; +}; + +type IRangeUpdates = { + value: string; + label: string; +}; + +export { + ISideMenu, + IUpdaterStates, + IServerSetting, + IPopup, + ILanguages, + IUpdateSetting, + IAbout, + IGeneralSetting, + IRangeUpdates, + ISelectItems +} diff --git a/apps/server-web/src/renderer/libs/interfaces/index.ts b/apps/server-web/src/renderer/libs/interfaces/index.ts new file mode 100644 index 000000000..68a8d5aa7 --- /dev/null +++ b/apps/server-web/src/renderer/libs/interfaces/index.ts @@ -0,0 +1,2 @@ +export * from './i-setting'; +export * from './i-components'; diff --git a/apps/server-web/src/renderer/pages/Server.tsx b/apps/server-web/src/renderer/pages/Server.tsx new file mode 100644 index 000000000..ca5e83d43 --- /dev/null +++ b/apps/server-web/src/renderer/pages/Server.tsx @@ -0,0 +1,101 @@ +import { useState, useEffect } from 'react'; +import { ServerPageTypeMessage } from '../../main/helpers/constant'; +import { IPC_TYPES, LOG_TYPES } from '../../main/helpers/constant'; +import { EverTeamsLogo } from '../components/svgs'; +import { useTranslation } from 'react-i18next'; + +export function ServerPage() { + const [isRun, setIsRun] = useState(false); + const [logs, setLogs] = useState([]); + const [loading, setLoading] = useState(false); + const { t } = useTranslation(); + + useEffect(() => { + window.electron.ipcRenderer.removeEventListener(IPC_TYPES.SERVER_PAGE); + window.electron.ipcRenderer.on(IPC_TYPES.SERVER_PAGE, (arg: any) => { + switch (arg.type) { + case LOG_TYPES.SERVER_LOG: + setLogs((prev) => [...prev, arg.msg]); + break; + case ServerPageTypeMessage.SERVER_STATUS: + if (arg.data.isRun) { + setIsRun(true); + } else { + setIsRun(false); + } + setLoading(false); + break; + default: + break; + } + }); + }, []); + + const runServer = () => { + setLoading(true); + window.electron.ipcRenderer.sendMessage(IPC_TYPES.SERVER_PAGE, { + type: ServerPageTypeMessage.SERVER_EXEC, + data: { + isRun: !isRun, + }, + }); + }; + + return ( +
+
+
+ +
+
+ +
+
+
+ + Server Logs + + + + + + +
+
+ {logs.length > 0 && + logs.map((log, i) => ( +
+ {log} +
+ ))} +
+
+
+
+
+
+ ); +} diff --git a/apps/server-web/src/renderer/pages/Setting.tsx b/apps/server-web/src/renderer/pages/Setting.tsx index 14440074f..87ef415f1 100644 --- a/apps/server-web/src/renderer/pages/Setting.tsx +++ b/apps/server-web/src/renderer/pages/Setting.tsx @@ -8,57 +8,17 @@ import { AboutComponent, GeneralComponent, } from '../components'; - -interface SideMenu { - displayName: string; - key: string; - isActive: boolean; -} - -interface UpdaterStates { - state: - | 'check-update' - | 'update-available' - | 'downloading' - | 'downloaded' - | 'error' - | 'not-started' - | 'up-to-date' - | 'cancel' - ; - data: any; - label: - | 'CHECKING' - | 'DOWNLOADING' - | 'QUIT_N_INSTALL' - | 'UP_TO_DATE' - | 'UPDATE_AVAILABLE' - | 'CHECK_FOR_UPDATE'; -} - -interface IServerSetting { - PORT: number; - GAUZY_API_SERVER_URL: string; - NEXT_PUBLIC_GAUZY_API_SERVER_URL: string; -} - -interface IPopup { - type: 'success' | 'error' | 'none'; - isShow: boolean; -} - -interface Languages { - code: string; - label: string; -} - -type UpdateSetting = { - autoUpdate: boolean; - updateCheckPeriode: string; -}; +import { + IUpdaterStates, + IUpdateSetting, + IServerSetting, + IPopup, + ILanguages, + ISideMenu, +} from '../libs/interfaces'; export function Setting() { - const [menus, setMenu] = useState([ + const [menus, setMenu] = useState([ { displayName: 'UPDATER', key: 'updater', @@ -76,12 +36,12 @@ export function Setting() { }, ]); - const [updateSetting, setUpdateSetting] = useState({ + const [updateSetting, setUpdateSetting] = useState({ autoUpdate: false, updateCheckPeriode: '180', }); - const [langs, setLangs] = useState([ + const [langs, setLangs] = useState([ { code: 'en', label: 'English', @@ -94,7 +54,7 @@ export function Setting() { const [lng, setLng] = useState('en'); - const [updateStates, setUpdateState] = useState({ + const [updateStates, setUpdateState] = useState({ state: 'not-started', data: null, label: 'CHECK_FOR_UPDATE', @@ -127,12 +87,12 @@ export function Setting() { setMenu(newMenu); }; - const changeLanguage = (lang: Languages) => { + const changeLanguage = (lang: ILanguages) => { sendingMessageToMain(lang.code, SettingPageTypeMessage.langChange); setLng(lang.code); }; - const saveSettingUpdate = (data: UpdateSetting) => { + const saveSettingUpdate = (data: IUpdateSetting) => { sendingMessageToMain(data, SettingPageTypeMessage.updateSetting); }; @@ -143,7 +103,7 @@ export function Setting() { }); }; - const updateDataSettingUpdate = (data: UpdateSetting) => { + const updateDataSettingUpdate = (data: IUpdateSetting) => { setUpdateSetting(data); }; diff --git a/apps/web/app/constants.ts b/apps/web/app/constants.ts index e9ba40c66..cb2e49e5f 100644 --- a/apps/web/app/constants.ts +++ b/apps/web/app/constants.ts @@ -36,7 +36,6 @@ export const RECAPTCHA_SITE_KEY = getNextPublicEnv( process.env.NEXT_PUBLIC_CAPTCHA_SITE_KEY ); export const RECAPTCHA_SECRET_KEY = process.env.CAPTCHA_SECRET_KEY; - const basePath = process.env.GAUZY_API_SERVER_URL ? process.env.GAUZY_API_SERVER_URL : 'https://api.ever.team'; export const GAUZY_API_SERVER_URL = basePath + '/api';