From d4101a48b3eee8b1fb177831aa02a4b4fbec2588 Mon Sep 17 00:00:00 2001 From: Markus Hatvan Date: Sat, 18 Sep 2021 11:15:25 +0200 Subject: chore: convert various files from JS to TS (#1959) --- src/assets/themeInfo.json | 1 - src/electron/ipc-api/localServer.ts | 4 +- src/electron/macOSPermissions.ts | 2 +- src/environment.js | 190 -------------------- src/environment.ts | 205 ++++++++++++++++++++++ src/features/appearance/index.js | 259 ---------------------------- src/features/appearance/index.ts | 250 +++++++++++++++++++++++++++ src/features/basicAuth/Form.js | 17 -- src/features/basicAuth/Form.ts | 17 ++ src/features/basicAuth/mainIpcHandler.js | 9 - src/features/basicAuth/mainIpcHandler.ts | 11 ++ src/features/basicAuth/store.js | 30 ---- src/features/basicAuth/store.ts | 30 ++++ src/features/basicAuth/styles.js | 12 -- src/features/basicAuth/styles.ts | 12 ++ src/features/communityRecipes/index.js | 7 - src/features/communityRecipes/index.ts | 7 + src/features/utils/ActionBinding.js | 29 ---- src/features/utils/ActionBinding.ts | 29 ++++ src/features/workspaces/actions.js | 27 --- src/features/workspaces/actions.ts | 30 ++++ src/features/workspaces/api.js | 66 ------- src/features/workspaces/api.ts | 86 +++++++++ src/features/workspaces/constants.js | 4 - src/features/workspaces/constants.ts | 4 + src/features/workspaces/index.js | 30 ---- src/features/workspaces/index.ts | 28 +++ src/features/workspaces/models/Workspace.js | 37 ---- src/features/workspaces/models/Workspace.ts | 39 +++++ src/i18n/apply-branding.js | 66 ------- src/i18n/apply-branding.ts | 66 +++++++ src/i18n/globalMessages.js | 77 --------- src/i18n/globalMessages.ts | 77 +++++++++ src/i18n/languages.js | 123 ------------- src/i18n/languages.ts | 123 +++++++++++++ src/i18n/translations.js | 15 -- src/i18n/translations.ts | 15 ++ src/internal-server/start.js | 51 ------ src/internal-server/start.ts | 51 ++++++ src/internal-server/test.js | 9 - src/internal-server/test.ts | 9 + 41 files changed, 1092 insertions(+), 1062 deletions(-) delete mode 100644 src/assets/themeInfo.json delete mode 100644 src/environment.js create mode 100644 src/environment.ts delete mode 100644 src/features/appearance/index.js create mode 100644 src/features/appearance/index.ts delete mode 100644 src/features/basicAuth/Form.js create mode 100644 src/features/basicAuth/Form.ts delete mode 100644 src/features/basicAuth/mainIpcHandler.js create mode 100644 src/features/basicAuth/mainIpcHandler.ts delete mode 100644 src/features/basicAuth/store.js create mode 100644 src/features/basicAuth/store.ts delete mode 100644 src/features/basicAuth/styles.js create mode 100644 src/features/basicAuth/styles.ts delete mode 100644 src/features/communityRecipes/index.js create mode 100644 src/features/communityRecipes/index.ts delete mode 100644 src/features/utils/ActionBinding.js create mode 100644 src/features/utils/ActionBinding.ts delete mode 100644 src/features/workspaces/actions.js create mode 100644 src/features/workspaces/actions.ts delete mode 100644 src/features/workspaces/api.js create mode 100644 src/features/workspaces/api.ts delete mode 100644 src/features/workspaces/constants.js create mode 100644 src/features/workspaces/constants.ts delete mode 100644 src/features/workspaces/index.js create mode 100644 src/features/workspaces/index.ts delete mode 100644 src/features/workspaces/models/Workspace.js create mode 100644 src/features/workspaces/models/Workspace.ts delete mode 100644 src/i18n/apply-branding.js create mode 100644 src/i18n/apply-branding.ts delete mode 100644 src/i18n/globalMessages.js create mode 100644 src/i18n/globalMessages.ts delete mode 100644 src/i18n/languages.js create mode 100644 src/i18n/languages.ts delete mode 100644 src/i18n/translations.js create mode 100644 src/i18n/translations.ts delete mode 100644 src/internal-server/start.js create mode 100644 src/internal-server/start.ts delete mode 100644 src/internal-server/test.js create mode 100644 src/internal-server/test.ts (limited to 'src') diff --git a/src/assets/themeInfo.json b/src/assets/themeInfo.json deleted file mode 100644 index 54e833789..000000000 --- a/src/assets/themeInfo.json +++ /dev/null @@ -1 +0,0 @@ -{"color":".theme__dark .app .sidebar .sidebar__button.is-muted, .theme__dark .app .sidebar .sidebar__button.is-active, .sidebar .sidebar__button.is-muted, .sidebar .sidebar__button.is-active, .tab-item.is-active, .settings .account .invoices .invoices__action button, .settings-navigation .settings-navigation__link.is-active .badge, a.link, button.link, .auth .welcome .button:hover, .auth .welcome .button__inverted, .franz-form .franz-form__radio.is-selected, .theme__dark .franz-form__button.franz-form__button--inverted, .franz-form__button.franz-form__button--inverted","border-color":".theme__dark .settings, .franz-form .franz-form__radio.is-selected","background":".settings .settings__header, .settings .settings__close, .settings-navigation .settings-navigation__link.is-active, a.button, button.button, .auth, .info-bar, .info-bar.info-bar--primary, .infobox.infobox--primary, .theme__dark .badge.badge--primary, .theme__dark, .badge.badge--primary, .content-tabs .content-tabs__tabs .content-tabs__item.is-active, #electron-app-title-bar .toolbar-dropdown:not(.open) > .toolbar-button > button:hover, #electron-app-title-bar .list-item.selected .menu-item, #electron-app-title-bar .list-item.selected:focus .menu-item, .theme__dark .quick-switch .active, .franz-form .franz-form__toggle-wrapper .franz-form__toggle.is-active .franz-form__toggle-button, .theme__dark .franz-form__button, .franz-form__button, .ferdi__fab, .franz-form .franz-form__slider-wrapper .slider::-webkit-slider-thumb","border-right-color":".settings .settings__header .separator"} diff --git a/src/electron/ipc-api/localServer.ts b/src/electron/ipc-api/localServer.ts index d318b93a5..61e56c777 100644 --- a/src/electron/ipc-api/localServer.ts +++ b/src/electron/ipc-api/localServer.ts @@ -2,7 +2,7 @@ import { ipcMain, BrowserWindow } from 'electron'; import net from 'net'; import { LOCAL_HOSTNAME, LOCAL_PORT } from '../../config'; import { userDataPath } from '../../environment'; -import startServer from '../../internal-server/start'; +import { server } from '../../internal-server/start'; const portInUse = (port: number): Promise => new Promise(resolve => { @@ -35,7 +35,7 @@ export default (params: { mainWindow: BrowserWindow }) => { } console.log('Starting local server on port', port); - startServer(userDataPath(), port); + server(userDataPath(), port); params.mainWindow.webContents.send('localServerPort', { port, diff --git a/src/electron/macOSPermissions.ts b/src/electron/macOSPermissions.ts index f5a8c7cc4..aef3ac30b 100644 --- a/src/electron/macOSPermissions.ts +++ b/src/electron/macOSPermissions.ts @@ -15,7 +15,7 @@ debug( const filePath = userDataPath('.has-app-requested-screen-capture-permissions'); -function hasPromptedForScreenCapturePermission(): boolean { +function hasPromptedForScreenCapturePermission(): string | boolean { if (!isExplicitScreenCapturePermissionReqd) { return false; } diff --git a/src/environment.js b/src/environment.js deleted file mode 100644 index b315466fc..000000000 --- a/src/environment.js +++ /dev/null @@ -1,190 +0,0 @@ -import os from 'os'; -import { join } from 'path'; - -import { is, api as electronApi } from 'electron-util'; - -import { DEFAULT_ACCENT_COLOR } from '@meetfranz/theme'; - -import osName from 'os-name'; -import { - LIVE_FERDI_API, - DEV_FRANZ_API, - LOCAL_API, - LOCAL_API_WEBSITE, - DEV_API_FRANZ_WEBSITE, - LIVE_API_FERDI_WEBSITE, - LIVE_WS_API, - LOCAL_WS_API, - DEV_WS_API, - LOCAL_TODOS_FRONTEND_URL, - PRODUCTION_TODOS_FRONTEND_URL, - DEFAULT_TODO_SERVICE, - SEARCH_ENGINE_DDG, - iconSizeBias, -} from './config'; - -import { asarPath } from './helpers/asar-helpers'; -import * as buildInfo from './buildInfo.json'; // eslint-disable-line import/no-unresolved - -export const { app } = electronApi; -export const ferdiVersion = app.getVersion(); -export const electronVersion = process.versions.electron; -export const chromeVersion = process.versions.chrome; -export const nodeVersion = process.versions.node; -export const ferdiLocale = app.getLocale(); - -// Set app directory before loading user modules -if (process.env.FERDI_APPDATA_DIR != null) { - app.setPath('appData', process.env.FERDI_APPDATA_DIR); - app.setPath('userData', join(app.getPath('appData'))); -} else if (process.env.PORTABLE_EXECUTABLE_DIR != null) { - app.setPath('appData', process.env.PORTABLE_EXECUTABLE_DIR, `${app.name}AppData`); - app.setPath('userData', join(app.getPath('appData'), `${app.name}AppData`)); -} else if (is.windows) { - app.setPath('appData', process.env.APPDATA); - app.setPath('userData', join(app.getPath('appData'), app.name)); -} - -export const isDevMode = is.development; -if (isDevMode) { - app.setPath('userData', join(app.getPath('appData'), `${app.name}Dev`)); -} - -export function userDataPath(...segments) { - return join(app.getPath('userData'), ...([segments].flat())); -} - -export function userDataRecipesPath(...segments) { - return userDataPath('recipes', ...([segments].flat())); -} - -// Replacing app.asar is not beautiful but unfortunately necessary -export function asarRecipesPath(...segments) { - return join(asarPath(join(__dirname, 'recipes')), ...([segments].flat())); -} - -export const useLiveAPI = process.env.USE_LIVE_API; -const useLocalAPI = process.env.USE_LOCAL_API; - -export const isMac = is.macos; -export const isWindows = is.windows; -export const isLinux = is.linux; -export const osPlatform = os.platform(); -export const osArch = os.arch(); -export const osRelease = os.release(); -export const is64Bit = osArch.match(/64/); - -// for accelerator, show the shortform that electron/OS understands -// for tooltip, show symbol -const ctrlKey = isMac ? '⌘' : 'Ctrl'; -const cmdKey = isMac ? 'Cmd' : 'Ctrl'; - -export const altKey = (isAccelerator = true) => (!isAccelerator && isMac ? '⌥' : 'Alt'); -export const shiftKey = (isAccelerator = true) => (!isAccelerator && isMac ? '⇧' : 'Shift'); - -// Platform specific shortcut keys -export const cmdOrCtrlShortcutKey = (isAccelerator = true) => (isAccelerator ? cmdKey : ctrlKey); -export const lockFerdiShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+${shiftKey(isAccelerator)}+L`; -export const todosToggleShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+T`; -export const workspaceToggleShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+D`; -export const muteFerdiShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+${shiftKey(isAccelerator)}+M`; -export const addNewServiceShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+N`; -export const settingsShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+${isMac ? ',' : 'P'}`; - -let api; -let wsApi; -let web; -let todos; -if (!isDevMode || (isDevMode && useLiveAPI)) { - api = LIVE_FERDI_API; - wsApi = LIVE_WS_API; - web = LIVE_API_FERDI_WEBSITE; - todos = PRODUCTION_TODOS_FRONTEND_URL; -} else if (isDevMode && useLocalAPI) { - api = LOCAL_API; - wsApi = LOCAL_WS_API; - web = LOCAL_API_WEBSITE; - todos = LOCAL_TODOS_FRONTEND_URL; -} else { - api = DEV_FRANZ_API; - wsApi = DEV_WS_API; - web = DEV_API_FRANZ_WEBSITE; - todos = PRODUCTION_TODOS_FRONTEND_URL; -} - -export const API = api; -export const API_VERSION = 'v1'; -export const WS_API = wsApi; -export const WEBSITE = web; -export const TODOS_FRONTEND = todos; - -export const DEFAULT_APP_SETTINGS = { - autoLaunchInBackground: false, - runInBackground: true, - reloadAfterResume: true, - enableSystemTray: true, - startMinimized: false, - confirmOnQuit: false, - minimizeToSystemTray: false, - closeToSystemTray: false, - privateNotifications: false, - clipboardNotifications: true, - notifyTaskBarOnMessage: false, - showDisabledServices: true, - showMessageBadgeWhenMuted: true, - showDragArea: false, - enableSpellchecking: true, - spellcheckerLanguage: 'en-us', - darkMode: isMac && electronApi.nativeTheme.shouldUseDarkColors, - splitMode: false, - locale: '', - fallbackLocale: 'en-US', - beta: false, - isAppMuted: false, - enableGPUAcceleration: true, - - // Ferdi specific options - server: LIVE_FERDI_API, - predefinedTodoServer: DEFAULT_TODO_SERVICE, - autohideMenuBar: false, - lockingFeatureEnabled: false, - locked: false, - lockedPassword: '', - useTouchIdToUnlock: true, - scheduledDNDEnabled: false, - scheduledDNDStart: '17:00', - scheduledDNDEnd: '09:00', - hibernateOnStartup: true, - hibernationStrategy: '300', // seconds - wakeUpStrategy: '300', // seconds - inactivityLock: 0, - automaticUpdates: true, - showServiceNavigationBar: false, - universalDarkMode: true, - userAgentPref: '', - adaptableDarkMode: true, - accentColor: DEFAULT_ACCENT_COLOR, - serviceRibbonWidth: 68, - iconSize: iconSizeBias, - sentry: false, - nightly: false, - navigationBarBehaviour: 'custom', - searchEngine: SEARCH_ENGINE_DDG, - useVerticalStyle: false, - alwaysShowWorkspaces: false, - liftSingleInstanceLock: false, -}; - -export function aboutAppDetails() { - return [ - `Version: ${ferdiVersion}`, - `Electron: ${electronVersion}`, - `Chrome: ${chromeVersion}`, - `Node.js: ${nodeVersion}`, - `Platform: ${osName()}`, - `Arch: ${process.arch}`, - `Build date: ${new Date(Number(buildInfo.timestamp))}`, - `Git SHA: ${buildInfo.gitHashShort}`, - `Git branch: ${buildInfo.gitBranch}`, - ].join('\n'); -} diff --git a/src/environment.ts b/src/environment.ts new file mode 100644 index 000000000..ca1380199 --- /dev/null +++ b/src/environment.ts @@ -0,0 +1,205 @@ +import os from 'os'; +import { join } from 'path'; + +import { is, api as electronApi } from 'electron-util'; + +import { DEFAULT_ACCENT_COLOR } from '@meetfranz/theme'; + +import osName from 'os-name'; +import { + LIVE_FERDI_API, + DEV_FRANZ_API, + LOCAL_API, + LOCAL_API_WEBSITE, + DEV_API_FRANZ_WEBSITE, + LIVE_API_FERDI_WEBSITE, + LIVE_WS_API, + LOCAL_WS_API, + DEV_WS_API, + LOCAL_TODOS_FRONTEND_URL, + PRODUCTION_TODOS_FRONTEND_URL, + DEFAULT_TODO_SERVICE, + SEARCH_ENGINE_DDG, + iconSizeBias, +} from './config'; + +import { asarPath } from './helpers/asar-helpers'; + +// @ts-expect-error Cannot find module './buildInfo.json' or its corresponding type declarations. +import * as buildInfo from './buildInfo.json'; + +export const { app } = electronApi; +export const ferdiVersion = app.getVersion(); +export const electronVersion = process.versions.electron; +export const chromeVersion = process.versions.chrome; +export const nodeVersion = process.versions.node; +export const ferdiLocale = app.getLocale(); + +// Set app directory before loading user modules +if (process.env.FERDI_APPDATA_DIR != null) { + app.setPath('appData', process.env.FERDI_APPDATA_DIR); + app.setPath('userData', join(app.getPath('appData'))); +} else if (process.env.PORTABLE_EXECUTABLE_DIR != null) { + app.setPath( + 'appData', + process.env.PORTABLE_EXECUTABLE_DIR, + `${app.name}AppData`, + ); + app.setPath('userData', join(app.getPath('appData'), `${app.name}AppData`)); +} else if (is.windows) { + app.setPath('appData', process.env.APPDATA); + app.setPath('userData', join(app.getPath('appData'), app.name)); +} + +export const isDevMode = is.development; +if (isDevMode) { + app.setPath('userData', join(app.getPath('appData'), `${app.name}Dev`)); +} + +export function userDataPath(...segments: string[]) { + return join(app.getPath('userData'), ...[segments].flat()); +} + +export function userDataRecipesPath(...segments: any[]) { + return userDataPath('recipes', ...[segments].flat()); +} + +// Replacing app.asar is not beautiful but unfortunately necessary +export function asarRecipesPath(...segments: any[]) { + return join(asarPath(join(__dirname, 'recipes')), ...[segments].flat()); +} + +export const useLiveAPI = process.env.USE_LIVE_API; +const useLocalAPI = process.env.USE_LOCAL_API; + +export const isMac = is.macos; +export const isWindows = is.windows; +export const isLinux = is.linux; +export const osPlatform = os.platform(); +export const osArch = os.arch(); +export const osRelease = os.release(); +export const is64Bit = osArch.match(/64/); + +// for accelerator, show the shortform that electron/OS understands +// for tooltip, show symbol +const ctrlKey = isMac ? '⌘' : 'Ctrl'; +const cmdKey = isMac ? 'Cmd' : 'Ctrl'; + +export const altKey = (isAccelerator = true) => + !isAccelerator && isMac ? '⌥' : 'Alt'; +export const shiftKey = (isAccelerator = true) => + !isAccelerator && isMac ? '⇧' : 'Shift'; + +// Platform specific shortcut keys +export const cmdOrCtrlShortcutKey = (isAccelerator = true) => + isAccelerator ? cmdKey : ctrlKey; +export const lockFerdiShortcutKey = (isAccelerator = true) => + `${cmdOrCtrlShortcutKey(isAccelerator)}+${shiftKey(isAccelerator)}+L`; +export const todosToggleShortcutKey = (isAccelerator = true) => + `${cmdOrCtrlShortcutKey(isAccelerator)}+T`; +export const workspaceToggleShortcutKey = (isAccelerator = true) => + `${cmdOrCtrlShortcutKey(isAccelerator)}+D`; +export const muteFerdiShortcutKey = (isAccelerator = true) => + `${cmdOrCtrlShortcutKey(isAccelerator)}+${shiftKey(isAccelerator)}+M`; +export const addNewServiceShortcutKey = (isAccelerator = true) => + `${cmdOrCtrlShortcutKey(isAccelerator)}+N`; +export const settingsShortcutKey = (isAccelerator = true) => + `${cmdOrCtrlShortcutKey(isAccelerator)}+${isMac ? ',' : 'P'}`; + +let api: string; +let wsApi: string; +let web: string; +let todos: string; +if (!isDevMode || (isDevMode && useLiveAPI)) { + api = LIVE_FERDI_API; + wsApi = LIVE_WS_API; + web = LIVE_API_FERDI_WEBSITE; + todos = PRODUCTION_TODOS_FRONTEND_URL; +} else if (isDevMode && useLocalAPI) { + api = LOCAL_API; + wsApi = LOCAL_WS_API; + web = LOCAL_API_WEBSITE; + todos = LOCAL_TODOS_FRONTEND_URL; +} else { + api = DEV_FRANZ_API; + wsApi = DEV_WS_API; + web = DEV_API_FRANZ_WEBSITE; + todos = PRODUCTION_TODOS_FRONTEND_URL; +} + +export const API = api; +export const API_VERSION = 'v1'; +export const WS_API = wsApi; +export const WEBSITE = web; +export const TODOS_FRONTEND = todos; + +export const DEFAULT_APP_SETTINGS = { + autoLaunchInBackground: false, + runInBackground: true, + reloadAfterResume: true, + enableSystemTray: true, + startMinimized: false, + confirmOnQuit: false, + minimizeToSystemTray: false, + closeToSystemTray: false, + privateNotifications: false, + clipboardNotifications: true, + notifyTaskBarOnMessage: false, + showDisabledServices: true, + showMessageBadgeWhenMuted: true, + showDragArea: false, + enableSpellchecking: true, + spellcheckerLanguage: 'en-us', + darkMode: isMac && electronApi.nativeTheme.shouldUseDarkColors, + splitMode: false, + locale: '', + fallbackLocale: 'en-US', + beta: false, + isAppMuted: false, + enableGPUAcceleration: true, + + // Ferdi specific options + server: LIVE_FERDI_API, + predefinedTodoServer: DEFAULT_TODO_SERVICE, + autohideMenuBar: false, + lockingFeatureEnabled: false, + locked: false, + lockedPassword: '', + useTouchIdToUnlock: true, + scheduledDNDEnabled: false, + scheduledDNDStart: '17:00', + scheduledDNDEnd: '09:00', + hibernateOnStartup: true, + hibernationStrategy: '300', // seconds + wakeUpStrategy: '300', // seconds + inactivityLock: 0, + automaticUpdates: true, + showServiceNavigationBar: false, + universalDarkMode: true, + userAgentPref: '', + adaptableDarkMode: true, + accentColor: DEFAULT_ACCENT_COLOR, + serviceRibbonWidth: 68, + iconSize: iconSizeBias, + sentry: false, + nightly: false, + navigationBarBehaviour: 'custom', + searchEngine: SEARCH_ENGINE_DDG, + useVerticalStyle: false, + alwaysShowWorkspaces: false, + liftSingleInstanceLock: false, +}; + +export function aboutAppDetails() { + return [ + `Version: ${ferdiVersion}`, + `Electron: ${electronVersion}`, + `Chrome: ${chromeVersion}`, + `Node.js: ${nodeVersion}`, + `Platform: ${osName()}`, + `Arch: ${process.arch}`, + `Build date: ${new Date(Number(buildInfo.timestamp))}`, + `Git SHA: ${buildInfo.gitHashShort}`, + `Git branch: ${buildInfo.gitBranch}`, + ].join('\n'); +} diff --git a/src/features/appearance/index.js b/src/features/appearance/index.js deleted file mode 100644 index 0c935be32..000000000 --- a/src/features/appearance/index.js +++ /dev/null @@ -1,259 +0,0 @@ -import color from 'color'; -import { reaction } from 'mobx'; -import themeInfo from '../../assets/themeInfo.json'; -import { iconSizeBias } from '../../config'; -import { DEFAULT_APP_SETTINGS } from '../../environment'; - -const STYLE_ELEMENT_ID = 'custom-appearance-style'; - -function createStyleElement() { - const styles = document.createElement('style'); - styles.id = STYLE_ELEMENT_ID; - - document.querySelector('head')?.appendChild(styles); -} - -function setAppearance(style) { - const styleElement = document.querySelector(`#${STYLE_ELEMENT_ID}`); - - if (styleElement) { - styleElement.innerHTML = style; - } -} - -// See https://github.com/Qix-/color/issues/53#issuecomment-656590710 -function darkenAbsolute(originalColor, absoluteChange) { - const originalLightness = originalColor.lightness(); - return originalColor.lightness(originalLightness - absoluteChange); -} - -function generateAccentStyle(accentColorStr) { - let style = ''; - - for (const property of Object.keys(themeInfo)) { - style += ` - ${themeInfo[property]} { - ${property}: ${accentColorStr}; - } - `; - } - - let accentColor = color(DEFAULT_APP_SETTINGS.accentColor); - try { - accentColor = color(accentColorStr); - } catch { - // Ignore invalid accent color. - } - const darkerColorStr = darkenAbsolute(accentColor, 5).hex(); - style += ` - a.button:hover, button.button:hover { - background: ${darkenAbsolute(accentColor, 10).hex()}; - } - - .franz-form__button:hover, - .franz-form__button.franz-form__button--inverted:hover, - .settings .settings__close:hover, - .theme__dark .franz-form__button:hover, - .theme__dark .franz-form__button.franz-form__button--inverted:hover, - .theme__dark .settings .settings__close:hover { - background: ${darkerColorStr}; - } - - .franz-form__button:active, - .theme__dark .franz-form__button:active { - background: ${darkerColorStr}; - } - - .theme__dark .franz-form__button.franz-form__button--inverted, - .franz-form__button.franz-form__button--inverted { - background: none; - border-color: ${accentColorStr}; - } - - .tab-item.is-active { - background: ${accentColor.lighten(0.35).hex()}; - } - `; - - return style; -} - -function generateServiceRibbonWidthStyle(widthStr, iconSizeStr, vertical) { - const width = Number(widthStr); - const iconSize = Number(iconSizeStr) - iconSizeBias; - - return vertical - ? ` - .tab-item { - width: ${width - 2}px !important; - height: ${width - 5 + iconSize}px !important; - min-height: unset; - } - .tab-item .tab-item__icon { - width: ${width / 2 + iconSize}px !important; - } - .sidebar__button { - font-size: ${width / 3}px !important; - } - ` - : ` - .sidebar { - width: ${width}px !important; - } - .tab-item { - width: ${width}px !important; - height: ${width - 5 + iconSize}px !important; - } - .tab-item .tab-item__icon { - width: ${width / 2 + iconSize}px !important; - } - .sidebar__button { - font-size: ${width / 3}px !important; - } - .todos__todos-panel--expanded { - width: calc(100% - ${300 + width}px) !important; - } - `; -} - -function generateShowDragAreaStyle(accentColor) { - return ` - .sidebar { - padding-top: 0px !important; - } - .window-draggable { - position: initial; - background-color: ${accentColor}; - } - #root { - /** Remove 22px from app height, otherwise the page will be too high */ - height: calc(100% - 22px); - } - `; -} - -function generateVerticalStyle(widthStr, alwaysShowWorkspaces) { - if (!document.querySelector('#vertical-style')) { - const link = document.createElement('link'); - link.id = 'vertical-style'; - link.rel = 'stylesheet'; - link.type = 'text/css'; - link.href = './styles/vertical.css'; - - document.head.append(link); - } - const width = Number(widthStr); - const sidebarWidth = width - 4; - const verticalStyleOffset = 23; - - return ` - .sidebar { - height: ${sidebarWidth + verticalStyleOffset + 1}px !important; - ${ - alwaysShowWorkspaces - ? ` - width: calc(100% - 300px) !important; - ` - : '' - } - } - - .sidebar .sidebar__button { - width: ${width}px; - } - - .app .app__content { - padding-top: ${sidebarWidth + verticalStyleOffset + 1}px !important; - } - - .workspaces-drawer { - margin-top: -${sidebarWidth - verticalStyleOffset - 1}px !important; - } - - .todos__todos-panel--expanded { - width: calc(100% - 300px) !important; - } - `; -} - -function generateOpenWorkspaceStyle() { - return ` - .app .app__content { - width: 100%; - transform: translateX(0px); - } - .sidebar__button--workspaces { - display: none; - } - `; -} - -function generateStyle(settings) { - let style = ''; - - const { - accentColor, - serviceRibbonWidth, - iconSize, - showDragArea, - useVerticalStyle, - alwaysShowWorkspaces, - } = settings; - - if ( - accentColor.toLowerCase() !== DEFAULT_APP_SETTINGS.accentColor.toLowerCase() - ) { - style += generateAccentStyle(accentColor); - } - if ( - serviceRibbonWidth !== DEFAULT_APP_SETTINGS.serviceRibbonWidth || - iconSize !== DEFAULT_APP_SETTINGS.iconSize - ) { - style += generateServiceRibbonWidthStyle( - serviceRibbonWidth, - iconSize, - useVerticalStyle, - ); - } - if (showDragArea) { - style += generateShowDragAreaStyle(accentColor); - } - if (useVerticalStyle) { - style += generateVerticalStyle(serviceRibbonWidth, alwaysShowWorkspaces); - } else if (document.querySelector('#vertical-style')) { - const link = document.querySelector('#vertical-style'); - if (link) { - link.remove(); - } - } - if (alwaysShowWorkspaces) { - style += generateOpenWorkspaceStyle(); - } - - return style; -} -function updateStyle(settings) { - const style = generateStyle(settings); - setAppearance(style); -} - -export default function initAppearance(stores) { - const { settings } = stores; - createStyleElement(); - - // Update style when settings change - reaction( - () => [ - settings.all.app.accentColor, - settings.all.app.serviceRibbonWidth, - settings.all.app.iconSize, - settings.all.app.showDragArea, - settings.all.app.useVerticalStyle, - settings.all.app.alwaysShowWorkspaces, - ], - () => { - updateStyle(settings.all.app); - }, - { fireImmediately: true }, - ); -} diff --git a/src/features/appearance/index.ts b/src/features/appearance/index.ts new file mode 100644 index 000000000..b00b9df3d --- /dev/null +++ b/src/features/appearance/index.ts @@ -0,0 +1,250 @@ +import color from 'color'; +import { reaction } from 'mobx'; +import { iconSizeBias } from '../../config'; +import { DEFAULT_APP_SETTINGS } from '../../environment'; + +const STYLE_ELEMENT_ID = 'custom-appearance-style'; + +function createStyleElement() { + const styles = document.createElement('style'); + styles.id = STYLE_ELEMENT_ID; + + document.querySelector('head')?.appendChild(styles); +} + +function setAppearance(style) { + const styleElement = document.querySelector(`#${STYLE_ELEMENT_ID}`); + + if (styleElement) { + styleElement.innerHTML = style; + } +} + +// See https://github.com/Qix-/color/issues/53#issuecomment-656590710 +function darkenAbsolute(originalColor, absoluteChange) { + const originalLightness = originalColor.lightness(); + return originalColor.lightness(originalLightness - absoluteChange); +} + +function generateAccentStyle(accentColorStr) { + let style = ''; + + let accentColor = color(DEFAULT_APP_SETTINGS.accentColor); + try { + accentColor = color(accentColorStr); + } catch { + // Ignore invalid accent color. + } + const darkerColorStr = darkenAbsolute(accentColor, 5).hex(); + style += ` + a.button:hover, button.button:hover { + background: ${darkenAbsolute(accentColor, 10).hex()}; + } + + .franz-form__button:hover, + .franz-form__button.franz-form__button--inverted:hover, + .settings .settings__close:hover, + .theme__dark .franz-form__button:hover, + .theme__dark .franz-form__button.franz-form__button--inverted:hover, + .theme__dark .settings .settings__close:hover { + background: ${darkerColorStr}; + } + + .franz-form__button:active, + .theme__dark .franz-form__button:active { + background: ${darkerColorStr}; + } + + .theme__dark .franz-form__button.franz-form__button--inverted, + .franz-form__button.franz-form__button--inverted { + background: none; + border-color: ${accentColorStr}; + } + + .tab-item.is-active { + background: ${accentColor.lighten(0.35).hex()}; + } + `; + + return style; +} + +function generateServiceRibbonWidthStyle(widthStr, iconSizeStr, vertical) { + const width = Number(widthStr); + const iconSize = Number(iconSizeStr) - iconSizeBias; + + return vertical + ? ` + .tab-item { + width: ${width - 2}px !important; + height: ${width - 5 + iconSize}px !important; + min-height: unset; + } + .tab-item .tab-item__icon { + width: ${width / 2 + iconSize}px !important; + } + .sidebar__button { + font-size: ${width / 3}px !important; + } + ` + : ` + .sidebar { + width: ${width}px !important; + } + .tab-item { + width: ${width}px !important; + height: ${width - 5 + iconSize}px !important; + } + .tab-item .tab-item__icon { + width: ${width / 2 + iconSize}px !important; + } + .sidebar__button { + font-size: ${width / 3}px !important; + } + .todos__todos-panel--expanded { + width: calc(100% - ${300 + width}px) !important; + } + `; +} + +function generateShowDragAreaStyle(accentColor) { + return ` + .sidebar { + padding-top: 0px !important; + } + .window-draggable { + position: initial; + background-color: ${accentColor}; + } + #root { + /** Remove 22px from app height, otherwise the page will be too high */ + height: calc(100% - 22px); + } + `; +} + +function generateVerticalStyle(widthStr, alwaysShowWorkspaces) { + if (!document.querySelector('#vertical-style')) { + const link = document.createElement('link'); + link.id = 'vertical-style'; + link.rel = 'stylesheet'; + link.type = 'text/css'; + link.href = './styles/vertical.css'; + + document.head.append(link); + } + const width = Number(widthStr); + const sidebarWidth = width - 4; + const verticalStyleOffset = 23; + + return ` + .sidebar { + height: ${sidebarWidth + verticalStyleOffset + 1}px !important; + ${ + alwaysShowWorkspaces + ? ` + width: calc(100% - 300px) !important; + ` + : '' + } + } + + .sidebar .sidebar__button { + width: ${width}px; + } + + .app .app__content { + padding-top: ${sidebarWidth + verticalStyleOffset + 1}px !important; + } + + .workspaces-drawer { + margin-top: -${sidebarWidth - verticalStyleOffset - 1}px !important; + } + + .todos__todos-panel--expanded { + width: calc(100% - 300px) !important; + } + `; +} + +function generateOpenWorkspaceStyle() { + return ` + .app .app__content { + width: 100%; + transform: translateX(0px); + } + .sidebar__button--workspaces { + display: none; + } + `; +} + +function generateStyle(settings) { + let style = ''; + + const { + accentColor, + serviceRibbonWidth, + iconSize, + showDragArea, + useVerticalStyle, + alwaysShowWorkspaces, + } = settings; + + if ( + accentColor.toLowerCase() !== DEFAULT_APP_SETTINGS.accentColor.toLowerCase() + ) { + style += generateAccentStyle(accentColor); + } + if ( + serviceRibbonWidth !== DEFAULT_APP_SETTINGS.serviceRibbonWidth || + iconSize !== DEFAULT_APP_SETTINGS.iconSize + ) { + style += generateServiceRibbonWidthStyle( + serviceRibbonWidth, + iconSize, + useVerticalStyle, + ); + } + if (showDragArea) { + style += generateShowDragAreaStyle(accentColor); + } + if (useVerticalStyle) { + style += generateVerticalStyle(serviceRibbonWidth, alwaysShowWorkspaces); + } else if (document.querySelector('#vertical-style')) { + const link = document.querySelector('#vertical-style'); + if (link) { + link.remove(); + } + } + if (alwaysShowWorkspaces) { + style += generateOpenWorkspaceStyle(); + } + + return style; +} +function updateStyle(settings) { + const style = generateStyle(settings); + setAppearance(style); +} + +export default function initAppearance(stores) { + const { settings } = stores; + createStyleElement(); + + // Update style when settings change + reaction( + () => [ + settings.all.app.accentColor, + settings.all.app.serviceRibbonWidth, + settings.all.app.iconSize, + settings.all.app.showDragArea, + settings.all.app.useVerticalStyle, + settings.all.app.alwaysShowWorkspaces, + ], + () => { + updateStyle(settings.all.app); + }, + { fireImmediately: true }, + ); +} diff --git a/src/features/basicAuth/Form.js b/src/features/basicAuth/Form.js deleted file mode 100644 index 95721d0e9..000000000 --- a/src/features/basicAuth/Form.js +++ /dev/null @@ -1,17 +0,0 @@ -import Form from '../../lib/Form'; - -export default new Form({ - fields: { - user: { - label: 'user', - placeholder: 'Username', - value: '', - }, - password: { - label: 'Password', - placeholder: 'Password', - value: '', - type: 'password', - }, - }, -}); diff --git a/src/features/basicAuth/Form.ts b/src/features/basicAuth/Form.ts new file mode 100644 index 000000000..95721d0e9 --- /dev/null +++ b/src/features/basicAuth/Form.ts @@ -0,0 +1,17 @@ +import Form from '../../lib/Form'; + +export default new Form({ + fields: { + user: { + label: 'user', + placeholder: 'Username', + value: '', + }, + password: { + label: 'Password', + placeholder: 'Password', + value: '', + type: 'password', + }, + }, +}); diff --git a/src/features/basicAuth/mainIpcHandler.js b/src/features/basicAuth/mainIpcHandler.js deleted file mode 100644 index ae4e7cf93..000000000 --- a/src/features/basicAuth/mainIpcHandler.js +++ /dev/null @@ -1,9 +0,0 @@ -const debug = require('debug')('Ferdi:feature:basicAuth:main'); - -export default function mainIpcHandler(mainWindow, authInfo) { - debug('Sending basic auth call', authInfo); - - mainWindow.webContents.send('feature:basic-auth', { - authInfo, - }); -} diff --git a/src/features/basicAuth/mainIpcHandler.ts b/src/features/basicAuth/mainIpcHandler.ts new file mode 100644 index 000000000..4ec3848e8 --- /dev/null +++ b/src/features/basicAuth/mainIpcHandler.ts @@ -0,0 +1,11 @@ +import { BrowserWindow } from 'electron'; + +const debug = require('debug')('Ferdi:feature:basicAuth:main'); + +export default function mainIpcHandler(mainWindow: BrowserWindow, authInfo) { + debug('Sending basic auth call', authInfo); + + mainWindow.webContents.send('feature:basic-auth', { + authInfo, + }); +} diff --git a/src/features/basicAuth/store.js b/src/features/basicAuth/store.js deleted file mode 100644 index 0713ff572..000000000 --- a/src/features/basicAuth/store.js +++ /dev/null @@ -1,30 +0,0 @@ -import { observable } from 'mobx'; -import { ipcRenderer } from 'electron'; - -const debug = require('debug')('Ferdi:feature:basicAuth'); - -const defaultState = { - isModalVisible: true, - service: null, - authInfo: null, -}; - -export const state = observable(defaultState); - -export function resetState() { - Object.assign(state, defaultState); -} -export function sendCredentials(user, password) { - debug('Sending credentials to main', user, password); - - ipcRenderer.send('feature-basic-auth-credentials', { - user, - password, - }); -} - -export function cancelLogin() { - debug('Cancel basic auth event'); - - ipcRenderer.send('feature-basic-auth-cancel'); -} diff --git a/src/features/basicAuth/store.ts b/src/features/basicAuth/store.ts new file mode 100644 index 000000000..0713ff572 --- /dev/null +++ b/src/features/basicAuth/store.ts @@ -0,0 +1,30 @@ +import { observable } from 'mobx'; +import { ipcRenderer } from 'electron'; + +const debug = require('debug')('Ferdi:feature:basicAuth'); + +const defaultState = { + isModalVisible: true, + service: null, + authInfo: null, +}; + +export const state = observable(defaultState); + +export function resetState() { + Object.assign(state, defaultState); +} +export function sendCredentials(user, password) { + debug('Sending credentials to main', user, password); + + ipcRenderer.send('feature-basic-auth-credentials', { + user, + password, + }); +} + +export function cancelLogin() { + debug('Cancel basic auth event'); + + ipcRenderer.send('feature-basic-auth-cancel'); +} diff --git a/src/features/basicAuth/styles.js b/src/features/basicAuth/styles.js deleted file mode 100644 index 6bdaf9a6e..000000000 --- a/src/features/basicAuth/styles.js +++ /dev/null @@ -1,12 +0,0 @@ -export default { - modal: { - width: 300, - }, - buttons: { - display: 'flex', - justifyContent: 'space-between', - }, - form: { - marginTop: 15, - }, -}; diff --git a/src/features/basicAuth/styles.ts b/src/features/basicAuth/styles.ts new file mode 100644 index 000000000..6bdaf9a6e --- /dev/null +++ b/src/features/basicAuth/styles.ts @@ -0,0 +1,12 @@ +export default { + modal: { + width: 300, + }, + buttons: { + display: 'flex', + justifyContent: 'space-between', + }, + form: { + marginTop: 15, + }, +}; diff --git a/src/features/communityRecipes/index.js b/src/features/communityRecipes/index.js deleted file mode 100644 index 828c6d867..000000000 --- a/src/features/communityRecipes/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import { CommunityRecipesStore } from './store'; - -export const communityRecipesStore = new CommunityRecipesStore(); - -export default function initCommunityRecipes(stores, actions) { - communityRecipesStore.start(stores, actions); -} diff --git a/src/features/communityRecipes/index.ts b/src/features/communityRecipes/index.ts new file mode 100644 index 000000000..828c6d867 --- /dev/null +++ b/src/features/communityRecipes/index.ts @@ -0,0 +1,7 @@ +import { CommunityRecipesStore } from './store'; + +export const communityRecipesStore = new CommunityRecipesStore(); + +export default function initCommunityRecipes(stores, actions) { + communityRecipesStore.start(stores, actions); +} diff --git a/src/features/utils/ActionBinding.js b/src/features/utils/ActionBinding.js deleted file mode 100644 index 787166d44..000000000 --- a/src/features/utils/ActionBinding.js +++ /dev/null @@ -1,29 +0,0 @@ -export default class ActionBinding { - action; - - isActive = false; - - constructor(action) { - this.action = action; - } - - start() { - if (!this.isActive) { - const { action } = this; - action[0].listen(action[1]); - this.isActive = true; - } - } - - stop() { - if (this.isActive) { - const { action } = this; - action[0].off(action[1]); - this.isActive = false; - } - } -} - -export const createActionBindings = (actions) => ( - actions.map((a) => new ActionBinding(a)) -); diff --git a/src/features/utils/ActionBinding.ts b/src/features/utils/ActionBinding.ts new file mode 100644 index 000000000..787166d44 --- /dev/null +++ b/src/features/utils/ActionBinding.ts @@ -0,0 +1,29 @@ +export default class ActionBinding { + action; + + isActive = false; + + constructor(action) { + this.action = action; + } + + start() { + if (!this.isActive) { + const { action } = this; + action[0].listen(action[1]); + this.isActive = true; + } + } + + stop() { + if (this.isActive) { + const { action } = this; + action[0].off(action[1]); + this.isActive = false; + } + } +} + +export const createActionBindings = (actions) => ( + actions.map((a) => new ActionBinding(a)) +); diff --git a/src/features/workspaces/actions.js b/src/features/workspaces/actions.js deleted file mode 100644 index 5b5db422e..000000000 --- a/src/features/workspaces/actions.js +++ /dev/null @@ -1,27 +0,0 @@ -import PropTypes from 'prop-types'; -import Workspace from './models/Workspace'; -import { createActionsFromDefinitions } from '../../actions/lib/actions'; - -export const workspaceActions = createActionsFromDefinitions({ - edit: { - workspace: PropTypes.instanceOf(Workspace).isRequired, - }, - create: { - name: PropTypes.string.isRequired, - }, - delete: { - workspace: PropTypes.instanceOf(Workspace).isRequired, - }, - update: { - workspace: PropTypes.instanceOf(Workspace).isRequired, - }, - activate: { - workspace: PropTypes.instanceOf(Workspace).isRequired, - }, - deactivate: {}, - toggleWorkspaceDrawer: {}, - openWorkspaceSettings: {}, - toggleKeepAllWorkspacesLoadedSetting: {}, -}, PropTypes.checkPropTypes); - -export default workspaceActions; diff --git a/src/features/workspaces/actions.ts b/src/features/workspaces/actions.ts new file mode 100644 index 000000000..5e7e6e721 --- /dev/null +++ b/src/features/workspaces/actions.ts @@ -0,0 +1,30 @@ +import PropTypes from 'prop-types'; +import Workspace from './models/Workspace'; +import { createActionsFromDefinitions } from '../../actions/lib/actions'; + +export const workspaceActions = createActionsFromDefinitions( + { + edit: { + workspace: PropTypes.instanceOf(Workspace).isRequired, + }, + create: { + name: PropTypes.string.isRequired, + }, + delete: { + workspace: PropTypes.instanceOf(Workspace).isRequired, + }, + update: { + workspace: PropTypes.instanceOf(Workspace).isRequired, + }, + activate: { + workspace: PropTypes.instanceOf(Workspace).isRequired, + }, + deactivate: {}, + toggleWorkspaceDrawer: {}, + openWorkspaceSettings: {}, + toggleKeepAllWorkspacesLoadedSetting: {}, + }, + PropTypes.checkPropTypes, +); + +export default workspaceActions; diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js deleted file mode 100644 index 322695ed2..000000000 --- a/src/features/workspaces/api.js +++ /dev/null @@ -1,66 +0,0 @@ -import { pick } from 'lodash'; -import { sendAuthRequest } from '../../api/utils/auth'; -import Request from '../../stores/lib/Request'; -import Workspace from './models/Workspace'; -import apiBase from '../../api/apiBase'; - -const debug = require('debug')('Ferdi:feature:workspaces:api'); - -export const workspaceApi = { - getUserWorkspaces: async () => { - const url = `${apiBase()}/workspace`; - debug('getUserWorkspaces GET', url); - const result = await sendAuthRequest(url, { method: 'GET' }); - debug('getUserWorkspaces RESULT', result); - if (!result.ok) throw result; - const workspaces = await result.json(); - return workspaces.map((data) => new Workspace(data)); - }, - - createWorkspace: async (name) => { - const url = `${apiBase()}/workspace`; - const options = { - method: 'POST', - body: JSON.stringify({ name }), - }; - debug('createWorkspace POST', url, options); - const result = await sendAuthRequest(url, options); - debug('createWorkspace RESULT', result); - if (!result.ok) throw result; - return new Workspace(await result.json()); - }, - - deleteWorkspace: async (workspace) => { - const url = `${apiBase()}/workspace/${workspace.id}`; - debug('deleteWorkspace DELETE', url); - const result = await sendAuthRequest(url, { method: 'DELETE' }); - debug('deleteWorkspace RESULT', result); - if (!result.ok) throw result; - return true; - }, - - updateWorkspace: async (workspace) => { - const url = `${apiBase()}/workspace/${workspace.id}`; - const options = { - method: 'PUT', - body: JSON.stringify(pick(workspace, ['name', 'services'])), - }; - debug('updateWorkspace UPDATE', url, options); - const result = await sendAuthRequest(url, options); - debug('updateWorkspace RESULT', result); - if (!result.ok) throw result; - return new Workspace(await result.json()); - }, -}; - -export const getUserWorkspacesRequest = new Request(workspaceApi, 'getUserWorkspaces'); -export const createWorkspaceRequest = new Request(workspaceApi, 'createWorkspace'); -export const deleteWorkspaceRequest = new Request(workspaceApi, 'deleteWorkspace'); -export const updateWorkspaceRequest = new Request(workspaceApi, 'updateWorkspace'); - -export const resetApiRequests = () => { - getUserWorkspacesRequest.reset(); - createWorkspaceRequest.reset(); - deleteWorkspaceRequest.reset(); - updateWorkspaceRequest.reset(); -}; diff --git a/src/features/workspaces/api.ts b/src/features/workspaces/api.ts new file mode 100644 index 000000000..8447fc247 --- /dev/null +++ b/src/features/workspaces/api.ts @@ -0,0 +1,86 @@ +import { pick } from 'lodash'; +import { sendAuthRequest } from '../../api/utils/auth'; +import Request from '../../stores/lib/Request'; +import Workspace from './models/Workspace'; +import apiBase from '../../api/apiBase'; + +const debug = require('debug')('Ferdi:feature:workspaces:api'); + +export const workspaceApi = { + getUserWorkspaces: async () => { + const url = `${apiBase()}/workspace`; + debug('getUserWorkspaces GET', url); + const result = await sendAuthRequest(url, { method: 'GET' }); + debug('getUserWorkspaces RESULT', result); + if (!result.ok) { + throw new Error("Couldn't getUserWorkspaces"); + } + const workspaces = await result.json(); + return workspaces.map(data => new Workspace(data)); + }, + + createWorkspace: async name => { + const url = `${apiBase()}/workspace`; + const options = { + method: 'POST', + body: JSON.stringify({ name }), + }; + debug('createWorkspace POST', url, options); + const result = await sendAuthRequest(url, options); + debug('createWorkspace RESULT', result); + if (!result.ok) { + throw new Error("Couldn't createWorkspace"); + } + return new Workspace(await result.json()); + }, + + deleteWorkspace: async workspace => { + const url = `${apiBase()}/workspace/${workspace.id}`; + debug('deleteWorkspace DELETE', url); + const result = await sendAuthRequest(url, { method: 'DELETE' }); + debug('deleteWorkspace RESULT', result); + if (!result.ok) { + throw new Error("Couldn't deleteWorkspace"); + } + return true; + }, + + updateWorkspace: async workspace => { + const url = `${apiBase()}/workspace/${workspace.id}`; + const options = { + method: 'PUT', + body: JSON.stringify(pick(workspace, ['name', 'services'])), + }; + debug('updateWorkspace UPDATE', url, options); + const result = await sendAuthRequest(url, options); + debug('updateWorkspace RESULT', result); + if (!result.ok) { + throw new Error("Couldn't updateWorkspace"); + } + return new Workspace(await result.json()); + }, +}; + +export const getUserWorkspacesRequest = new Request( + workspaceApi, + 'getUserWorkspaces', +); +export const createWorkspaceRequest = new Request( + workspaceApi, + 'createWorkspace', +); +export const deleteWorkspaceRequest = new Request( + workspaceApi, + 'deleteWorkspace', +); +export const updateWorkspaceRequest = new Request( + workspaceApi, + 'updateWorkspace', +); + +export const resetApiRequests = () => { + getUserWorkspacesRequest.reset(); + createWorkspaceRequest.reset(); + deleteWorkspaceRequest.reset(); + updateWorkspaceRequest.reset(); +}; diff --git a/src/features/workspaces/constants.js b/src/features/workspaces/constants.js deleted file mode 100644 index 2d1416ee0..000000000 --- a/src/features/workspaces/constants.js +++ /dev/null @@ -1,4 +0,0 @@ -export const WORKSPACES_ROUTES = { - ROOT: '/settings/workspaces', - EDIT: '/settings/workspaces/:action/:id', -}; diff --git a/src/features/workspaces/constants.ts b/src/features/workspaces/constants.ts new file mode 100644 index 000000000..2d1416ee0 --- /dev/null +++ b/src/features/workspaces/constants.ts @@ -0,0 +1,4 @@ +export const WORKSPACES_ROUTES = { + ROOT: '/settings/workspaces', + EDIT: '/settings/workspaces/:action/:id', +}; diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js deleted file mode 100644 index 83e4d9049..000000000 --- a/src/features/workspaces/index.js +++ /dev/null @@ -1,30 +0,0 @@ -import { reaction } from 'mobx'; -import WorkspacesStore from './store'; -import { resetApiRequests } from './api'; - -const debug = require('debug')('Ferdi:feature:workspaces'); - -export const workspaceStore = new WorkspacesStore(); - -export default function initWorkspaces(stores, actions) { - stores.workspaces = workspaceStore; - const { features } = stores; - - // Toggle workspace feature - reaction( - () => ( - features.features.isWorkspaceEnabled - ), - (isEnabled) => { - if (isEnabled && !workspaceStore.isFeatureActive) { - debug('Initializing `workspaces` feature'); - workspaceStore.start(stores, actions); - } else if (workspaceStore.isFeatureActive) { - debug('Disabling `workspaces` feature'); - workspaceStore.stop(); - resetApiRequests(); - } - }, - { fireImmediately: true }, - ); -} diff --git a/src/features/workspaces/index.ts b/src/features/workspaces/index.ts new file mode 100644 index 000000000..ecca64b41 --- /dev/null +++ b/src/features/workspaces/index.ts @@ -0,0 +1,28 @@ +import { reaction } from 'mobx'; +import WorkspacesStore from './store'; +import { resetApiRequests } from './api'; + +const debug = require('debug')('Ferdi:feature:workspaces'); + +export const workspaceStore = new WorkspacesStore(); + +export default function initWorkspaces(stores, actions) { + stores.workspaces = workspaceStore; + const { features } = stores; + + // Toggle workspace feature + reaction( + () => features.features.isWorkspaceEnabled, + isEnabled => { + if (isEnabled && !workspaceStore.isFeatureActive) { + debug('Initializing `workspaces` feature'); + workspaceStore.start(stores, actions); + } else if (workspaceStore.isFeatureActive) { + debug('Disabling `workspaces` feature'); + workspaceStore.stop(); + resetApiRequests(); + } + }, + { fireImmediately: true }, + ); +} diff --git a/src/features/workspaces/models/Workspace.js b/src/features/workspaces/models/Workspace.js deleted file mode 100644 index 14add9437..000000000 --- a/src/features/workspaces/models/Workspace.js +++ /dev/null @@ -1,37 +0,0 @@ -import { observable } from 'mobx'; - -import { KEEP_WS_LOADED_USID } from '../../../config'; - -export default class Workspace { - id = null; - - @observable name = null; - - @observable order = null; - - @observable services = []; - - @observable userId = null; - - constructor(data) { - if (!data.id) { - throw new Error('Workspace requires Id'); - } - - this.id = data.id; - this.name = data.name; - this.order = data.order; - - let { services } = data; - if (data.saving && Boolean(data.keepLoaded)) { - // Keep workspaces loaded - services.push(KEEP_WS_LOADED_USID); - } else if (data.saving && data.services.includes(KEEP_WS_LOADED_USID)) { - // Don't keep loaded - services = services.filter((e) => e !== KEEP_WS_LOADED_USID); - } - this.services.replace(services); - - this.userId = data.userId; - } -} diff --git a/src/features/workspaces/models/Workspace.ts b/src/features/workspaces/models/Workspace.ts new file mode 100644 index 000000000..cd3918fba --- /dev/null +++ b/src/features/workspaces/models/Workspace.ts @@ -0,0 +1,39 @@ +import { observable } from 'mobx'; + +import { KEEP_WS_LOADED_USID } from '../../../config'; + +export default class Workspace { + id = null; + + @observable name = null; + + @observable order = null; + + @observable services = []; + + @observable userId = null; + + constructor(data) { + if (!data.id) { + throw new Error('Workspace requires Id'); + } + + this.id = data.id; + this.name = data.name; + this.order = data.order; + + let { services } = data; + if (data.saving && Boolean(data.keepLoaded)) { + // Keep workspaces loaded + services.push(KEEP_WS_LOADED_USID); + } else if (data.saving && data.services.includes(KEEP_WS_LOADED_USID)) { + // Don't keep loaded + services = services.filter(e => e !== KEEP_WS_LOADED_USID); + } + + // @ts-expect-error Property 'replace' does not exist on type 'never[]'. + this.services.replace(services); + + this.userId = data.userId; + } +} diff --git a/src/i18n/apply-branding.js b/src/i18n/apply-branding.js deleted file mode 100644 index 8ec573919..000000000 --- a/src/i18n/apply-branding.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Apply Ferdi branding to i18n translations - */ -const fs = require('fs-extra'); -const path = require('path'); - -console.log('Applying Ferdi branding to translations...'); - -// Keys to ignore when applying branding -const ignore = new Set([ - 'login.customServerSuggestion', - 'login.customServerQuestion', - 'settings.app.todoServerInfo', - 'settings.app.serverMoneyInfo', - 'settings.team.teamsUnavailableInfo', - 'settings.team.contentHeadline', - 'settings.team.intro', - 'settings.team.copy', - 'settings.team.manageAction', - 'settings.app.serverMoneyInfo', -]); - -// Files to ignore when applying branding -const ignoreFiles = new Set(['.DS_Store', '.', '..']); - -// What to replace -const replace = { - 'meetfranz.com': 'getferdi.com', - 'meetferdi.com': 'getferdi.com', // If Franz already got replaced with Ferdi - franz: 'Ferdi', - '!!!': '', -}; - -const locales = path.join(__dirname, 'locales'); -const files = fs.readdirSync(locales); - -const replaceFind = Object.keys(replace); -const replaceReplaceWith = Object.values(replace); - -const replaceStr = (str, find, replaceWith) => { - for (const [i, element] of find.entries()) { - str = str.replace(new RegExp(element, 'gi'), replaceWith[i]); - } - return str; -}; - -// eslint-disable-next-line unicorn/no-array-for-each -files.forEach(async file => { - if (ignoreFiles.has(file)) return; - - // Read locale data - const filePath = path.join(locales, file); - const locale = await fs.readJson(filePath); - - // Replace branding - for (const key in locale) { - if (!ignore.has(key)) { - locale[key] = replaceStr(locale[key], replaceFind, replaceReplaceWith); - } - } - - await fs.writeJson(filePath, locale, { - spaces: 2, - EOL: '\n', - }); -}); diff --git a/src/i18n/apply-branding.ts b/src/i18n/apply-branding.ts new file mode 100644 index 000000000..801a4a525 --- /dev/null +++ b/src/i18n/apply-branding.ts @@ -0,0 +1,66 @@ +/** + * Apply Ferdi branding to i18n translations + */ +import fs from 'fs-extra'; +import path from 'path'; + +console.log('Applying Ferdi branding to translations...'); + +// Keys to ignore when applying branding +const ignore = new Set([ + 'login.customServerSuggestion', + 'login.customServerQuestion', + 'settings.app.todoServerInfo', + 'settings.app.serverMoneyInfo', + 'settings.team.teamsUnavailableInfo', + 'settings.team.contentHeadline', + 'settings.team.intro', + 'settings.team.copy', + 'settings.team.manageAction', + 'settings.app.serverMoneyInfo', +]); + +// Files to ignore when applying branding +const ignoreFiles = new Set(['.DS_Store', '.', '..']); + +// What to replace +const replace = { + 'meetfranz.com': 'getferdi.com', + 'meetferdi.com': 'getferdi.com', // If Franz already got replaced with Ferdi + franz: 'Ferdi', + '!!!': '', +}; + +const locales = path.join(__dirname, 'locales'); +const files = fs.readdirSync(locales); + +const replaceFind = Object.keys(replace); +const replaceReplaceWith = Object.values(replace); + +const replaceStr = (str, find, replaceWith) => { + for (const [i, element] of find.entries()) { + str = str.replace(new RegExp(element, 'gi'), replaceWith[i]); + } + return str; +}; + +// eslint-disable-next-line unicorn/no-array-for-each +files.forEach(async file => { + if (ignoreFiles.has(file)) return; + + // Read locale data + const filePath = path.join(locales, file); + const locale = await fs.readJson(filePath); + + // Replace branding + for (const key in locale) { + if (!ignore.has(key)) { + locale[key] = replaceStr(locale[key], replaceFind, replaceReplaceWith); + } + } + + await fs.writeJson(filePath, locale, { + spaces: 2, + EOL: '\n', + }); +}); diff --git a/src/i18n/globalMessages.js b/src/i18n/globalMessages.js deleted file mode 100644 index 8e1df10f7..000000000 --- a/src/i18n/globalMessages.js +++ /dev/null @@ -1,77 +0,0 @@ -import { defineMessages } from 'react-intl'; - -export default defineMessages({ - APIUnhealthy: { - id: 'global.api.unhealthy', - defaultMessage: "Can't connect to Ferdi online services", - }, - notConnectedToTheInternet: { - id: 'global.notConnectedToTheInternet', - defaultMessage: 'You are not connected to the internet.', - }, - spellcheckerLanguage: { - id: 'global.spellchecking.language', - defaultMessage: 'Spell checking language', - }, - spellcheckerSystemDefault: { - id: 'global.spellchecker.useDefault', - defaultMessage: 'Use System Default ({default})', - }, - spellcheckerAutomaticDetection: { - id: 'global.spellchecking.autodetect', - defaultMessage: 'Detect language automatically', - }, - spellcheckerAutomaticDetectionShort: { - id: 'global.spellchecking.autodetect.short', - defaultMessage: 'Automatic', - }, - userAgentPref: { - id: 'global.userAgentPref', - defaultMessage: 'User Agent', - }, - userAgentHelp: { - id: 'global.userAgentHelp', - defaultMessage: - "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", - }, - yes: { - id: 'global.yes', - defaultMessage: 'Yes', - }, - no: { - id: 'global.no', - defaultMessage: 'No', - }, - ok: { - id: 'global.ok', - defaultMessage: 'Ok', - }, - cancel: { - id: 'global.cancel', - defaultMessage: 'Cancel', - }, - save: { - id: 'global.save', - defaultMessage: 'Save', - }, - submit: { - id: 'global.submit', - defaultMessage: 'Submit', - }, - quit: { - id: 'global.quit', - defaultMessage: 'Quit', - }, - quitConfirmation: { - id: 'global.quitConfirmation', - defaultMessage: 'Do you really want to quit Ferdi?', - }, - settings: { - id: 'global.settings', - defaultMessage: 'Settings', - }, - edit: { - id: 'global.edit', - defaultMessage: 'Edit', - }, -}); diff --git a/src/i18n/globalMessages.ts b/src/i18n/globalMessages.ts new file mode 100644 index 000000000..8e1df10f7 --- /dev/null +++ b/src/i18n/globalMessages.ts @@ -0,0 +1,77 @@ +import { defineMessages } from 'react-intl'; + +export default defineMessages({ + APIUnhealthy: { + id: 'global.api.unhealthy', + defaultMessage: "Can't connect to Ferdi online services", + }, + notConnectedToTheInternet: { + id: 'global.notConnectedToTheInternet', + defaultMessage: 'You are not connected to the internet.', + }, + spellcheckerLanguage: { + id: 'global.spellchecking.language', + defaultMessage: 'Spell checking language', + }, + spellcheckerSystemDefault: { + id: 'global.spellchecker.useDefault', + defaultMessage: 'Use System Default ({default})', + }, + spellcheckerAutomaticDetection: { + id: 'global.spellchecking.autodetect', + defaultMessage: 'Detect language automatically', + }, + spellcheckerAutomaticDetectionShort: { + id: 'global.spellchecking.autodetect.short', + defaultMessage: 'Automatic', + }, + userAgentPref: { + id: 'global.userAgentPref', + defaultMessage: 'User Agent', + }, + userAgentHelp: { + id: 'global.userAgentHelp', + defaultMessage: + "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", + }, + yes: { + id: 'global.yes', + defaultMessage: 'Yes', + }, + no: { + id: 'global.no', + defaultMessage: 'No', + }, + ok: { + id: 'global.ok', + defaultMessage: 'Ok', + }, + cancel: { + id: 'global.cancel', + defaultMessage: 'Cancel', + }, + save: { + id: 'global.save', + defaultMessage: 'Save', + }, + submit: { + id: 'global.submit', + defaultMessage: 'Submit', + }, + quit: { + id: 'global.quit', + defaultMessage: 'Quit', + }, + quitConfirmation: { + id: 'global.quitConfirmation', + defaultMessage: 'Do you really want to quit Ferdi?', + }, + settings: { + id: 'global.settings', + defaultMessage: 'Settings', + }, + edit: { + id: 'global.edit', + defaultMessage: 'Edit', + }, +}); diff --git a/src/i18n/languages.js b/src/i18n/languages.js deleted file mode 100644 index e7713b42b..000000000 --- a/src/i18n/languages.js +++ /dev/null @@ -1,123 +0,0 @@ -export const APP_LOCALES = { - 'en-US': 'English', - ca: 'Català', - 'zh-HANT': '中文 (Chinese Traditional)', - cs: 'Čeština', - da: 'Dansk', - nl: 'Nederlands', - fr: 'Français', - ka: 'ქართული (Georgian)', - de: 'Deutsch', - hu: 'Magyar', - id: 'Bahasa Indonesia', - ga: 'Gaeilge', - it: 'Italiano', - ja: '日本語 (Japanese)', - pl: 'Polski', - pt: 'Português', - 'pt-BR': 'Português (Brazil)', - ru: 'Русский (Russian)', - sk: 'Slovenčina', - uk: 'Українська (Ukrainian)', - 'nl-BE': 'Vlaams', - el: 'ελληνικά (Greek)', - hr: 'Hrvatski', - sr: 'Srpski', - tr: 'Türkçe', - 'zh-TW': '台語 (Chinese Taiwan)', - es: 'Español', - no: 'Norsk (Norwegian)', - be: 'белар (Belarusian)', - et: 'Eestlane', -}; - -// Hunspell compatible keys -export const SPELLCHECKER_LOCALES = { - // 'bg-BG': 'български език', - // 'ca-es': 'Català', - // 'cs-cz': 'Čeština', - // 'da-dk': 'Dansk', - // 'de-de': 'Deutsch', - // 'el-gr': 'ελληνικά (Greek)', - // 'en-gb': 'English (GB)', - // 'en-us': 'English (US)', - // 'es-es': 'Español', - // 'et-ee': 'Estonian', - // 'fa-ir': 'فارسی (Persian)', - // 'fo-fo': 'Faroese', - // 'fr-fr': 'Français', - // 'he-il': 'עברית (Hebrew)', - // 'hr-hr': 'Hrvatski jezik', - // 'hu-hu': 'Magyar', - // 'it-it': 'Italiano', - // ko: 'Korean', - // 'lt-lt': 'Lietuvių kalba', - // 'lv-lv': 'Latviešu valoda', - // 'nb-no': 'Norsk bokmål', - // 'nl-nl': 'Nederlands', - // 'pl-pl': 'Język polski', - // 'pt-br': 'Português (Brazil)', - // 'pt-pt': 'Português', - // 'ro-ro': 'Limba română', - // 'ru-ru': 'Русский (Russian)', - // 'sk-sk': 'Slovenčina', - // 'sl-si': 'Slovenski jezik', - // sr: 'Српски језик (Serbian)', - // 'sv-se': 'Svenska', - // 'ta-in': 'தமிழ் (Tamil)', - // 'tg-tg': 'Тоҷикӣ (Tajik)', - // tr: 'Türkçe', - // 'uk-ua': 'Українська (Ukrainian)', - // vi: 'Tiếng Việt', - - af: 'Afrikaans', - bg: 'български език', - ca: 'Català', - cs: 'Čeština', - cy: 'Welsh', - da: 'Dansk', - de: 'Deutsch', - el: 'ελληνικά (Greek)', - 'en-AU': 'English (Australia)', - 'en-CA': 'English (Canada)', - 'en-GB': 'English (Great Britain)', - 'en-US': 'English (United States)', - es: 'Español', - 'es-AR': 'Español (Argentina)', - 'es-ES': 'Español (España)', - 'es-MX': 'Español (Mexico)', - 'es-US': 'Español (Estados Unidos)', - et: 'Eesti', - fa: 'فارسی (Persian)', - fo: 'Føroyskt', - fr: 'Français', - he: 'עברית (Hebrew)', - hi: 'नहीं। (Hindi)', - hr: 'Hrvatski jezik', - hu: 'Magyar', - hy: 'հայերեն (Armenian)', - id: 'bahasa Indonesia', - it: 'Italiano', - ko: 'Korean', - lt: 'Lietuvis', - lv: 'Latviešu valoda', - nb: 'Norsk bokmål', - nl: 'Nederlands', - pl: 'Język polski', - 'pt-BR': 'Português (Brasil)', - 'pt-PT': 'Português (Portugal)', - ro: 'Limba română', - ru: 'Русский (Russian)', - sh: 'Srpsko hrvatski', - sk: 'Slovenčina', - sl: 'Slovenščina', - sq: 'Shqip', - sv: 'Svenska', - ta: 'தமிழ் (Tamil)', - tg: 'Тоҷикӣ (Tajik)', - tr: 'Türkçe', - uk: 'Українська (Ukrainian)', - vi: 'Tiếng Việt', -}; - -export default APP_LOCALES; diff --git a/src/i18n/languages.ts b/src/i18n/languages.ts new file mode 100644 index 000000000..e7713b42b --- /dev/null +++ b/src/i18n/languages.ts @@ -0,0 +1,123 @@ +export const APP_LOCALES = { + 'en-US': 'English', + ca: 'Català', + 'zh-HANT': '中文 (Chinese Traditional)', + cs: 'Čeština', + da: 'Dansk', + nl: 'Nederlands', + fr: 'Français', + ka: 'ქართული (Georgian)', + de: 'Deutsch', + hu: 'Magyar', + id: 'Bahasa Indonesia', + ga: 'Gaeilge', + it: 'Italiano', + ja: '日本語 (Japanese)', + pl: 'Polski', + pt: 'Português', + 'pt-BR': 'Português (Brazil)', + ru: 'Русский (Russian)', + sk: 'Slovenčina', + uk: 'Українська (Ukrainian)', + 'nl-BE': 'Vlaams', + el: 'ελληνικά (Greek)', + hr: 'Hrvatski', + sr: 'Srpski', + tr: 'Türkçe', + 'zh-TW': '台語 (Chinese Taiwan)', + es: 'Español', + no: 'Norsk (Norwegian)', + be: 'белар (Belarusian)', + et: 'Eestlane', +}; + +// Hunspell compatible keys +export const SPELLCHECKER_LOCALES = { + // 'bg-BG': 'български език', + // 'ca-es': 'Català', + // 'cs-cz': 'Čeština', + // 'da-dk': 'Dansk', + // 'de-de': 'Deutsch', + // 'el-gr': 'ελληνικά (Greek)', + // 'en-gb': 'English (GB)', + // 'en-us': 'English (US)', + // 'es-es': 'Español', + // 'et-ee': 'Estonian', + // 'fa-ir': 'فارسی (Persian)', + // 'fo-fo': 'Faroese', + // 'fr-fr': 'Français', + // 'he-il': 'עברית (Hebrew)', + // 'hr-hr': 'Hrvatski jezik', + // 'hu-hu': 'Magyar', + // 'it-it': 'Italiano', + // ko: 'Korean', + // 'lt-lt': 'Lietuvių kalba', + // 'lv-lv': 'Latviešu valoda', + // 'nb-no': 'Norsk bokmål', + // 'nl-nl': 'Nederlands', + // 'pl-pl': 'Język polski', + // 'pt-br': 'Português (Brazil)', + // 'pt-pt': 'Português', + // 'ro-ro': 'Limba română', + // 'ru-ru': 'Русский (Russian)', + // 'sk-sk': 'Slovenčina', + // 'sl-si': 'Slovenski jezik', + // sr: 'Српски језик (Serbian)', + // 'sv-se': 'Svenska', + // 'ta-in': 'தமிழ் (Tamil)', + // 'tg-tg': 'Тоҷикӣ (Tajik)', + // tr: 'Türkçe', + // 'uk-ua': 'Українська (Ukrainian)', + // vi: 'Tiếng Việt', + + af: 'Afrikaans', + bg: 'български език', + ca: 'Català', + cs: 'Čeština', + cy: 'Welsh', + da: 'Dansk', + de: 'Deutsch', + el: 'ελληνικά (Greek)', + 'en-AU': 'English (Australia)', + 'en-CA': 'English (Canada)', + 'en-GB': 'English (Great Britain)', + 'en-US': 'English (United States)', + es: 'Español', + 'es-AR': 'Español (Argentina)', + 'es-ES': 'Español (España)', + 'es-MX': 'Español (Mexico)', + 'es-US': 'Español (Estados Unidos)', + et: 'Eesti', + fa: 'فارسی (Persian)', + fo: 'Føroyskt', + fr: 'Français', + he: 'עברית (Hebrew)', + hi: 'नहीं। (Hindi)', + hr: 'Hrvatski jezik', + hu: 'Magyar', + hy: 'հայերեն (Armenian)', + id: 'bahasa Indonesia', + it: 'Italiano', + ko: 'Korean', + lt: 'Lietuvis', + lv: 'Latviešu valoda', + nb: 'Norsk bokmål', + nl: 'Nederlands', + pl: 'Język polski', + 'pt-BR': 'Português (Brasil)', + 'pt-PT': 'Português (Portugal)', + ro: 'Limba română', + ru: 'Русский (Russian)', + sh: 'Srpsko hrvatski', + sk: 'Slovenčina', + sl: 'Slovenščina', + sq: 'Shqip', + sv: 'Svenska', + ta: 'தமிழ் (Tamil)', + tg: 'Тоҷикӣ (Tajik)', + tr: 'Türkçe', + uk: 'Українська (Ukrainian)', + vi: 'Tiếng Việt', +}; + +export default APP_LOCALES; diff --git a/src/i18n/translations.js b/src/i18n/translations.js deleted file mode 100644 index 9a7dc7453..000000000 --- a/src/i18n/translations.js +++ /dev/null @@ -1,15 +0,0 @@ -/* eslint-disable global-require */ -import { APP_LOCALES } from './languages'; - -const translations = []; -for (const key of Object.keys(APP_LOCALES)) { - try { - // eslint-disable-next-line import/no-dynamic-require - const translation = require(`./locales/${key}.json`); - translations[key] = translation; - } catch { - console.warn(`Can't find translations for ${key}`); - } -} - -module.exports = translations; diff --git a/src/i18n/translations.ts b/src/i18n/translations.ts new file mode 100644 index 000000000..9a7dc7453 --- /dev/null +++ b/src/i18n/translations.ts @@ -0,0 +1,15 @@ +/* eslint-disable global-require */ +import { APP_LOCALES } from './languages'; + +const translations = []; +for (const key of Object.keys(APP_LOCALES)) { + try { + // eslint-disable-next-line import/no-dynamic-require + const translation = require(`./locales/${key}.json`); + translations[key] = translation; + } catch { + console.warn(`Can't find translations for ${key}`); + } +} + +module.exports = translations; diff --git a/src/internal-server/start.js b/src/internal-server/start.js deleted file mode 100644 index 5ccc1330e..000000000 --- a/src/internal-server/start.js +++ /dev/null @@ -1,51 +0,0 @@ -/* -|-------------------------------------------------------------------------- -| Http server -|-------------------------------------------------------------------------- -| -| This file bootstraps Adonisjs to start the HTTP server. You are free to -| customize the process of booting the http server. -| -| """ Loading ace commands """ -| At times you may want to load ace commands when starting the HTTP server. -| Same can be done by chaining `loadCommands()` method after -| -| """ Preloading files """ -| Also you can preload files by calling `preLoad('path/to/file')` method. -| Make sure to pass a relative path from the project root. -*/ - -const fold = require('@adonisjs/fold'); -const { Ignitor } = require('@adonisjs/ignitor'); -const fs = require('fs-extra'); -const path = require('path'); -const { LOCAL_HOSTNAME } = require('../config'); -const { isWindows } = require('../environment'); - -process.env.ENV_PATH = path.join(__dirname, 'env.ini'); - -module.exports = async (userPath, port) => { - const dbPath = path.join(userPath, 'server.sqlite'); - const dbTemplatePath = path.join(__dirname, 'database', 'template.sqlite'); - - if (!fs.existsSync(dbPath)) { - // Manually copy file - // We can't use copyFile here as it will cause the file to be readonly on Windows - const dbTemplate = await fs.readFile(dbTemplatePath); - await fs.writeFile(dbPath, dbTemplate); - - // Change permissions to ensure to file is not read-only - if (isWindows) { - // eslint-disable-next-line no-bitwise - fs.chmodSync(dbPath, fs.statSync(dbPath).mode | 146); - } - } - - // Note: These env vars are used by adonis as env vars - process.env.DB_PATH = dbPath; - process.env.USER_PATH = userPath; - process.env.HOST = LOCAL_HOSTNAME; - process.env.PORT = port; - - new Ignitor(fold).appRoot(__dirname).fireHttpServer().catch(console.error); // eslint-disable-line no-console -}; diff --git a/src/internal-server/start.ts b/src/internal-server/start.ts new file mode 100644 index 000000000..392f7cf41 --- /dev/null +++ b/src/internal-server/start.ts @@ -0,0 +1,51 @@ +/* +|-------------------------------------------------------------------------- +| Http server +|-------------------------------------------------------------------------- +| +| This file bootstraps Adonisjs to start the HTTP server. You are free to +| customize the process of booting the http server. +| +| """ Loading ace commands """ +| At times you may want to load ace commands when starting the HTTP server. +| Same can be done by chaining `loadCommands()` method after +| +| """ Preloading files """ +| Also you can preload files by calling `preLoad('path/to/file')` method. +| Make sure to pass a relative path from the project root. +*/ + +import fold from '@adonisjs/fold'; +import { Ignitor } from '@adonisjs/ignitor'; +import fs from 'fs-extra'; +import path from 'path'; +import { LOCAL_HOSTNAME } from '../config'; +import { isWindows } from '../environment'; + +process.env.ENV_PATH = path.join(__dirname, 'env.ini'); + +export const server = async (userPath: string, port: number) => { + const dbPath = path.join(userPath, 'server.sqlite'); + const dbTemplatePath = path.join(__dirname, 'database', 'template.sqlite'); + + if (!fs.existsSync(dbPath)) { + // Manually copy file + // We can't use copyFile here as it will cause the file to be readonly on Windows + const dbTemplate = await fs.readFile(dbTemplatePath); + await fs.writeFile(dbPath, dbTemplate); + + // Change permissions to ensure to file is not read-only + if (isWindows) { + // eslint-disable-next-line no-bitwise + fs.chmodSync(dbPath, fs.statSync(dbPath).mode | 146); + } + } + + // Note: These env vars are used by adonis as env vars + process.env.DB_PATH = dbPath; + process.env.USER_PATH = userPath; + process.env.HOST = LOCAL_HOSTNAME; + process.env.PORT = port.toString(); + + new Ignitor(fold).appRoot(__dirname).fireHttpServer().catch(console.error); +}; diff --git a/src/internal-server/test.js b/src/internal-server/test.js deleted file mode 100644 index ef85743f3..000000000 --- a/src/internal-server/test.js +++ /dev/null @@ -1,9 +0,0 @@ -const path = require('path'); -const fs = require('fs-extra'); -const server = require('./start'); - -const dummyUserFolder = path.join(__dirname, 'user_data'); - -fs.ensureDirSync(dummyUserFolder); - -server(dummyUserFolder, 45_568); diff --git a/src/internal-server/test.ts b/src/internal-server/test.ts new file mode 100644 index 000000000..437a2813b --- /dev/null +++ b/src/internal-server/test.ts @@ -0,0 +1,9 @@ +import path from 'path'; +import fs from 'fs-extra'; +import { server } from './start'; + +const dummyUserFolder = path.join(__dirname, 'user_data'); + +fs.ensureDirSync(dummyUserFolder); + +server(dummyUserFolder, 45_568); -- cgit v1.2.3-70-g09d2