From ad17ec5ccad3ceffd383f228d4529438b5a3b9a6 Mon Sep 17 00:00:00 2001 From: niu tech Date: Fri, 12 Nov 2021 23:52:58 +0100 Subject: Adjust number of columns for Split Mode (#2208) Co-authored-by: Vijay A --- src/stores/ServicesStore.js | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/stores/ServicesStore.js') diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 926ee36f0..a34390d88 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -170,6 +170,13 @@ export default class ServicesStore extends Store { }, ); + reaction( + () => this.stores.settings.app.splitColumns, + () => { + this._shareSettingsWithServiceProcess(); + }, + ); + reaction( () => this.stores.settings.app.searchEngine, () => { -- cgit v1.2.3-70-g09d2 From 8e076d4763831059573abc6fa98bd67fe3b3f3dc Mon Sep 17 00:00:00 2001 From: Adrian Klaeger Date: Sun, 14 Nov 2021 04:01:37 +0100 Subject: Fix service activation and hibernation timeout (#2224) Fixes issue #2051 --- src/stores/ServicesStore.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'src/stores/ServicesStore.js') diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index a34390d88..16deb91c5 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -587,7 +587,10 @@ export default class ServicesStore extends Store { const service = this.one(serviceId); for (const s of this.all) { - s.isActive = false; + if (s.isActive) { + s.lastUsed = Date.now(); + s.isActive = false; + } } service.isActive = true; this._awake({ serviceId: service.id }); @@ -624,12 +627,7 @@ export default class ServicesStore extends Store { this.allDisplayed.length, ); - for (const s of this.all) { - s.isActive = false; - } - this.allDisplayed[nextIndex].isActive = true; - - this._focusActiveService(); + this._setActive({ serviceId: this.allDisplayed[nextIndex].id }); } @action _setActivePrev() { @@ -639,12 +637,7 @@ export default class ServicesStore extends Store { this.allDisplayed.length, ); - for (const s of this.all) { - s.isActive = false; - } - this.allDisplayed[prevIndex].isActive = true; - - this._focusActiveService(); + this._setActive({ serviceId: this.allDisplayed[prevIndex].id }); } @action _setUnreadMessageCount({ serviceId, count }) { -- cgit v1.2.3-70-g09d2 From b37a6b07b39c8c7827052dc6fb97f490f1e0f514 Mon Sep 17 00:00:00 2001 From: Markus Hatvan Date: Thu, 18 Nov 2021 17:37:45 +0100 Subject: chore: convert various files to TS (#2246) * convert various files to TS * removed outdated docs/example-feature folder * turn off unicorn/no-empty-file * update eslint config --- .eslintrc.js | 6 + docs/example-feature/actions.js | 10 - docs/example-feature/api.js | 5 - docs/example-feature/state.js | 14 - docs/example-feature/store.js | 36 -- src/I18n.js | 42 -- src/I18n.tsx | 42 ++ src/api/server/ServerApi.js | 610 --------------------- src/api/server/ServerApi.ts | 616 ++++++++++++++++++++++ src/api/utils/auth.ts | 2 +- src/components/services/content/ServiceWebview.js | 12 +- src/components/ui/Tabs/TabItem.tsx | 4 +- src/features/communityRecipes/store.ts | 2 +- src/features/publishDebugInfo/index.js | 19 - src/features/publishDebugInfo/index.ts | 19 + src/i18n/translations.ts | 24 +- src/internal-server/database/factory.js | 1 - src/routes.js | 98 ---- src/routes.tsx | 97 ++++ src/stores/AppStore.js | 4 +- src/stores/ServicesStore.js | 56 +- src/webview/lib/RecipeWebview.js | 166 ------ src/webview/lib/RecipeWebview.ts | 177 +++++++ src/webview/lib/Userscript.js | 138 ----- src/webview/lib/Userscript.ts | 107 ++++ 25 files changed, 1118 insertions(+), 1189 deletions(-) delete mode 100644 docs/example-feature/actions.js delete mode 100644 docs/example-feature/api.js delete mode 100644 docs/example-feature/state.js delete mode 100644 docs/example-feature/store.js delete mode 100644 src/I18n.js create mode 100644 src/I18n.tsx delete mode 100644 src/api/server/ServerApi.js create mode 100644 src/api/server/ServerApi.ts delete mode 100644 src/features/publishDebugInfo/index.js create mode 100644 src/features/publishDebugInfo/index.ts delete mode 100644 src/routes.js create mode 100644 src/routes.tsx delete mode 100644 src/webview/lib/RecipeWebview.js create mode 100644 src/webview/lib/RecipeWebview.ts delete mode 100644 src/webview/lib/Userscript.js create mode 100644 src/webview/lib/Userscript.ts (limited to 'src/stores/ServicesStore.js') diff --git a/.eslintrc.js b/.eslintrc.js index b18927381..f7ca7b620 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -83,6 +83,7 @@ module.exports = { 'react/state-in-constructor': 0, 'react/static-property-placement': 0, 'react/function-component-definition': 0, + 'react/jsx-no-useless-fragment': 0, // eslint-plugin-jsx-a11y 'jsx-a11y/click-events-have-key-events': 1, 'jsx-a11y/mouse-events-have-key-events': 1, @@ -116,6 +117,8 @@ module.exports = { }, ], 'unicorn/consistent-destructuring': 0, + // INFO: Turned off due to src/internal-server/database/factory.js + 'unicorn/no-empty-file': 0, // eslint-plugin-prettier 'prettier/prettier': 1, }, @@ -167,6 +170,7 @@ module.exports = { 'react/state-in-constructor': 1, 'react/sort-comp': 0, 'react/function-component-definition': 0, + 'react/jsx-no-useless-fragment': 0, // eslint-plugin-jsx-a11y 'jsx-a11y/click-events-have-key-events': 1, 'jsx-a11y/no-static-element-interactions': 1, @@ -189,6 +193,8 @@ module.exports = { }, ], 'unicorn/consistent-destructuring': 0, + // INFO: Turned off due to src/internal-server/database/factory.js + 'unicorn/no-empty-file': 0, // eslint-plugin-prettier 'prettier/prettier': 1, }, diff --git a/docs/example-feature/actions.js b/docs/example-feature/actions.js deleted file mode 100644 index c4d49b708..000000000 --- a/docs/example-feature/actions.js +++ /dev/null @@ -1,10 +0,0 @@ -import PropTypes from 'prop-types'; -import { createActionsFromDefinitions } from '../../src/actions/lib/actions'; - -export const exampleFeatureActions = createActionsFromDefinitions({ - greet: { - name: PropTypes.string.isRequired, - }, -}, PropTypes.checkPropTypes); - -export default exampleFeatureActions; diff --git a/docs/example-feature/api.js b/docs/example-feature/api.js deleted file mode 100644 index d9c769c91..000000000 --- a/docs/example-feature/api.js +++ /dev/null @@ -1,5 +0,0 @@ -export default { - async getName() { - return Promise.resolve('Ferdi'); - }, -}; diff --git a/docs/example-feature/state.js b/docs/example-feature/state.js deleted file mode 100644 index 676717da7..000000000 --- a/docs/example-feature/state.js +++ /dev/null @@ -1,14 +0,0 @@ -import { observable } from 'mobx'; - -const defaultState = { - name: null, - isFeatureActive: false, -}; - -export const exampleFeatureState = observable(defaultState); - -export function resetState() { - Object.assign(exampleFeatureState, defaultState); -} - -export default exampleFeatureState; diff --git a/docs/example-feature/store.js b/docs/example-feature/store.js deleted file mode 100644 index 9fc86de36..000000000 --- a/docs/example-feature/store.js +++ /dev/null @@ -1,36 +0,0 @@ -import { action, observable, reaction } from 'mobx'; -import Store from '../../src/stores/lib/Store'; -import Request from '../../src/stores/lib/Request'; - -const debug = require('debug')('Ferdi:feature:EXAMPLE_FEATURE:store'); - -export class ExampleFeatureStore extends Store { - @observable getNameRequest = new Request(this.api, 'getName'); - - constructor(stores, api, actions, state) { - super(stores, api, actions); - this.state = state; - } - - setup() { - debug('fetching name from api'); - this.getNameRequest.execute(); - - // Update the name on the state when the request resolved - reaction( - () => ( - this.getNameRequest.result - ), - (name) => { - this._setName(name); - }, - ); - } - - @action _setName = (name) => { - debug('setting name', name); - this.state.name = name; - }; -} - -export default ExampleFeatureStore; diff --git a/src/I18n.js b/src/I18n.js deleted file mode 100644 index b10c5a94b..000000000 --- a/src/I18n.js +++ /dev/null @@ -1,42 +0,0 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; -import { inject, observer } from 'mobx-react'; -import { IntlProvider } from 'react-intl'; - -import { oneOrManyChildElements } from './prop-types'; -import translations from './i18n/translations'; -import UserStore from './stores/UserStore'; -import AppStore from './stores/AppStore'; - -@inject('stores') -@observer -class I18N extends Component { - componentDidUpdate() { - window['ferdi'].menu.rebuild(); - } - - render() { - const { stores, children } = this.props; - const { locale } = stores.app; - return ( - { - window['ferdi'].intl = intlProvider ? intlProvider.state.intl : null; - }} - > - {children} - - ); - } -} - -I18N.wrappedComponent.propTypes = { - stores: PropTypes.shape({ - app: PropTypes.instanceOf(AppStore).isRequired, - user: PropTypes.instanceOf(UserStore).isRequired, - }).isRequired, - children: oneOrManyChildElements.isRequired, -}; - -export default I18N; diff --git a/src/I18n.tsx b/src/I18n.tsx new file mode 100644 index 000000000..39b5273c1 --- /dev/null +++ b/src/I18n.tsx @@ -0,0 +1,42 @@ +import { Component, ReactNode } from 'react'; +import { inject, observer } from 'mobx-react'; +import { IntlProvider } from 'react-intl'; + +import { generatedTranslations } from './i18n/translations'; +import UserStore from './stores/UserStore'; +import AppStore from './stores/AppStore'; + +const translations = generatedTranslations(); + +type Props = { + stores: { + app: typeof AppStore; + user: typeof UserStore; + }; + children: ReactNode; +}; + +@inject('stores') +@observer +class I18N extends Component { + componentDidUpdate() { + window['ferdi'].menu.rebuild(); + } + + render() { + const { stores, children } = this.props; + const { locale } = stores.app; + return ( + { + window['ferdi'].intl = intlProvider ? intlProvider.state.intl : null; + }} + > + {children} + + ); + } +} + +export default I18N; diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js deleted file mode 100644 index bcc72ffdc..000000000 --- a/src/api/server/ServerApi.js +++ /dev/null @@ -1,610 +0,0 @@ -/* eslint-disable import/no-import-module-exports */ -/* eslint-disable global-require */ -import { join } from 'path'; -import tar from 'tar'; -import { - readdirSync, - statSync, - writeFileSync, - copySync, - ensureDirSync, - pathExistsSync, - readJsonSync, - removeSync, -} from 'fs-extra'; -import fetch from 'electron-fetch'; - -import ServiceModel from '../../models/Service'; -import RecipePreviewModel from '../../models/RecipePreview'; -import RecipeModel from '../../models/Recipe'; -import UserModel from '../../models/User'; - -import { sleep } from '../../helpers/async-helpers'; - -import { SERVER_NOT_LOADED } from '../../config'; -import { userDataRecipesPath, userDataPath } from '../../environment-remote'; -import { asarRecipesPath } from '../../helpers/asar-helpers'; -import apiBase from '../apiBase'; -import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; - -import { - getRecipeDirectory, - getDevRecipeDirectory, - loadRecipeConfig, -} from '../../helpers/recipe-helpers'; - -import { removeServicePartitionDirectory } from '../../helpers/service-helpers'; - -const debug = require('debug')('Ferdi:ServerApi'); - -module.paths.unshift(getDevRecipeDirectory(), getRecipeDirectory()); - -export default class ServerApi { - recipePreviews = []; - - recipes = []; - - // User - async login(email, passwordHash) { - const request = await sendAuthRequest( - `${apiBase()}/auth/login`, - { - method: 'POST', - headers: { - Authorization: `Basic ${window.btoa(`${email}:${passwordHash}`)}`, - }, - }, - false, - ); - if (!request.ok) { - throw request; - } - const u = await request.json(); - - debug('ServerApi::login resolves', u); - return u.token; - } - - async signup(data) { - const request = await sendAuthRequest( - `${apiBase()}/auth/signup`, - { - method: 'POST', - body: JSON.stringify(data), - }, - false, - ); - if (!request.ok) { - throw request; - } - const u = await request.json(); - - debug('ServerApi::signup resolves', u); - return u.token; - } - - async inviteUser(data) { - const request = await sendAuthRequest(`${apiBase()}/invite`, { - method: 'POST', - body: JSON.stringify(data), - }); - if (!request.ok) { - throw request; - } - - debug('ServerApi::inviteUser'); - return true; - } - - async retrievePassword(email) { - const request = await sendAuthRequest( - `${apiBase()}/auth/password`, - { - method: 'POST', - body: JSON.stringify({ - email, - }), - }, - false, - ); - if (!request.ok) { - throw request; - } - const r = await request.json(); - - debug('ServerApi::retrievePassword'); - return r; - } - - async userInfo() { - if (apiBase() === SERVER_NOT_LOADED) { - throw new Error('Server not loaded'); - } - - const request = await sendAuthRequest(`${apiBase()}/me`); - if (!request.ok) { - throw request; - } - const data = await request.json(); - - const user = new UserModel(data); - debug('ServerApi::userInfo resolves', user); - - return user; - } - - async updateUserInfo(data) { - const request = await sendAuthRequest(`${apiBase()}/me`, { - method: 'PUT', - body: JSON.stringify(data), - }); - if (!request.ok) { - throw request; - } - const updatedData = await request.json(); - - const user = Object.assign(updatedData, { - data: new UserModel(updatedData.data), - }); - debug('ServerApi::updateUserInfo resolves', user); - return user; - } - - async deleteAccount() { - const request = await sendAuthRequest(`${apiBase()}/me`, { - method: 'DELETE', - }); - if (!request.ok) { - throw request; - } - const data = await request.json(); - - debug('ServerApi::deleteAccount resolves', data); - return data; - } - - // Services - async getServices() { - if (apiBase() === SERVER_NOT_LOADED) { - throw new Error('Server not loaded'); - } - - const request = await sendAuthRequest(`${apiBase()}/me/services`); - if (!request.ok) { - throw request; - } - const data = await request.json(); - - const services = await this._mapServiceModels(data); - const filteredServices = services.filter(service => !!service); - debug('ServerApi::getServices resolves', filteredServices); - return filteredServices; - } - - async createService(recipeId, data) { - const request = await sendAuthRequest(`${apiBase()}/service`, { - method: 'POST', - body: JSON.stringify({ recipeId, ...data }), - }); - if (!request.ok) { - throw request; - } - const serviceData = await request.json(); - - if (data.iconFile) { - const iconData = await this.uploadServiceIcon( - serviceData.data.id, - data.iconFile, - ); - - serviceData.data = iconData; - } - - const service = Object.assign(serviceData, { - data: await this._prepareServiceModel(serviceData.data), - }); - - debug('ServerApi::createService resolves', service); - return service; - } - - async updateService(serviceId, rawData) { - const data = rawData; - - if (data.iconFile) { - await this.uploadServiceIcon(serviceId, data.iconFile); - } - - const request = await sendAuthRequest(`${apiBase()}/service/${serviceId}`, { - method: 'PUT', - body: JSON.stringify(data), - }); - - if (!request.ok) { - throw request; - } - - const serviceData = await request.json(); - - const service = Object.assign(serviceData, { - data: await this._prepareServiceModel(serviceData.data), - }); - - debug('ServerApi::updateService resolves', service); - return service; - } - - async uploadServiceIcon(serviceId, icon) { - const formData = new FormData(); - formData.append('icon', icon); - - const requestData = prepareAuthRequest({ - method: 'PUT', - body: formData, - }); - - delete requestData.headers['Content-Type']; - - const request = await window.fetch( - `${apiBase()}/service/${serviceId}`, - requestData, - ); - - if (!request.ok) { - throw request; - } - - const serviceData = await request.json(); - - return serviceData.data; - } - - async reorderService(data) { - const request = await sendAuthRequest(`${apiBase()}/service/reorder`, { - method: 'PUT', - body: JSON.stringify(data), - }); - if (!request.ok) { - throw request; - } - const serviceData = await request.json(); - debug('ServerApi::reorderService resolves', serviceData); - return serviceData; - } - - async deleteService(id) { - const request = await sendAuthRequest(`${apiBase()}/service/${id}`, { - method: 'DELETE', - }); - if (!request.ok) { - throw request; - } - const data = await request.json(); - - removeServicePartitionDirectory(id, true); - - debug('ServerApi::deleteService resolves', data); - return data; - } - - // Features - async getDefaultFeatures() { - const request = await sendAuthRequest(`${apiBase()}/features/default`); - if (!request.ok) { - throw request; - } - const data = await request.json(); - - const features = data; - debug('ServerApi::getDefaultFeatures resolves', features); - return features; - } - - async getFeatures() { - if (apiBase() === SERVER_NOT_LOADED) { - throw new Error('Server not loaded'); - } - - const request = await sendAuthRequest(`${apiBase()}/features`); - if (!request.ok) { - throw request; - } - const data = await request.json(); - - const features = data; - debug('ServerApi::getFeatures resolves', features); - return features; - } - - // Recipes - async getInstalledRecipes() { - const recipesDirectory = getRecipeDirectory(); - const paths = readdirSync(recipesDirectory).filter( - file => - statSync(join(recipesDirectory, file)).isDirectory() && - file !== 'temp' && - file !== 'dev', - ); - - this.recipes = paths - .map(id => { - // eslint-disable-next-line import/no-dynamic-require - const Recipe = require(id)(RecipeModel); - return new Recipe(loadRecipeConfig(id)); - }) - .filter(recipe => recipe.id); - - // eslint-disable-next-line unicorn/prefer-spread - this.recipes = this.recipes.concat(this._getDevRecipes()); - - debug('StubServerApi::getInstalledRecipes resolves', this.recipes); - return this.recipes; - } - - async getRecipeUpdates(recipeVersions) { - const request = await sendAuthRequest(`${apiBase()}/recipes/update`, { - method: 'POST', - body: JSON.stringify(recipeVersions), - }); - if (!request.ok) { - throw request; - } - const recipes = await request.json(); - debug('ServerApi::getRecipeUpdates resolves', recipes); - return recipes; - } - - // Recipes Previews - async getRecipePreviews() { - const request = await sendAuthRequest(`${apiBase()}/recipes`); - if (!request.ok) throw request; - const data = await request.json(); - const recipePreviews = this._mapRecipePreviewModel(data); - debug('ServerApi::getRecipes resolves', recipePreviews); - return recipePreviews; - } - - async getFeaturedRecipePreviews() { - // TODO: If we are hitting the internal-server, we need to return an empty list, else we can hit the remote server and get the data - const request = await sendAuthRequest(`${apiBase()}/recipes/popular`); - if (!request.ok) throw request; - - const data = await request.json(); - const recipePreviews = this._mapRecipePreviewModel(data); - debug('ServerApi::getFeaturedRecipes resolves', recipePreviews); - return recipePreviews; - } - - async searchRecipePreviews(needle) { - const url = `${apiBase()}/recipes/search?needle=${needle}`; - const request = await sendAuthRequest(url); - if (!request.ok) throw request; - - const data = await request.json(); - const recipePreviews = this._mapRecipePreviewModel(data); - debug('ServerApi::searchRecipePreviews resolves', recipePreviews); - return recipePreviews; - } - - async getRecipePackage(recipeId) { - try { - const recipesDirectory = userDataRecipesPath(); - const recipeTempDirectory = join(recipesDirectory, 'temp', recipeId); - const tempArchivePath = join(recipeTempDirectory, 'recipe.tar.gz'); - - const internalRecipeFile = asarRecipesPath(`${recipeId}.tar.gz`); - - ensureDirSync(recipeTempDirectory); - - let archivePath; - - if (pathExistsSync(internalRecipeFile)) { - debug('[ServerApi::getRecipePackage] Using internal recipe file'); - archivePath = internalRecipeFile; - } else { - debug('[ServerApi::getRecipePackage] Downloading recipe from server'); - archivePath = tempArchivePath; - - const packageUrl = `${apiBase()}/recipes/download/${recipeId}`; - - const res = await fetch(packageUrl); - debug('Recipe downloaded', recipeId); - const buffer = await res.buffer(); - writeFileSync(archivePath, buffer); - } - debug(archivePath); - - await sleep(10); - - await tar.x({ - file: archivePath, - cwd: recipeTempDirectory, - preservePaths: true, - unlink: true, - preserveOwner: false, - onwarn: x => debug('warn', recipeId, x), - }); - - await sleep(10); - - const { id } = readJsonSync(join(recipeTempDirectory, 'package.json')); - const recipeDirectory = join(recipesDirectory, id); - copySync(recipeTempDirectory, recipeDirectory); - removeSync(recipeTempDirectory); - removeSync(join(recipesDirectory, recipeId, 'recipe.tar.gz')); - - return id; - } catch (error) { - console.error(error); - - return false; - } - } - - // Health Check - async healthCheck() { - if (apiBase() === SERVER_NOT_LOADED) { - throw new Error('Server not loaded'); - } - - const request = await sendAuthRequest( - `${apiBase(false)}/health`, - { - method: 'GET', - }, - false, - ); - if (!request.ok) { - throw request; - } - debug('ServerApi::healthCheck resolves'); - } - - async getLegacyServices() { - const file = userDataPath('settings', 'services.json'); - - try { - const config = readJsonSync(file); - - if (Object.prototype.hasOwnProperty.call(config, 'services')) { - const services = await Promise.all( - config.services.map(async s => { - const service = s; - const request = await sendAuthRequest( - `${apiBase()}/recipes/${s.service}`, - ); - - if (request.status === 200) { - const data = await request.json(); - service.recipe = new RecipePreviewModel(data); - } - - return service; - }), - ); - - debug('ServerApi::getLegacyServices resolves', services); - return services; - } - } catch { - console.error('ServerApi::getLegacyServices no config found'); - } - - return []; - } - - // Helper - async _mapServiceModels(services) { - const recipes = services.map(s => s.recipeId); - await this._bulkRecipeCheck(recipes); - /* eslint-disable no-return-await */ - return Promise.all( - services.map(async service => await this._prepareServiceModel(service)), - ); - /* eslint-enable no-return-await */ - } - - async _prepareServiceModel(service) { - let recipe; - try { - recipe = this.recipes.find(r => r.id === service.recipeId); - - if (!recipe) { - console.warn(`Recipe ${service.recipeId} not loaded`); - return null; - } - - return new ServiceModel(service, recipe); - } catch (error) { - debug(error); - return null; - } - } - - async _bulkRecipeCheck(unfilteredRecipes) { - // Filter recipe duplicates as we don't need to download 3 Slack recipes - const recipes = unfilteredRecipes.filter( - (elem, pos, arr) => arr.indexOf(elem) === pos, - ); - - return Promise.all( - recipes.map(async recipeId => { - let recipe = this.recipes.find(r => r.id === recipeId); - - if (!recipe) { - console.warn( - `Recipe '${recipeId}' not installed, trying to fetch from server`, - ); - - await this.getRecipePackage(recipeId); - - debug('Rerun ServerAPI::getInstalledRecipes'); - await this.getInstalledRecipes(); - - recipe = this.recipes.find(r => r.id === recipeId); - - if (!recipe) { - console.warn(`Could not load recipe ${recipeId}`); - return null; - } - } - - return recipe; - }), - ).catch(error => console.error("Can't load recipe", error)); - } - - _mapRecipePreviewModel(recipes) { - return recipes - .map(recipe => { - try { - return new RecipePreviewModel(recipe); - } catch (error) { - console.error(error); - return null; - } - }) - .filter(recipe => recipe !== null); - } - - _getDevRecipes() { - const recipesDirectory = getDevRecipeDirectory(); - try { - const paths = readdirSync(recipesDirectory).filter( - file => - statSync(join(recipesDirectory, file)).isDirectory() && - file !== 'temp', - ); - - const recipes = paths - .map(id => { - let Recipe; - try { - // eslint-disable-next-line import/no-dynamic-require - Recipe = require(id)(RecipeModel); - return new Recipe(loadRecipeConfig(id)); - } catch (error) { - console.error(error); - } - - return false; - }) - .filter(recipe => recipe.id) - .map(data => { - const recipe = data; - - recipe.icons = { - svg: `${recipe.path}/icon.svg`, - }; - recipe.local = true; - - return data; - }); - - return recipes; - } catch { - debug('Could not load dev recipes'); - return false; - } - } -} diff --git a/src/api/server/ServerApi.ts b/src/api/server/ServerApi.ts new file mode 100644 index 000000000..2fd1a8d0d --- /dev/null +++ b/src/api/server/ServerApi.ts @@ -0,0 +1,616 @@ +/* eslint-disable import/no-import-module-exports */ +/* eslint-disable global-require */ +import { join } from 'path'; +import tar from 'tar'; +import { + readdirSync, + statSync, + writeFileSync, + copySync, + ensureDirSync, + pathExistsSync, + readJsonSync, + removeSync, + PathOrFileDescriptor, +} from 'fs-extra'; +import fetch from 'electron-fetch'; + +import ServiceModel from '../../models/Service'; +import RecipePreviewModel from '../../models/RecipePreview'; +import RecipeModel from '../../models/Recipe'; +import UserModel from '../../models/User'; + +import { sleep } from '../../helpers/async-helpers'; + +import { SERVER_NOT_LOADED } from '../../config'; +import { userDataRecipesPath, userDataPath } from '../../environment-remote'; +import { asarRecipesPath } from '../../helpers/asar-helpers'; +import apiBase from '../apiBase'; +import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; + +import { + getRecipeDirectory, + getDevRecipeDirectory, + loadRecipeConfig, +} from '../../helpers/recipe-helpers'; + +import { removeServicePartitionDirectory } from '../../helpers/service-helpers'; + +const debug = require('debug')('Ferdi:ServerApi'); + +module.paths.unshift(getDevRecipeDirectory(), getRecipeDirectory()); + +export default class ServerApi { + recipePreviews: any[] = []; + + recipes: any[] = []; + + // User + async login(email: string, passwordHash: string) { + const request = await sendAuthRequest( + `${apiBase()}/auth/login`, + { + method: 'POST', + headers: { + Authorization: `Basic ${window.btoa(`${email}:${passwordHash}`)}`, + }, + }, + false, + ); + if (!request.ok) { + throw new Error(request.statusText); + } + const u = await request.json(); + + debug('ServerApi::login resolves', u); + return u.token; + } + + async signup(data: any) { + const request = await sendAuthRequest( + `${apiBase()}/auth/signup`, + { + method: 'POST', + body: JSON.stringify(data), + }, + false, + ); + if (!request.ok) { + throw new Error(request.statusText); + } + const u = await request.json(); + + debug('ServerApi::signup resolves', u); + return u.token; + } + + async inviteUser(data: any) { + const request = await sendAuthRequest(`${apiBase()}/invite`, { + method: 'POST', + body: JSON.stringify(data), + }); + if (!request.ok) { + throw new Error(request.statusText); + } + + debug('ServerApi::inviteUser'); + return true; + } + + async retrievePassword(email: string) { + const request = await sendAuthRequest( + `${apiBase()}/auth/password`, + { + method: 'POST', + body: JSON.stringify({ + email, + }), + }, + false, + ); + if (!request.ok) { + throw new Error(request.statusText); + } + const r = await request.json(); + + debug('ServerApi::retrievePassword'); + return r; + } + + async userInfo() { + if (apiBase() === SERVER_NOT_LOADED) { + throw new Error('Server not loaded'); + } + + const request = await sendAuthRequest(`${apiBase()}/me`); + if (!request.ok) { + throw new Error(request.statusText); + } + const data = await request.json(); + + const user = new UserModel(data); + debug('ServerApi::userInfo resolves', user); + + return user; + } + + async updateUserInfo(data: any) { + const request = await sendAuthRequest(`${apiBase()}/me`, { + method: 'PUT', + body: JSON.stringify(data), + }); + if (!request.ok) { + throw new Error(request.statusText); + } + const updatedData = await request.json(); + + const user = Object.assign(updatedData, { + data: new UserModel(updatedData.data), + }); + debug('ServerApi::updateUserInfo resolves', user); + return user; + } + + async deleteAccount() { + const request = await sendAuthRequest(`${apiBase()}/me`, { + method: 'DELETE', + }); + if (!request.ok) { + throw new Error(request.statusText); + } + const data = await request.json(); + + debug('ServerApi::deleteAccount resolves', data); + return data; + } + + // Services + async getServices() { + if (apiBase() === SERVER_NOT_LOADED) { + throw new Error('Server not loaded'); + } + + const request = await sendAuthRequest(`${apiBase()}/me/services`); + if (!request.ok) { + throw new Error(request.statusText); + } + const data = await request.json(); + + const services = await this._mapServiceModels(data); + const filteredServices = services.filter(service => !!service); + debug('ServerApi::getServices resolves', filteredServices); + return filteredServices; + } + + async createService(recipeId: string, data: { iconFile: any }) { + const request = await sendAuthRequest(`${apiBase()}/service`, { + method: 'POST', + body: JSON.stringify({ recipeId, ...data }), + }); + if (!request.ok) { + throw new Error(request.statusText); + } + const serviceData = await request.json(); + + if (data.iconFile) { + const iconData = await this.uploadServiceIcon( + serviceData.data.id, + data.iconFile, + ); + + serviceData.data = iconData; + } + + const service = Object.assign(serviceData, { + data: await this._prepareServiceModel(serviceData.data), + }); + + debug('ServerApi::createService resolves', service); + return service; + } + + async updateService(serviceId: string, rawData: any) { + const data = rawData; + + if (data.iconFile) { + await this.uploadServiceIcon(serviceId, data.iconFile); + } + + const request = await sendAuthRequest(`${apiBase()}/service/${serviceId}`, { + method: 'PUT', + body: JSON.stringify(data), + }); + + if (!request.ok) { + throw new Error(request.statusText); + } + + const serviceData = await request.json(); + + const service = Object.assign(serviceData, { + data: await this._prepareServiceModel(serviceData.data), + }); + + debug('ServerApi::updateService resolves', service); + return service; + } + + async uploadServiceIcon(serviceId: string, icon: string | Blob) { + const formData = new FormData(); + formData.append('icon', icon); + + const requestData = prepareAuthRequest({ + method: 'PUT', + // @ts-expect-error Argument of type '{ method: string; body: FormData; }' is not assignable to parameter of type '{ method: string; }'. + body: formData, + }); + + delete requestData.headers['Content-Type']; + + const request = await window.fetch( + `${apiBase()}/service/${serviceId}`, + // @ts-expect-error Argument of type '{ method: string; } & { mode: string; headers: any; }' is not assignable to parameter of type 'RequestInit | undefined'. + requestData, + ); + + if (!request.ok) { + throw new Error(request.statusText); + } + + const serviceData = await request.json(); + + return serviceData.data; + } + + async reorderService(data: any) { + const request = await sendAuthRequest(`${apiBase()}/service/reorder`, { + method: 'PUT', + body: JSON.stringify(data), + }); + if (!request.ok) { + throw new Error(request.statusText); + } + const serviceData = await request.json(); + debug('ServerApi::reorderService resolves', serviceData); + return serviceData; + } + + async deleteService(id: string) { + const request = await sendAuthRequest(`${apiBase()}/service/${id}`, { + method: 'DELETE', + }); + if (!request.ok) { + throw new Error(request.statusText); + } + const data = await request.json(); + + removeServicePartitionDirectory(id, true); + + debug('ServerApi::deleteService resolves', data); + return data; + } + + // Features + async getDefaultFeatures() { + const request = await sendAuthRequest(`${apiBase()}/features/default`); + if (!request.ok) { + throw new Error(request.statusText); + } + const data = await request.json(); + + const features = data; + debug('ServerApi::getDefaultFeatures resolves', features); + return features; + } + + async getFeatures() { + if (apiBase() === SERVER_NOT_LOADED) { + throw new Error('Server not loaded'); + } + + const request = await sendAuthRequest(`${apiBase()}/features`); + if (!request.ok) { + throw new Error(request.statusText); + } + const data = await request.json(); + + const features = data; + debug('ServerApi::getFeatures resolves', features); + return features; + } + + // Recipes + async getInstalledRecipes() { + const recipesDirectory = getRecipeDirectory(); + const paths = readdirSync(recipesDirectory).filter( + file => + statSync(join(recipesDirectory, file)).isDirectory() && + file !== 'temp' && + file !== 'dev', + ); + + this.recipes = paths + .map(id => { + // eslint-disable-next-line import/no-dynamic-require + const Recipe = require(id)(RecipeModel); + return new Recipe(loadRecipeConfig(id)); + }) + .filter(recipe => recipe.id); + + // eslint-disable-next-line unicorn/prefer-spread + this.recipes = this.recipes.concat(this._getDevRecipes()); + + debug('StubServerApi::getInstalledRecipes resolves', this.recipes); + return this.recipes; + } + + async getRecipeUpdates(recipeVersions: any) { + const request = await sendAuthRequest(`${apiBase()}/recipes/update`, { + method: 'POST', + body: JSON.stringify(recipeVersions), + }); + if (!request.ok) { + throw new Error(request.statusText); + } + const recipes = await request.json(); + debug('ServerApi::getRecipeUpdates resolves', recipes); + return recipes; + } + + // Recipes Previews + async getRecipePreviews() { + const request = await sendAuthRequest(`${apiBase()}/recipes`); + if (!request.ok) throw new Error(request.statusText); + const data = await request.json(); + const recipePreviews = this._mapRecipePreviewModel(data); + debug('ServerApi::getRecipes resolves', recipePreviews); + return recipePreviews; + } + + async getFeaturedRecipePreviews() { + // TODO: If we are hitting the internal-server, we need to return an empty list, else we can hit the remote server and get the data + const request = await sendAuthRequest(`${apiBase()}/recipes/popular`); + if (!request.ok) throw new Error(request.statusText); + + const data = await request.json(); + const recipePreviews = this._mapRecipePreviewModel(data); + debug('ServerApi::getFeaturedRecipes resolves', recipePreviews); + return recipePreviews; + } + + async searchRecipePreviews(needle: string) { + const url = `${apiBase()}/recipes/search?needle=${needle}`; + const request = await sendAuthRequest(url); + if (!request.ok) throw new Error(request.statusText); + + const data = await request.json(); + const recipePreviews = this._mapRecipePreviewModel(data); + debug('ServerApi::searchRecipePreviews resolves', recipePreviews); + return recipePreviews; + } + + async getRecipePackage(recipeId: string) { + try { + const recipesDirectory = userDataRecipesPath(); + const recipeTempDirectory = join(recipesDirectory, 'temp', recipeId); + const tempArchivePath = join(recipeTempDirectory, 'recipe.tar.gz'); + + const internalRecipeFile = asarRecipesPath(`${recipeId}.tar.gz`); + + ensureDirSync(recipeTempDirectory); + + let archivePath: PathOrFileDescriptor; + + if (pathExistsSync(internalRecipeFile)) { + debug('[ServerApi::getRecipePackage] Using internal recipe file'); + archivePath = internalRecipeFile; + } else { + debug('[ServerApi::getRecipePackage] Downloading recipe from server'); + archivePath = tempArchivePath; + + const packageUrl = `${apiBase()}/recipes/download/${recipeId}`; + + const res = await fetch(packageUrl); + debug('Recipe downloaded', recipeId); + const buffer = await res.buffer(); + writeFileSync(archivePath, buffer); + } + debug(archivePath); + + await sleep(10); + + // @ts-expect-error No overload matches this call. + await tar.x({ + file: archivePath, + cwd: recipeTempDirectory, + preservePaths: true, + unlink: true, + preserveOwner: false, + onwarn: x => debug('warn', recipeId, x), + }); + + await sleep(10); + + const { id } = readJsonSync(join(recipeTempDirectory, 'package.json')); + const recipeDirectory = join(recipesDirectory, id); + copySync(recipeTempDirectory, recipeDirectory); + removeSync(recipeTempDirectory); + removeSync(join(recipesDirectory, recipeId, 'recipe.tar.gz')); + + return id; + } catch (error) { + console.error(error); + + return false; + } + } + + // Health Check + async healthCheck() { + if (apiBase() === SERVER_NOT_LOADED) { + throw new Error('Server not loaded'); + } + + const request = await sendAuthRequest( + `${apiBase(false)}/health`, + { + method: 'GET', + }, + false, + ); + if (!request.ok) { + throw new Error(request.statusText); + } + debug('ServerApi::healthCheck resolves'); + } + + async getLegacyServices() { + const file = userDataPath('settings', 'services.json'); + + try { + const config = readJsonSync(file); + + if (Object.prototype.hasOwnProperty.call(config, 'services')) { + const services = await Promise.all( + config.services.map(async (s: { service: any }) => { + const service = s; + const request = await sendAuthRequest( + `${apiBase()}/recipes/${s.service}`, + ); + + if (request.status === 200) { + const data = await request.json(); + // @ts-expect-error Property 'recipe' does not exist on type '{ service: any; }'. + service.recipe = new RecipePreviewModel(data); + } + + return service; + }), + ); + + debug('ServerApi::getLegacyServices resolves', services); + return services; + } + } catch { + console.error('ServerApi::getLegacyServices no config found'); + } + + return []; + } + + // Helper + async _mapServiceModels(services: any[]) { + const recipes = services.map((s: { recipeId: string }) => s.recipeId); + await this._bulkRecipeCheck(recipes); + /* eslint-disable no-return-await */ + return Promise.all( + services.map(async (service: any) => this._prepareServiceModel(service)), + ); + /* eslint-enable no-return-await */ + } + + async _prepareServiceModel(service: { recipeId: string }) { + let recipe: undefined; + try { + recipe = this.recipes.find(r => r.id === service.recipeId); + + if (!recipe) { + console.warn(`Recipe ${service.recipeId} not loaded`); + return null; + } + + return new ServiceModel(service, recipe); + } catch (error) { + debug(error); + return null; + } + } + + async _bulkRecipeCheck(unfilteredRecipes: any[]) { + // Filter recipe duplicates as we don't need to download 3 Slack recipes + const recipes = unfilteredRecipes.filter( + (elem: any, pos: number, arr: string | any[]) => + arr.indexOf(elem) === pos, + ); + + return Promise.all( + recipes.map(async (recipeId: string) => { + let recipe = this.recipes.find(r => r.id === recipeId); + + if (!recipe) { + console.warn( + `Recipe '${recipeId}' not installed, trying to fetch from server`, + ); + + await this.getRecipePackage(recipeId); + + debug('Rerun ServerAPI::getInstalledRecipes'); + await this.getInstalledRecipes(); + + recipe = this.recipes.find(r => r.id === recipeId); + + if (!recipe) { + console.warn(`Could not load recipe ${recipeId}`); + return null; + } + } + + return recipe; + }), + ).catch(error => console.error("Can't load recipe", error)); + } + + _mapRecipePreviewModel(recipes: any[]) { + return recipes + .map(recipe => { + try { + return new RecipePreviewModel(recipe); + } catch (error) { + console.error(error); + return null; + } + }) + .filter(recipe => recipe !== null); + } + + _getDevRecipes() { + const recipesDirectory = getDevRecipeDirectory(); + try { + const paths = readdirSync(recipesDirectory).filter( + file => + statSync(join(recipesDirectory, file)).isDirectory() && + file !== 'temp', + ); + + const recipes = paths + .map(id => { + let Recipe; + try { + // eslint-disable-next-line import/no-dynamic-require + Recipe = require(id)(RecipeModel); + return new Recipe(loadRecipeConfig(id)); + } catch (error) { + console.error(error); + } + + return false; + }) + .filter(recipe => recipe.id) + .map(data => { + const recipe = data; + + recipe.icons = { + svg: `${recipe.path}/icon.svg`, + }; + recipe.local = true; + + return data; + }); + + return recipes; + } catch { + debug('Could not load dev recipes'); + return false; + } + } +} diff --git a/src/api/utils/auth.ts b/src/api/utils/auth.ts index 98295d1a4..899881e88 100644 --- a/src/api/utils/auth.ts +++ b/src/api/utils/auth.ts @@ -31,7 +31,7 @@ export const prepareAuthRequest = ( export const sendAuthRequest = ( url: RequestInfo, - options: { method: string } | undefined, + options?: { method: string; headers?: any; body?: any }, auth?: boolean, ) => // @ts-expect-error Argument of type '{ method: string; } & { mode: string; headers: any; }' is not assignable to parameter of type 'RequestInit | undefined'. diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index 187785f82..c70494edd 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js @@ -31,11 +31,13 @@ class ServiceWebview extends Component { debug('Service logged a message:', e.message); }); this.webview.view.addEventListener('did-navigate', () => { - document.title = `Ferdi - ${this.props.service.name} ${ - this.props.service.dialogTitle - ? ` - ${this.props.service.dialogTitle}` - : '' - } ${`- ${this.props.service._webview.getTitle()}`}`; + if (this.props.service._webview) { + document.title = `Ferdi - ${this.props.service.name} ${ + this.props.service.dialogTitle + ? ` - ${this.props.service.dialogTitle}` + : '' + } ${`- ${this.props.service._webview.getTitle()}`}`; + } }); } }, diff --git a/src/components/ui/Tabs/TabItem.tsx b/src/components/ui/Tabs/TabItem.tsx index 81ea0ea2b..9fcc3c41e 100644 --- a/src/components/ui/Tabs/TabItem.tsx +++ b/src/components/ui/Tabs/TabItem.tsx @@ -1,3 +1 @@ -export const TabItem = ({ children }) => { - children; -}; +export const TabItem = ({ children }) => <>{children}; diff --git a/src/features/communityRecipes/store.ts b/src/features/communityRecipes/store.ts index a8d358ba0..c7a51c311 100644 --- a/src/features/communityRecipes/store.ts +++ b/src/features/communityRecipes/store.ts @@ -26,7 +26,7 @@ export class CommunityRecipesStore extends FeatureStore { (recipePreview: { isDevRecipe: boolean; author: any[] }) => { // TODO: Need to figure out if this is even necessary/used recipePreview.isDevRecipe = !!recipePreview.author.some( - (author: { email: any }) => + (author: { email: string }) => author.email === this.stores.user.data.email, ); diff --git a/src/features/publishDebugInfo/index.js b/src/features/publishDebugInfo/index.js deleted file mode 100644 index 43841b530..000000000 --- a/src/features/publishDebugInfo/index.js +++ /dev/null @@ -1,19 +0,0 @@ -import { state as ModalState } from './store'; - -export { default as Component } from './Component'; - -const state = ModalState; -const debug = require('debug')('Ferdi:feature:publishDebugInfo'); - -export default function initialize() { - debug('Initialize publishDebugInfo feature'); - - function showModal() { - state.isModalVisible = true; - } - - window['ferdi'].features.publishDebugInfo = { - state, - showModal, - }; -} diff --git a/src/features/publishDebugInfo/index.ts b/src/features/publishDebugInfo/index.ts new file mode 100644 index 000000000..43841b530 --- /dev/null +++ b/src/features/publishDebugInfo/index.ts @@ -0,0 +1,19 @@ +import { state as ModalState } from './store'; + +export { default as Component } from './Component'; + +const state = ModalState; +const debug = require('debug')('Ferdi:feature:publishDebugInfo'); + +export default function initialize() { + debug('Initialize publishDebugInfo feature'); + + function showModal() { + state.isModalVisible = true; + } + + window['ferdi'].features.publishDebugInfo = { + state, + showModal, + }; +} diff --git a/src/i18n/translations.ts b/src/i18n/translations.ts index cc5ecf83a..9b23497e1 100644 --- a/src/i18n/translations.ts +++ b/src/i18n/translations.ts @@ -1,16 +1,16 @@ -/* eslint-disable import/no-import-module-exports */ /* 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}`); +export const generatedTranslations = () => { + 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; + return translations; +}; diff --git a/src/internal-server/database/factory.js b/src/internal-server/database/factory.js index 8cd45a80d..8534fc20a 100644 --- a/src/internal-server/database/factory.js +++ b/src/internal-server/database/factory.js @@ -1,4 +1,3 @@ -/* eslint-disable unicorn/no-empty-file */ /* |-------------------------------------------------------------------------- | Factory diff --git a/src/routes.js b/src/routes.js deleted file mode 100644 index 9891e5d43..000000000 --- a/src/routes.js +++ /dev/null @@ -1,98 +0,0 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; -import { inject, observer } from 'mobx-react'; -import { Router, Route, IndexRedirect } from 'react-router'; - -import AppLayoutContainer from './containers/layout/AppLayoutContainer'; -import SettingsWindow from './containers/settings/SettingsWindow'; -import RecipesScreen from './containers/settings/RecipesScreen'; -import ServicesScreen from './containers/settings/ServicesScreen'; -import EditServiceScreen from './containers/settings/EditServiceScreen'; -import AccountScreen from './containers/settings/AccountScreen'; -import TeamScreen from './containers/settings/TeamScreen'; -import EditUserScreen from './containers/settings/EditUserScreen'; -import EditSettingsScreen from './containers/settings/EditSettingsScreen'; -import InviteSettingsScreen from './containers/settings/InviteScreen'; -import SupportFerdiScreen from './containers/settings/SupportScreen'; -import WelcomeScreen from './containers/auth/WelcomeScreen'; -import LoginScreen from './containers/auth/LoginScreen'; -import LockedScreen from './containers/auth/LockedScreen'; -import PasswordScreen from './containers/auth/PasswordScreen'; -import ChangeServerScreen from './containers/auth/ChangeServerScreen'; -import SignupScreen from './containers/auth/SignupScreen'; -import ImportScreen from './containers/auth/ImportScreen'; -import SetupAssistentScreen from './containers/auth/SetupAssistantScreen'; -import InviteScreen from './containers/auth/InviteScreen'; -import AuthLayoutContainer from './containers/auth/AuthLayoutContainer'; -import WorkspacesScreen from './features/workspaces/containers/WorkspacesScreen'; -import EditWorkspaceScreen from './features/workspaces/containers/EditWorkspaceScreen'; -import { WORKSPACES_ROUTES } from './features/workspaces/constants'; - -import SettingsStore from './stores/SettingsStore'; - -@inject('stores', 'actions') -@observer -class Routes extends Component { - render() { - const { locked } = this.props.stores.settings.app; - - const { history } = this.props; - - if (locked) { - return ; - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); - } -} - -Routes.wrappedComponent.propTypes = { - stores: PropTypes.shape({ - settings: PropTypes.instanceOf(SettingsStore).isRequired, - }).isRequired, - history: PropTypes.any.isRequired, -}; - -export default Routes; diff --git a/src/routes.tsx b/src/routes.tsx new file mode 100644 index 000000000..569da06a7 --- /dev/null +++ b/src/routes.tsx @@ -0,0 +1,97 @@ +import { Component } from 'react'; +import { inject, observer } from 'mobx-react'; +import { Router, Route, IndexRedirect } from 'react-router'; + +import AppLayoutContainer from './containers/layout/AppLayoutContainer'; +import SettingsWindow from './containers/settings/SettingsWindow'; +import RecipesScreen from './containers/settings/RecipesScreen'; +import ServicesScreen from './containers/settings/ServicesScreen'; +import EditServiceScreen from './containers/settings/EditServiceScreen'; +import AccountScreen from './containers/settings/AccountScreen'; +import TeamScreen from './containers/settings/TeamScreen'; +import EditUserScreen from './containers/settings/EditUserScreen'; +import EditSettingsScreen from './containers/settings/EditSettingsScreen'; +import InviteSettingsScreen from './containers/settings/InviteScreen'; +import SupportFerdiScreen from './containers/settings/SupportScreen'; +import WelcomeScreen from './containers/auth/WelcomeScreen'; +import LoginScreen from './containers/auth/LoginScreen'; +import LockedScreen from './containers/auth/LockedScreen'; +import PasswordScreen from './containers/auth/PasswordScreen'; +import ChangeServerScreen from './containers/auth/ChangeServerScreen'; +import SignupScreen from './containers/auth/SignupScreen'; +import ImportScreen from './containers/auth/ImportScreen'; +import SetupAssistentScreen from './containers/auth/SetupAssistantScreen'; +import InviteScreen from './containers/auth/InviteScreen'; +import AuthLayoutContainer from './containers/auth/AuthLayoutContainer'; +import WorkspacesScreen from './features/workspaces/containers/WorkspacesScreen'; +import EditWorkspaceScreen from './features/workspaces/containers/EditWorkspaceScreen'; +import { WORKSPACES_ROUTES } from './features/workspaces/constants'; + +import SettingsStore from './stores/SettingsStore'; + +type Props = { + stores: { + settings: typeof SettingsStore; + }; + history: any; +}; + +@inject('stores', 'actions') +@observer +class Routes extends Component { + render() { + const { locked } = this.props.stores.settings.app; + + const { history } = this.props; + + if (locked) { + return ; + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } +} + +export default Routes; diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index d652276ea..5881e37a4 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js @@ -19,7 +19,7 @@ import Request from './lib/Request'; import { CHECK_INTERVAL, DEFAULT_APP_SETTINGS } from '../config'; import { isMac, electronVersion, osRelease } from '../environment'; import { ferdiVersion, userDataPath, ferdiLocale } from '../environment-remote'; -import locales from '../i18n/translations'; +import { generatedTranslations } from '../i18n/translations'; import { getLocale } from '../helpers/i18n-helpers'; import { @@ -42,6 +42,8 @@ const autoLauncher = new AutoLaunch({ const CATALINA_NOTIFICATION_HACK_KEY = '_temp_askedForCatalinaNotificationPermissions'; +const locales = generatedTranslations(); + export default class AppStore extends Store { updateStatusTypes = { CHECKING: 'CHECKING', diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 16deb91c5..3d418c4c5 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -655,20 +655,20 @@ export default class ServicesStore extends Store { @action _setWebviewReference({ serviceId, webview }) { const service = this.one(serviceId); - - service.webview = webview; - - if (!service.isAttached) { - debug('Webview is not attached, initializing'); - service.initializeWebViewEvents({ - handleIPCMessage: this.actions.service.handleIPCMessage, - openWindow: this.actions.service.openWindow, - stores: this.stores, - }); - service.initializeWebViewListener(); + if (service) { + service.webview = webview; + + if (!service.isAttached) { + debug('Webview is not attached, initializing'); + service.initializeWebViewEvents({ + handleIPCMessage: this.actions.service.handleIPCMessage, + openWindow: this.actions.service.openWindow, + stores: this.stores, + }); + service.initializeWebViewListener(); + } + service.isAttached = true; } - - service.isAttached = true; } @action _detachService({ service }) { @@ -690,20 +690,22 @@ export default class ServicesStore extends Store { // TODO: add checks to not focus service when router path is /settings or /auth const service = this.active; if (service) { - document.title = `Ferdi - ${service.name} ${ - service.dialogTitle ? ` - ${service.dialogTitle}` : '' - } ${service._webview ? `- ${service._webview.getTitle()}` : ''}`; - this._focusService({ serviceId: service.id }); - if (this.stores.settings.app.splitMode && !focusEvent) { - setTimeout(() => { - document - .querySelector('.services__webview-wrapper.is-active') - .scrollIntoView({ - behavior: 'smooth', - block: 'end', - inline: 'nearest', - }); - }, 10); + if (service._webview) { + document.title = `Ferdi - ${service.name} ${ + service.dialogTitle ? ` - ${service.dialogTitle}` : '' + } ${service._webview ? `- ${service._webview.getTitle()}` : ''}`; + this._focusService({ serviceId: service.id }); + if (this.stores.settings.app.splitMode && !focusEvent) { + setTimeout(() => { + document + .querySelector('.services__webview-wrapper.is-active') + .scrollIntoView({ + behavior: 'smooth', + block: 'end', + inline: 'nearest', + }); + }, 10); + } } } else { debug('No service is active'); diff --git a/src/webview/lib/RecipeWebview.js b/src/webview/lib/RecipeWebview.js deleted file mode 100644 index ebe88ed85..000000000 --- a/src/webview/lib/RecipeWebview.js +++ /dev/null @@ -1,166 +0,0 @@ -import { ipcRenderer } from 'electron'; -import { BrowserWindow } from '@electron/remote'; -import { pathExistsSync, readFileSync, existsSync } from 'fs-extra'; - -const debug = require('debug')('Ferdi:Plugin:RecipeWebview'); - -class RecipeWebview { - constructor( - badgeHandler, - dialogTitleHandler, - notificationsHandler, - sessionHandler, - ) { - this.badgeHandler = badgeHandler; - this.dialogTitleHandler = dialogTitleHandler; - this.notificationsHandler = notificationsHandler; - this.sessionHandler = sessionHandler; - - ipcRenderer.on('poll', () => { - this.loopFunc(); - - debug('Poll event'); - - // This event is for checking if the service recipe is still actively - // communicating with the client - ipcRenderer.sendToHost('alive'); - }); - } - - loopFunc = () => null; - - darkModeHandler = false; - - // TODO Remove this once we implement a proper wrapper. - get ipcRenderer() { - return ipcRenderer; - } - - // TODO Remove this once we implement a proper wrapper. - get BrowserWindow() { - return BrowserWindow; - } - - /** - * Initialize the loop - * - * @param {Function} Function that will be executed - */ - loop(fn) { - this.loopFunc = fn; - } - - /** - * Set the unread message badge - * - * @param {string | number | undefined | null} direct Set the count of direct messages - * eg. Slack direct mentions, or a - * message to @channel - * @param {string | number | undefined | null} indirect Set a badge that defines there are - * new messages but they do not involve - * me directly to me eg. in a channel - */ - setBadge(direct = 0, indirect = 0) { - this.badgeHandler.setBadge(direct, indirect); - } - - /** - * Set the active dialog title to the app title - * - * @param {string | undefined | null} title Set the active dialog title - * to the app title - * eg. WhatsApp contact name - */ - setDialogTitle(title) { - this.dialogTitleHandler.setDialogTitle(title); - } - - /** - * Safely parse the given text into an integer - * - * @param {string | number | undefined | null} text to be parsed - */ - safeParseInt(text) { - return this.badgeHandler.safeParseInt(text); - } - - /** - * Injects the contents of a CSS file into the current webview - * - * @param {Array} files CSS files that should be injected. This must - * be an absolute path to the file - */ - injectCSS(...files) { - // eslint-disable-next-line unicorn/no-array-for-each - files.forEach(file => { - if (pathExistsSync(file)) { - const styles = document.createElement('style'); - styles.innerHTML = readFileSync(file, 'utf8'); - - document.querySelector('head').append(styles); - - debug('Append styles', styles); - } - }); - } - - injectJSUnsafe(...files) { - Promise.all( - files.map(file => { - if (existsSync(file)) { - return readFileSync(file, 'utf8'); - } - debug('Script not found', file); - return null; - }), - ).then(scripts => { - const scriptsFound = scripts.filter(script => script !== null); - if (scriptsFound.length > 0) { - debug('Inject scripts to main world', scriptsFound); - ipcRenderer.sendToHost('inject-js-unsafe', ...scriptsFound); - } - }); - } - - /** - * Set a custom handler for turning on and off dark mode - * - * @param {function} handler - */ - handleDarkMode(handler) { - this.darkModeHandler = handler; - } - - onNotify(fn) { - if (typeof fn === 'function') { - this.notificationsHandler.onNotify = fn; - } - } - - initialize(fn) { - if (typeof fn === 'function') { - fn(); - } - } - - clearStorageData(serviceId, targetsToClear) { - ipcRenderer.send('clear-storage-data', { - serviceId, - targetsToClear, - }); - } - - releaseServiceWorkers() { - this.sessionHandler.releaseServiceWorkers(); - } - - setAvatarImage(avatarUrl) { - ipcRenderer.sendToHost('avatar', avatarUrl); - } - - openNewWindow(url) { - ipcRenderer.sendToHost('new-window', url); - } -} - -export default RecipeWebview; diff --git a/src/webview/lib/RecipeWebview.ts b/src/webview/lib/RecipeWebview.ts new file mode 100644 index 000000000..09dc462ed --- /dev/null +++ b/src/webview/lib/RecipeWebview.ts @@ -0,0 +1,177 @@ +import { ipcRenderer } from 'electron'; +import { BrowserWindow } from '@electron/remote'; +import { pathExistsSync, readFileSync, existsSync } from 'fs-extra'; + +const debug = require('debug')('Ferdi:Plugin:RecipeWebview'); + +class RecipeWebview { + badgeHandler: any; + + dialogTitleHandler: any; + + notificationsHandler: any; + + sessionHandler: any; + + constructor( + badgeHandler, + dialogTitleHandler, + notificationsHandler, + sessionHandler, + ) { + this.badgeHandler = badgeHandler; + this.dialogTitleHandler = dialogTitleHandler; + this.notificationsHandler = notificationsHandler; + this.sessionHandler = sessionHandler; + + ipcRenderer.on('poll', () => { + this.loopFunc(); + + debug('Poll event'); + + // This event is for checking if the service recipe is still actively + // communicating with the client + ipcRenderer.sendToHost('alive'); + }); + } + + loopFunc = () => null; + + darkModeHandler = false; + + // TODO Remove this once we implement a proper wrapper. + get ipcRenderer() { + return ipcRenderer; + } + + // TODO Remove this once we implement a proper wrapper. + get BrowserWindow() { + return BrowserWindow; + } + + /** + * Initialize the loop + * + * @param {Function} Function that will be executed + */ + loop(fn) { + this.loopFunc = fn; + } + + /** + * Set the unread message badge + * + * @param {string | number | undefined | null} direct Set the count of direct messages + * eg. Slack direct mentions, or a + * message to @channel + * @param {string | number | undefined | null} indirect Set a badge that defines there are + * new messages but they do not involve + * me directly to me eg. in a channel + */ + setBadge(direct = 0, indirect = 0) { + this.badgeHandler.setBadge(direct, indirect); + } + + /** + * Set the active dialog title to the app title + * + * @param {string | undefined | null} title Set the active dialog title + * to the app title + * eg. WhatsApp contact name + */ + setDialogTitle(title) { + this.dialogTitleHandler.setDialogTitle(title); + } + + /** + * Safely parse the given text into an integer + * + * @param {string | number | undefined | null} text to be parsed + */ + safeParseInt(text) { + return this.badgeHandler.safeParseInt(text); + } + + /** + * Injects the contents of a CSS file into the current webview + * + * @param {Array} files CSS files that should be injected. This must + * be an absolute path to the file + */ + injectCSS(...files) { + // eslint-disable-next-line unicorn/no-array-for-each + files.forEach(file => { + if (pathExistsSync(file)) { + const styles = document.createElement('style'); + styles.innerHTML = readFileSync(file, 'utf8'); + + const head = document.querySelector('head'); + + if (head) { + head.append(styles); + debug('Append styles', styles); + } + } + }); + } + + injectJSUnsafe(...files) { + Promise.all( + files.map(file => { + if (existsSync(file)) { + return readFileSync(file, 'utf8'); + } + debug('Script not found', file); + return null; + }), + ).then(scripts => { + const scriptsFound = scripts.filter(script => script !== null); + if (scriptsFound.length > 0) { + debug('Inject scripts to main world', scriptsFound); + ipcRenderer.sendToHost('inject-js-unsafe', ...scriptsFound); + } + }); + } + + /** + * Set a custom handler for turning on and off dark mode + * + * @param {function} handler + */ + handleDarkMode(handler) { + this.darkModeHandler = handler; + } + + onNotify(fn) { + if (typeof fn === 'function') { + this.notificationsHandler.onNotify = fn; + } + } + + initialize(fn) { + if (typeof fn === 'function') { + fn(); + } + } + + clearStorageData(serviceId, targetsToClear) { + ipcRenderer.send('clear-storage-data', { + serviceId, + targetsToClear, + }); + } + + releaseServiceWorkers() { + this.sessionHandler.releaseServiceWorkers(); + } + + setAvatarImage(avatarUrl) { + ipcRenderer.sendToHost('avatar', avatarUrl); + } + + openNewWindow(url) { + ipcRenderer.sendToHost('new-window', url); + } +} + +export default RecipeWebview; diff --git a/src/webview/lib/Userscript.js b/src/webview/lib/Userscript.js deleted file mode 100644 index f7bb99206..000000000 --- a/src/webview/lib/Userscript.js +++ /dev/null @@ -1,138 +0,0 @@ -import { ipcRenderer } from 'electron'; - -export default class Userscript { - // Current ./lib/RecipeWebview instance - recipe = null; - - // Current ./recipe.js instance - controller = null; - - // Service configuration - config = {}; - - // Ferdi and service settings - settings = {}; - - settingsUpdateHandler = null; - - constructor(recipe, controller, config) { - this.recipe = recipe; - this.controller = controller; - this.internal_setSettings(controller.settings); - this.config = config; - } - - /** - * Set internal copy of Ferdi's settings. - * This is only used internally and can not be used to change any settings - * - * @param {*} settings - */ - // eslint-disable-next-line camelcase - internal_setSettings(settings) { - // This is needed to get a clean JS object from the settings itself to provide better accessibility - // Otherwise this will be a mobX instance - this.settings = JSON.parse(JSON.stringify(settings)); - - if (typeof this.settingsUpdateHandler === 'function') { - this.settingsUpdateHandler(); - } - } - - /** - * Register a settings handler to be executed when the settings change - * - * @param {function} handler - */ - onSettingsUpdate(handler) { - this.settingsUpdateHandler = handler; - } - - /** - * Set badge count for the current service - * @param {*} direct Direct messages - * @param {*} indirect Indirect messages - */ - setBadge(direct = 0, indirect = 0) { - if (this.recipe && this.recipe.setBadge) { - this.recipe.setBadge(direct, indirect); - } - } - - /** - * Set active dialog title to the app title - * @param {*} title Dialog title - */ - setDialogTitle(title) { - if (this.recipe && this.recipe.setDialogTitle) { - this.recipe.setDialogTitle(title); - } - } - - /** - * Inject CSS files into the current page - * - * @param {...string} files - */ - injectCSSFiles(...files) { - if (this.recipe && this.recipe.injectCSS) { - this.recipe.injectCSS(...files); - } - } - - /** - * Inject a CSS string into the page - * - * @param {string} css - */ - injectCSS(css) { - const style = document.createElement('style'); - style.textContent = css; - document.head.append(style); - } - - /** - * Open "Find in Page" popup - */ - openFindInPage() { - this.controller.openFindInPage(); - } - - /** - * Set or update value in storage - * - * @param {*} key - * @param {*} value - */ - set(key, value) { - window.localStorage.setItem(`ferdi-user-${key}`, JSON.stringify(value)); - } - - /** - * Get value from storage - * - * @param {*} key - * @return Value of the key - */ - get(key) { - return JSON.parse(window.localStorage.getItem(`ferdi-user-${key}`)); - } - - /** - * Open a URL in an external browser - * - * @param {*} url - */ - externalOpen(url) { - ipcRenderer.sendToHost('new-window', url); - } - - /** - * Open a URL in the current service - * - * @param {*} url - */ - internalOpen(url) { - window.location.href = url; - } -} diff --git a/src/webview/lib/Userscript.ts b/src/webview/lib/Userscript.ts new file mode 100644 index 000000000..c50941dc7 --- /dev/null +++ b/src/webview/lib/Userscript.ts @@ -0,0 +1,107 @@ +type Recipe = { + setBadge: (direct: number, indirect: number) => void; + setDialogTitle: (title: string) => void; + injectCSS: (css: string | string[]) => void; +}; + +export default class Userscript { + // Current ./lib/RecipeWebview instance + recipe: Recipe | null = null; + + // Current ./recipe.js instance + controller = null; + + // Service configuration + config = {}; + + // Ferdi and service settings + settings = {}; + + constructor(recipe, controller, config) { + this.recipe = recipe; + this.controller = controller; + this.internal_setSettings(controller.settings); + this.config = config; + } + + /** + * Set internal copy of Ferdi's settings. + * This is only used internally and can not be used to change any settings + * + * @param {*} settings + */ + // eslint-disable-next-line camelcase + internal_setSettings(settings: any) { + // This is needed to get a clean JS object from the settings itself to provide better accessibility + // Otherwise this will be a mobX instance + this.settings = JSON.parse(JSON.stringify(settings)); + } + + /** + * Set badge count for the current service + * @param {number} direct Direct messages + * @param {number} indirect Indirect messages + */ + setBadge(direct: number = 0, indirect: number = 0) { + if (this.recipe && this.recipe.setBadge) { + this.recipe.setBadge(direct, indirect); + } + } + + /** + * Set active dialog title to the app title + * @param {*} title Dialog title + */ + setDialogTitle(title: string) { + if (this.recipe && this.recipe.setDialogTitle) { + this.recipe.setDialogTitle(title); + } + } + + /** + * Inject CSS files into the current page + * + * @param {...string} files + */ + injectCSSFiles(...files: string[]) { + if (this.recipe && this.recipe.injectCSS) { + // @ts-expect-error A spread argument must either have a tuple type or be passed to a rest parameter. + this.recipe.injectCSS(...files); + } + } + + /** + * Inject a CSS string into the page + * + * @param {string} css + */ + injectCSS(css: string) { + const style = document.createElement('style'); + style.textContent = css; + document.head.append(style); + } + + /** + * Set or update value in storage + * + * @param {string} key + * @param {any} value + */ + set(key: string, value: string) { + window.localStorage.setItem(`ferdi-user-${key}`, JSON.stringify(value)); + } + + /** + * Get value from storage + * + * @param {string} key + * @return Value of the key + */ + get(key: string) { + const ferdiUserKey = window.localStorage.getItem(`ferdi-user-${key}`); + + if (ferdiUserKey) { + return JSON.parse(ferdiUserKey); + } + } +} -- cgit v1.2.3-70-g09d2 From 11c992b04f3cad6badf0ae86da65f490e31dd359 Mon Sep 17 00:00:00 2001 From: Markus Hatvan Date: Sat, 4 Dec 2021 10:51:16 +0100 Subject: chore: upgrade react-jss to latest (#2302) --- package-lock.json | 659 ++++++++++++--------- package.json | 6 +- src/I18n.tsx | 4 +- src/components/auth/AuthLayout.js | 3 +- src/components/auth/ChangeServer.js | 3 +- src/components/auth/Import.js | 3 +- src/components/auth/Invite.js | 3 +- src/components/auth/Locked.js | 3 +- src/components/auth/Login.js | 4 +- src/components/auth/Password.js | 3 +- src/components/auth/SetupAssistant.js | 6 +- src/components/auth/Signup.js | 4 +- src/components/auth/Welcome.js | 4 +- src/components/layout/AppLayout.js | 6 +- src/components/layout/Sidebar.js | 4 +- .../services/content/ConnectionLostBanner.js | 4 +- .../content/ErrorHandlers/WebviewErrorHandler.js | 6 +- src/components/services/content/ServiceDisabled.js | 3 +- src/components/services/content/ServiceView.js | 4 +- src/components/services/content/ServiceWebview.js | 3 +- src/components/services/content/Services.js | 9 +- .../services/content/WebviewCrashHandler.js | 3 +- src/components/services/tabs/TabBarSortableList.js | 3 +- src/components/services/tabs/TabItem.js | 11 +- src/components/services/tabs/Tabbar.js | 3 +- src/components/settings/SettingsLayout.js | 3 +- .../settings/account/AccountDashboard.js | 3 +- .../settings/navigation/SettingsNavigation.js | 4 +- src/components/settings/recipes/RecipeItem.js | 3 +- .../settings/recipes/RecipesDashboard.js | 28 +- .../settings/services/EditServiceForm.js | 3 +- src/components/settings/services/ServiceError.js | 3 +- src/components/settings/services/ServiceItem.js | 3 +- .../settings/services/ServicesDashboard.js | 3 +- .../settings/settings/EditSettingsForm.js | 3 +- src/components/settings/team/TeamDashboard.js | 6 +- src/components/settings/user/EditUserForm.js | 3 +- src/components/ui/AppLoader/index.tsx | 6 +- src/components/ui/Button.js | 4 +- src/components/ui/FAB.tsx | 3 +- src/components/ui/FullscreenLoader/index.js | 9 +- src/components/ui/ImageUpload.tsx | 3 +- src/components/ui/InfoBar.js | 3 +- src/components/ui/Infobox.js | 3 +- src/components/ui/Input.js | 12 +- src/components/ui/Link.js | 8 +- src/components/ui/Loader.tsx | 4 +- src/components/ui/Modal/index.tsx | 3 +- src/components/ui/Radio.tsx | 3 +- src/components/ui/SearchInput.tsx | 3 +- src/components/ui/Select.js | 3 +- src/components/ui/ServiceIcon.js | 6 +- src/components/ui/Slider.js | 3 +- src/components/ui/StatusBarTargetUrl.js | 3 +- src/components/ui/Tabs/Tabs.js | 3 +- src/components/ui/Toggle.js | 3 +- src/components/ui/ToggleRaw.js | 3 +- src/components/ui/WebviewLoader/index.js | 6 +- src/components/ui/badge/ProBadge.tsx | 9 +- src/components/ui/badge/index.tsx | 7 +- src/components/ui/button/index.tsx | 14 +- src/components/ui/error/index.tsx | 2 +- src/components/ui/headline/index.tsx | 10 +- src/components/ui/icon/index.tsx | 7 +- src/components/ui/infobox/index.tsx | 9 +- src/components/ui/input/index.tsx | 8 +- src/components/ui/label/index.tsx | 13 +- src/components/ui/loader/index.tsx | 18 +- src/components/ui/select/index.tsx | 11 +- src/components/ui/textarea/index.tsx | 10 +- src/components/ui/toggle/index.tsx | 10 +- src/components/ui/typings/generic.ts | 9 - src/components/ui/wrapper/index.tsx | 9 +- src/components/util/ErrorBoundary/index.js | 5 +- src/containers/auth/AuthLayoutContainer.js | 6 +- src/containers/auth/ChangeServerScreen.js | 6 +- src/containers/auth/ImportScreen.js | 6 +- src/containers/auth/InviteScreen.js | 6 +- src/containers/auth/LockedScreen.js | 6 +- src/containers/auth/LoginScreen.js | 6 +- src/containers/auth/PasswordScreen.js | 6 +- src/containers/auth/SetupAssistantScreen.js | 6 +- src/containers/auth/SignupScreen.js | 6 +- src/containers/auth/WelcomeScreen.js | 6 +- src/containers/layout/AppLayoutContainer.js | 6 +- src/containers/settings/AccountScreen.js | 6 +- src/containers/settings/EditServiceScreen.js | 8 +- src/containers/settings/EditSettingsScreen.js | 8 +- src/containers/settings/EditUserScreen.js | 8 +- src/containers/settings/InviteScreen.js | 6 +- src/containers/settings/RecipesScreen.js | 6 +- src/containers/settings/ServicesScreen.js | 6 +- src/containers/settings/SettingsWindow.js | 6 +- src/containers/settings/SupportScreen.js | 5 +- src/containers/settings/TeamScreen.js | 6 +- src/electron/ipc-api/download.ts | 2 +- src/features/basicAuth/Component.js | 6 +- src/features/nightlyBuilds/Component.js | 15 +- src/features/publishDebugInfo/Component.js | 16 +- src/features/quickSwitch/Component.js | 12 +- src/features/todos/components/TodosWebview.js | 7 +- src/features/todos/containers/TodosScreen.js | 6 +- src/features/todos/store.js | 4 - src/features/webControls/components/WebControls.js | 6 +- .../webControls/containers/WebControlsScreen.js | 6 +- .../workspaces/components/CreateWorkspaceForm.js | 10 +- .../workspaces/components/EditWorkspaceForm.js | 10 +- .../workspaces/components/WorkspaceDrawer.js | 6 +- .../workspaces/components/WorkspaceDrawerItem.js | 6 +- .../workspaces/components/WorkspaceItem.tsx | 6 +- .../components/WorkspaceServiceListItem.tsx | 6 +- .../components/WorkspaceSwitchingIndicator.js | 8 +- .../workspaces/components/WorkspacesDashboard.js | 15 +- .../workspaces/containers/EditWorkspaceScreen.tsx | 4 +- .../workspaces/containers/WorkspacesScreen.tsx | 4 +- src/lib/Form.ts | 7 + src/routes.tsx | 4 +- src/stores/ServicesStore.js | 2 - 118 files changed, 700 insertions(+), 673 deletions(-) (limited to 'src/stores/ServicesStore.js') diff --git a/package-lock.json b/package-lock.json index eefac54e2..b145811cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,8 +51,8 @@ "minimist": "^1.2.5", "mobx": "^5.15.0", "mobx-localstorage": "^1.2.0", - "mobx-react": "^5.4.2", - "mobx-react-form": "1.35.1", + "mobx-react": "^6.3.1", + "mobx-react-form": "^2.0.9", "mobx-react-router": "^3.1.2", "moment": "^2.29.1", "ms": "^2.1.3", @@ -68,7 +68,7 @@ "react-dropzone": "^11.4.2", "react-electron-web-view": "^2.0.1", "react-intl": "^5.21.0", - "react-jss": "^8.6.1", + "react-jss": "^10.8.2", "react-loader": "^2.4.7", "react-modal": "^3.14.3", "react-router": "^3.2.6", @@ -2866,6 +2866,19 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", + "integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==", + "dependencies": { + "@emotion/memoize": "0.7.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz", + "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==" + }, "node_modules/@endemolshinegroup/cosmiconfig-typescript-loader": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz", @@ -7769,11 +7782,6 @@ "node": ">=0.10.0" } }, - "node_modules/brcast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/brcast/-/brcast-3.0.2.tgz", - "integrity": "sha512-f5XwwFCCuvgqP2nMH/hJ74FqnGmb4X3D+NC//HphxJzzhsZvSZa+Hk/syB7j3ZHpPDLMoYU8oBgviRWfNvEfKA==" - }, "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", @@ -10098,6 +10106,16 @@ "node": ">= 0.8" } }, + "node_modules/css-jss": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/css-jss/-/css-jss-10.8.2.tgz", + "integrity": "sha512-KjsoKnBV4C9p+F+zW9jNXCai0UYU5K+3eyo+lJX/fY8UBEQd/yNREnHsLD1VMMzBwHRvrA8eQHvqmAL+XNLYcw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "jss-preset-default": "10.8.2" + } + }, "node_modules/css-select": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", @@ -10137,10 +10155,11 @@ } }, "node_modules/css-vendor": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz", - "integrity": "sha1-ZCHP0wNM5mT+dnOXL9ARn8KJQfo=", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", "dependencies": { + "@babel/runtime": "^7.8.3", "is-in-browser": "^1.0.2" } }, @@ -16616,11 +16635,6 @@ "node": ">=4" } }, - "node_modules/is-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", - "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" - }, "node_modules/is-generator-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", @@ -19420,122 +19434,141 @@ "url": "https://opencollective.com/jss" } }, - "node_modules/jss-camel-case": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jss-camel-case/-/jss-camel-case-6.1.0.tgz", - "integrity": "sha512-HPF2Q7wmNW1t79mCqSeU2vdd/vFFGpkazwvfHMOhPlMgXrJDzdj9viA2SaHk9ZbD5pfL63a8ylp4++irYbbzMQ==", + "node_modules/jss-plugin-camel-case": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz", + "integrity": "sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA==", "dependencies": { - "hyphenate-style-name": "^1.0.2" - }, - "peerDependencies": { - "jss": "^9.7.0" + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.8.2" } }, - "node_modules/jss-compose": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jss-compose/-/jss-compose-5.0.0.tgz", - "integrity": "sha512-YofRYuiA0+VbeOw0VjgkyO380sA4+TWDrW52nSluD9n+1FWOlDzNbgpZ/Sb3Y46+DcAbOS21W5jo6SAqUEiuwA==", + "node_modules/jss-plugin-compose": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-compose/-/jss-plugin-compose-10.8.2.tgz", + "integrity": "sha512-X7fDQJ6IlIJoT8A3zc++LuC1hmSGKVudb3LyXp+vHv8r2hzzfXEEZty3y2CaC5CGrWcLlYquXENjqLNmLYMgMA==", "dependencies": { - "warning": "^3.0.0" - }, - "peerDependencies": { - "jss": "^9.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" } }, - "node_modules/jss-default-unit": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/jss-default-unit/-/jss-default-unit-8.0.2.tgz", - "integrity": "sha512-WxNHrF/18CdoAGw2H0FqOEvJdREXVXLazn7PQYU7V6/BWkCV0GkmWsppNiExdw8dP4TU1ma1dT9zBNJ95feLmg==", - "peerDependencies": { - "jss": "^9.4.0" + "node_modules/jss-plugin-default-unit": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz", + "integrity": "sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" } }, - "node_modules/jss-expand": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/jss-expand/-/jss-expand-5.3.0.tgz", - "integrity": "sha512-NiM4TbDVE0ykXSAw6dfFmB1LIqXP/jdd0ZMnlvlGgEMkMt+weJIl8Ynq1DsuBY9WwkNyzWktdqcEW2VN0RAtQg==", - "peerDependencies": { - "jss": "^9.4.0" + "node_modules/jss-plugin-expand": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-expand/-/jss-plugin-expand-10.8.2.tgz", + "integrity": "sha512-Iy4qsZbEcomXz5aBZJYGwnzK23vK3hqlwGleqmd19fY3L+WbqTmUnW8W0fWeXSuCkw2NknBTAJuEpFcgm3b0Pw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" } }, - "node_modules/jss-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jss-extend/-/jss-extend-6.2.0.tgz", - "integrity": "sha512-YszrmcB6o9HOsKPszK7NeDBNNjVyiW864jfoiHoMlgMIg2qlxKw70axZHqgczXHDcoyi/0/ikP1XaHDPRvYtEA==", + "node_modules/jss-plugin-extend": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-extend/-/jss-plugin-extend-10.8.2.tgz", + "integrity": "sha512-NYu0cJ/Zb50ySPkegzbXQQfhXza0VpaRVXdXDex30yXqZpGcAdmhSg4HTv8vzHiL1v3uIOm641FYQX9WvLgSWw==", "dependencies": { - "warning": "^3.0.0" - }, - "peerDependencies": { - "jss": "^9.7.0" + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" } }, - "node_modules/jss-global": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jss-global/-/jss-global-3.0.0.tgz", - "integrity": "sha512-wxYn7vL+TImyQYGAfdplg7yaxnPQ9RaXY/cIA8hawaVnmmWxDHzBK32u1y+RAvWboa3lW83ya3nVZ/C+jyjZ5Q==", - "peerDependencies": { - "jss": "^9.0.0" + "node_modules/jss-plugin-global": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz", + "integrity": "sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" } }, - "node_modules/jss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jss-nested/-/jss-nested-6.0.1.tgz", - "integrity": "sha512-rn964TralHOZxoyEgeq3hXY8hyuCElnvQoVrQwKHVmu55VRDd6IqExAx9be5HgK0yN/+hQdgAXQl/GUrBbbSTA==", + "node_modules/jss-plugin-nested": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz", + "integrity": "sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA==", "dependencies": { - "warning": "^3.0.0" - }, - "peerDependencies": { - "jss": "^9.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" } }, - "node_modules/jss-preset-default": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-4.5.0.tgz", - "integrity": "sha512-qZbpRVtHT7hBPpZEBPFfafZKWmq3tA/An5RNqywDsZQGrlinIF/mGD9lmj6jGqu8GrED2SMHZ3pPKLmjCZoiaQ==", - "dependencies": { - "jss-camel-case": "^6.1.0", - "jss-compose": "^5.0.0", - "jss-default-unit": "^8.0.2", - "jss-expand": "^5.3.0", - "jss-extend": "^6.2.0", - "jss-global": "^3.0.0", - "jss-nested": "^6.0.1", - "jss-props-sort": "^6.0.0", - "jss-template": "^1.0.1", - "jss-vendor-prefixer": "^7.0.0" - }, - "peerDependencies": { - "jss": "^9.7.0" + "node_modules/jss-plugin-props-sort": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz", + "integrity": "sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" } }, - "node_modules/jss-props-sort": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/jss-props-sort/-/jss-props-sort-6.0.0.tgz", - "integrity": "sha512-E89UDcrphmI0LzmvYk25Hp4aE5ZBsXqMWlkFXS0EtPkunJkRr+WXdCNYbXbksIPnKlBenGB9OxzQY+mVc70S+g==", - "peerDependencies": { - "jss": "^9.0.0" + "node_modules/jss-plugin-rule-value-function": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz", + "integrity": "sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" } }, - "node_modules/jss-template": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jss-template/-/jss-template-1.0.1.tgz", - "integrity": "sha512-m5BqEWha17fmIVXm1z8xbJhY6GFJxNB9H68GVnCWPyGYfxiAgY9WTQyvDAVj+pYRgrXSOfN5V1T4+SzN1sJTeg==", + "node_modules/jss-plugin-rule-value-observable": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-observable/-/jss-plugin-rule-value-observable-10.8.2.tgz", + "integrity": "sha512-NaJCfsEg8/6l/E8HstwL2w8kHj2LHhwoG4fXxefmdvNKmJMwBpnjech5dEPL72It4bZfIIYoynWbyxo3Q0ZKQQ==", "dependencies": { - "warning": "^3.0.0" - }, - "peerDependencies": { - "jss": "^9.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "symbol-observable": "^1.2.0" } }, - "node_modules/jss-vendor-prefixer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/jss-vendor-prefixer/-/jss-vendor-prefixer-7.0.0.tgz", - "integrity": "sha512-Agd+FKmvsI0HLcYXkvy8GYOw3AAASBUpsmIRvVQheps+JWaN892uFOInTr0DRydwaD91vSSUCU4NssschvF7MA==", + "node_modules/jss-plugin-template": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-template/-/jss-plugin-template-10.8.2.tgz", + "integrity": "sha512-oTVwYRUCuCLslHxuH73F15kFmDxc4YEJIn8kHBnNpGr99ZbQdRIgPabosVTfkgE8czuyTx0KM5u8zEeuL+v66A==", "dependencies": { - "css-vendor": "^0.3.8" - }, - "peerDependencies": { - "jss": "^9.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-vendor-prefixer": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz", + "integrity": "sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.8.2" + } + }, + "node_modules/jss-preset-default": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-10.8.2.tgz", + "integrity": "sha512-mgkr6DAZuvkEleHFEpOkm8Y+sTdK/r0HH8PxToLHgaWHbYS0JAb0g1tBSUMG24kFj98VOYLTllK1o0J4lWU/uw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "jss-plugin-camel-case": "10.8.2", + "jss-plugin-compose": "10.8.2", + "jss-plugin-default-unit": "10.8.2", + "jss-plugin-expand": "10.8.2", + "jss-plugin-extend": "10.8.2", + "jss-plugin-global": "10.8.2", + "jss-plugin-nested": "10.8.2", + "jss-plugin-props-sort": "10.8.2", + "jss-plugin-rule-value-function": "10.8.2", + "jss-plugin-rule-value-observable": "10.8.2", + "jss-plugin-template": "10.8.2", + "jss-plugin-vendor-prefixer": "10.8.2" } }, "node_modules/jsx-ast-utils": { @@ -21173,32 +21206,48 @@ } }, "node_modules/mobx-react": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.4.4.tgz", - "integrity": "sha512-2mTzpyEjVB/RGk2i6KbcmP4HWcAUFox5ZRCrGvSyz49w20I4C4qql63grPpYrS9E9GKwgydBHQlA4y665LuRCQ==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-6.3.1.tgz", + "integrity": "sha512-IOxdJGnRSNSJrL2uGpWO5w9JH5q5HoxEqwOF4gye1gmZYdjoYkkMzSGMDnRCUpN/BNzZcFoMdHXrjvkwO7KgaQ==", "dependencies": { - "hoist-non-react-statics": "^3.0.0", - "react-lifecycles-compat": "^3.0.2" + "mobx-react-lite": "^2.2.0" }, "peerDependencies": { - "mobx": "^4.0.0 || ^5.0.0", - "react": "^0.13.0 || ^0.14.0 || ^15.0.0 || ^16.0.0" + "mobx": "^5.15.4 || ^4.15.4", + "react": "^16.8.0 || 16.9.0-alpha.0" } }, "node_modules/mobx-react-form": { - "version": "1.35.1", - "resolved": "https://registry.npmjs.org/mobx-react-form/-/mobx-react-form-1.35.1.tgz", - "integrity": "sha1-iSrsZykiThHCl4+4LmetxOgOOmo=", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/mobx-react-form/-/mobx-react-form-2.0.9.tgz", + "integrity": "sha512-YLbtXVUF6BtifeVr6XWJ76dQWJs3T/+aPNI/DKvNs1Opcl4jNCzENahqlqNsNI+RgXZbP36zck//IGWBNZsr0A==", "dependencies": { - "lodash": "^4.16.2" + "lodash": "^4.17.11" }, "engines": { - "node": ">=6.0.0" + "node": ">=8.0.0" }, "peerDependencies": { "mobx": "^2.5.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" } }, + "node_modules/mobx-react-lite": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-2.2.2.tgz", + "integrity": "sha512-2SlXALHIkyUPDsV4VTKVR9DW7K3Ksh1aaIv3NrNJygTbhXe2A9GrcKHZ2ovIiOp/BXilOcTYemfHHZubP431dg==", + "peerDependencies": { + "mobx": "^4.0.0 || ^5.0.0", + "react": "^16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/mobx-react-router": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/mobx-react-router/-/mobx-react-router-3.1.2.tgz", @@ -24552,6 +24601,11 @@ "react": "^16.3.0 || ^17.0.1" } }, + "node_modules/react-display-name": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/react-display-name/-/react-display-name-0.2.5.tgz", + "integrity": "sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==" + }, "node_modules/react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -24625,40 +24679,24 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-jss": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-8.6.1.tgz", - "integrity": "sha512-SH6XrJDJkAphp602J14JTy3puB2Zxz1FkM3bKVE8wON+va99jnUTKWnzGECb3NfIn9JPR5vHykge7K3/A747xQ==", + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-10.8.2.tgz", + "integrity": "sha512-/lLFIv1H6GA5RkvNb7TdXcJMBaSvSpfmSYsDisj4WI7MmqXUouoKfkZUJzG7CWq8xnIxik0WWYjFcGOvx0Sasw==", "dependencies": { - "hoist-non-react-statics": "^2.5.0", - "jss": "^9.7.0", - "jss-preset-default": "^4.3.0", + "@babel/runtime": "^7.3.1", + "@emotion/is-prop-valid": "^0.7.3", + "css-jss": "10.8.2", + "hoist-non-react-statics": "^3.2.0", + "is-in-browser": "^1.1.3", + "jss": "10.8.2", + "jss-preset-default": "10.8.2", "prop-types": "^15.6.0", - "theming": "^1.3.0" - }, - "engines": { - "node": ">=4" + "shallow-equal": "^1.2.0", + "theming": "^3.3.0", + "tiny-warning": "^1.0.2" }, "peerDependencies": { - "react": ">=0.13" - } - }, - "node_modules/react-jss/node_modules/hoist-non-react-statics": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", - "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" - }, - "node_modules/react-jss/node_modules/jss": { - "version": "9.8.7", - "resolved": "https://registry.npmjs.org/jss/-/jss-9.8.7.tgz", - "integrity": "sha512-awj3XRZYxbrmmrx9LUSj5pXSUfm12m8xzi/VKeqI1ZwWBtQ0kVPTs3vYs32t4rFw83CgFDukA8wKzOE9sMQnoQ==", - "hasInstallScript": true, - "dependencies": { - "is-in-browser": "^1.1.3", - "symbol-observable": "^1.1.0", - "warning": "^3.0.0" - }, - "engines": { - "node": ">=4" + "react": ">=16.8.6" } }, "node_modules/react-lifecycles-compat": { @@ -26490,6 +26528,11 @@ "node": ">=8" } }, + "node_modules/shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -28065,17 +28108,20 @@ "dev": true }, "node_modules/theming": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/theming/-/theming-1.3.0.tgz", - "integrity": "sha512-ya5Ef7XDGbTPBv5ENTwrwkPUexrlPeiAg/EI9kdlUAZhNlRbCdhMKRgjNX1IcmsmiPcqDQZE6BpSaH+cr31FKw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/theming/-/theming-3.3.0.tgz", + "integrity": "sha512-u6l4qTJRDaWZsqa8JugaNt7Xd8PPl9+gonZaIe28vAhqgHMIG/DOyFPqiKN/gQLQYj05tHv+YQdNILL4zoiAVA==", "dependencies": { - "brcast": "^3.0.1", - "is-function": "^1.0.1", - "is-plain-object": "^2.0.1", - "prop-types": "^15.5.8" + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.8", + "react-display-name": "^0.2.4", + "tiny-warning": "^1.0.2" + }, + "engines": { + "node": ">=8" }, "peerDependencies": { - "react": ">=0.15" + "react": ">=16.3" } }, "node_modules/throat": { @@ -33729,6 +33775,19 @@ } } }, + "@emotion/is-prop-valid": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", + "integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==", + "requires": { + "@emotion/memoize": "0.7.1" + } + }, + "@emotion/memoize": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz", + "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==" + }, "@endemolshinegroup/cosmiconfig-typescript-loader": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz", @@ -37695,11 +37754,6 @@ "to-regex": "^3.0.1" } }, - "brcast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/brcast/-/brcast-3.0.2.tgz", - "integrity": "sha512-f5XwwFCCuvgqP2nMH/hJ74FqnGmb4X3D+NC//HphxJzzhsZvSZa+Hk/syB7j3ZHpPDLMoYU8oBgviRWfNvEfKA==" - }, "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", @@ -39589,6 +39643,16 @@ "uid-safe": "2.1.5" } }, + "css-jss": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/css-jss/-/css-jss-10.8.2.tgz", + "integrity": "sha512-KjsoKnBV4C9p+F+zW9jNXCai0UYU5K+3eyo+lJX/fY8UBEQd/yNREnHsLD1VMMzBwHRvrA8eQHvqmAL+XNLYcw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "jss-preset-default": "10.8.2" + } + }, "css-select": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", @@ -39621,10 +39685,11 @@ } }, "css-vendor": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz", - "integrity": "sha1-ZCHP0wNM5mT+dnOXL9ARn8KJQfo=", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", "requires": { + "@babel/runtime": "^7.8.3", "is-in-browser": "^1.0.2" } }, @@ -44767,11 +44832,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, - "is-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", - "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" - }, "is-generator-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", @@ -46868,89 +46928,141 @@ "tiny-warning": "^1.0.2" } }, - "jss-camel-case": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jss-camel-case/-/jss-camel-case-6.1.0.tgz", - "integrity": "sha512-HPF2Q7wmNW1t79mCqSeU2vdd/vFFGpkazwvfHMOhPlMgXrJDzdj9viA2SaHk9ZbD5pfL63a8ylp4++irYbbzMQ==", + "jss-plugin-camel-case": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz", + "integrity": "sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA==", "requires": { - "hyphenate-style-name": "^1.0.2" + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.8.2" } }, - "jss-compose": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jss-compose/-/jss-compose-5.0.0.tgz", - "integrity": "sha512-YofRYuiA0+VbeOw0VjgkyO380sA4+TWDrW52nSluD9n+1FWOlDzNbgpZ/Sb3Y46+DcAbOS21W5jo6SAqUEiuwA==", + "jss-plugin-compose": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-compose/-/jss-plugin-compose-10.8.2.tgz", + "integrity": "sha512-X7fDQJ6IlIJoT8A3zc++LuC1hmSGKVudb3LyXp+vHv8r2hzzfXEEZty3y2CaC5CGrWcLlYquXENjqLNmLYMgMA==", "requires": { - "warning": "^3.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" } }, - "jss-default-unit": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/jss-default-unit/-/jss-default-unit-8.0.2.tgz", - "integrity": "sha512-WxNHrF/18CdoAGw2H0FqOEvJdREXVXLazn7PQYU7V6/BWkCV0GkmWsppNiExdw8dP4TU1ma1dT9zBNJ95feLmg==" + "jss-plugin-default-unit": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz", + "integrity": "sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" + } }, - "jss-expand": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/jss-expand/-/jss-expand-5.3.0.tgz", - "integrity": "sha512-NiM4TbDVE0ykXSAw6dfFmB1LIqXP/jdd0ZMnlvlGgEMkMt+weJIl8Ynq1DsuBY9WwkNyzWktdqcEW2VN0RAtQg==" + "jss-plugin-expand": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-expand/-/jss-plugin-expand-10.8.2.tgz", + "integrity": "sha512-Iy4qsZbEcomXz5aBZJYGwnzK23vK3hqlwGleqmd19fY3L+WbqTmUnW8W0fWeXSuCkw2NknBTAJuEpFcgm3b0Pw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" + } }, - "jss-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jss-extend/-/jss-extend-6.2.0.tgz", - "integrity": "sha512-YszrmcB6o9HOsKPszK7NeDBNNjVyiW864jfoiHoMlgMIg2qlxKw70axZHqgczXHDcoyi/0/ikP1XaHDPRvYtEA==", + "jss-plugin-extend": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-extend/-/jss-plugin-extend-10.8.2.tgz", + "integrity": "sha512-NYu0cJ/Zb50ySPkegzbXQQfhXza0VpaRVXdXDex30yXqZpGcAdmhSg4HTv8vzHiL1v3uIOm641FYQX9WvLgSWw==", "requires": { - "warning": "^3.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" } }, - "jss-global": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jss-global/-/jss-global-3.0.0.tgz", - "integrity": "sha512-wxYn7vL+TImyQYGAfdplg7yaxnPQ9RaXY/cIA8hawaVnmmWxDHzBK32u1y+RAvWboa3lW83ya3nVZ/C+jyjZ5Q==" + "jss-plugin-global": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz", + "integrity": "sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" + } }, - "jss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jss-nested/-/jss-nested-6.0.1.tgz", - "integrity": "sha512-rn964TralHOZxoyEgeq3hXY8hyuCElnvQoVrQwKHVmu55VRDd6IqExAx9be5HgK0yN/+hQdgAXQl/GUrBbbSTA==", + "jss-plugin-nested": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz", + "integrity": "sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA==", "requires": { - "warning": "^3.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" } }, - "jss-preset-default": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-4.5.0.tgz", - "integrity": "sha512-qZbpRVtHT7hBPpZEBPFfafZKWmq3tA/An5RNqywDsZQGrlinIF/mGD9lmj6jGqu8GrED2SMHZ3pPKLmjCZoiaQ==", - "requires": { - "jss-camel-case": "^6.1.0", - "jss-compose": "^5.0.0", - "jss-default-unit": "^8.0.2", - "jss-expand": "^5.3.0", - "jss-extend": "^6.2.0", - "jss-global": "^3.0.0", - "jss-nested": "^6.0.1", - "jss-props-sort": "^6.0.0", - "jss-template": "^1.0.1", - "jss-vendor-prefixer": "^7.0.0" - } - }, - "jss-props-sort": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/jss-props-sort/-/jss-props-sort-6.0.0.tgz", - "integrity": "sha512-E89UDcrphmI0LzmvYk25Hp4aE5ZBsXqMWlkFXS0EtPkunJkRr+WXdCNYbXbksIPnKlBenGB9OxzQY+mVc70S+g==" + "jss-plugin-props-sort": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz", + "integrity": "sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" + } }, - "jss-template": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jss-template/-/jss-template-1.0.1.tgz", - "integrity": "sha512-m5BqEWha17fmIVXm1z8xbJhY6GFJxNB9H68GVnCWPyGYfxiAgY9WTQyvDAVj+pYRgrXSOfN5V1T4+SzN1sJTeg==", + "jss-plugin-rule-value-function": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz", + "integrity": "sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug==", "requires": { - "warning": "^3.0.0" + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" } }, - "jss-vendor-prefixer": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/jss-vendor-prefixer/-/jss-vendor-prefixer-7.0.0.tgz", - "integrity": "sha512-Agd+FKmvsI0HLcYXkvy8GYOw3AAASBUpsmIRvVQheps+JWaN892uFOInTr0DRydwaD91vSSUCU4NssschvF7MA==", + "jss-plugin-rule-value-observable": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-observable/-/jss-plugin-rule-value-observable-10.8.2.tgz", + "integrity": "sha512-NaJCfsEg8/6l/E8HstwL2w8kHj2LHhwoG4fXxefmdvNKmJMwBpnjech5dEPL72It4bZfIIYoynWbyxo3Q0ZKQQ==", "requires": { - "css-vendor": "^0.3.8" + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "symbol-observable": "^1.2.0" + } + }, + "jss-plugin-template": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-template/-/jss-plugin-template-10.8.2.tgz", + "integrity": "sha512-oTVwYRUCuCLslHxuH73F15kFmDxc4YEJIn8kHBnNpGr99ZbQdRIgPabosVTfkgE8czuyTx0KM5u8zEeuL+v66A==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz", + "integrity": "sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.8.2" + } + }, + "jss-preset-default": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-10.8.2.tgz", + "integrity": "sha512-mgkr6DAZuvkEleHFEpOkm8Y+sTdK/r0HH8PxToLHgaWHbYS0JAb0g1tBSUMG24kFj98VOYLTllK1o0J4lWU/uw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "jss-plugin-camel-case": "10.8.2", + "jss-plugin-compose": "10.8.2", + "jss-plugin-default-unit": "10.8.2", + "jss-plugin-expand": "10.8.2", + "jss-plugin-extend": "10.8.2", + "jss-plugin-global": "10.8.2", + "jss-plugin-nested": "10.8.2", + "jss-plugin-props-sort": "10.8.2", + "jss-plugin-rule-value-function": "10.8.2", + "jss-plugin-rule-value-observable": "10.8.2", + "jss-plugin-template": "10.8.2", + "jss-plugin-vendor-prefixer": "10.8.2" } }, "jsx-ast-utils": { @@ -48251,22 +48363,26 @@ } }, "mobx-react": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-5.4.4.tgz", - "integrity": "sha512-2mTzpyEjVB/RGk2i6KbcmP4HWcAUFox5ZRCrGvSyz49w20I4C4qql63grPpYrS9E9GKwgydBHQlA4y665LuRCQ==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-6.3.1.tgz", + "integrity": "sha512-IOxdJGnRSNSJrL2uGpWO5w9JH5q5HoxEqwOF4gye1gmZYdjoYkkMzSGMDnRCUpN/BNzZcFoMdHXrjvkwO7KgaQ==", "requires": { - "hoist-non-react-statics": "^3.0.0", - "react-lifecycles-compat": "^3.0.2" + "mobx-react-lite": "^2.2.0" } }, "mobx-react-form": { - "version": "1.35.1", - "resolved": "https://registry.npmjs.org/mobx-react-form/-/mobx-react-form-1.35.1.tgz", - "integrity": "sha1-iSrsZykiThHCl4+4LmetxOgOOmo=", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/mobx-react-form/-/mobx-react-form-2.0.9.tgz", + "integrity": "sha512-YLbtXVUF6BtifeVr6XWJ76dQWJs3T/+aPNI/DKvNs1Opcl4jNCzENahqlqNsNI+RgXZbP36zck//IGWBNZsr0A==", "requires": { - "lodash": "^4.16.2" + "lodash": "^4.17.11" } }, + "mobx-react-lite": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-2.2.2.tgz", + "integrity": "sha512-2SlXALHIkyUPDsV4VTKVR9DW7K3Ksh1aaIv3NrNJygTbhXe2A9GrcKHZ2ovIiOp/BXilOcTYemfHHZubP431dg==" + }, "mobx-react-router": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/mobx-react-router/-/mobx-react-router-3.1.2.tgz", @@ -50927,6 +51043,11 @@ "tween-functions": "^1.2.0" } }, + "react-display-name": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/react-display-name/-/react-display-name-0.2.5.tgz", + "integrity": "sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==" + }, "react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -50978,32 +51099,21 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "react-jss": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-8.6.1.tgz", - "integrity": "sha512-SH6XrJDJkAphp602J14JTy3puB2Zxz1FkM3bKVE8wON+va99jnUTKWnzGECb3NfIn9JPR5vHykge7K3/A747xQ==", + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-10.8.2.tgz", + "integrity": "sha512-/lLFIv1H6GA5RkvNb7TdXcJMBaSvSpfmSYsDisj4WI7MmqXUouoKfkZUJzG7CWq8xnIxik0WWYjFcGOvx0Sasw==", "requires": { - "hoist-non-react-statics": "^2.5.0", - "jss": "^9.7.0", - "jss-preset-default": "^4.3.0", + "@babel/runtime": "^7.3.1", + "@emotion/is-prop-valid": "^0.7.3", + "css-jss": "10.8.2", + "hoist-non-react-statics": "^3.2.0", + "is-in-browser": "^1.1.3", + "jss": "10.8.2", + "jss-preset-default": "10.8.2", "prop-types": "^15.6.0", - "theming": "^1.3.0" - }, - "dependencies": { - "hoist-non-react-statics": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", - "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" - }, - "jss": { - "version": "9.8.7", - "resolved": "https://registry.npmjs.org/jss/-/jss-9.8.7.tgz", - "integrity": "sha512-awj3XRZYxbrmmrx9LUSj5pXSUfm12m8xzi/VKeqI1ZwWBtQ0kVPTs3vYs32t4rFw83CgFDukA8wKzOE9sMQnoQ==", - "requires": { - "is-in-browser": "^1.1.3", - "symbol-observable": "^1.1.0", - "warning": "^3.0.0" - } - } + "shallow-equal": "^1.2.0", + "theming": "^3.3.0", + "tiny-warning": "^1.0.2" } }, "react-lifecycles-compat": { @@ -52484,6 +52594,11 @@ "kind-of": "^6.0.2" } }, + "shallow-equal": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", + "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -53776,14 +53891,14 @@ "dev": true }, "theming": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/theming/-/theming-1.3.0.tgz", - "integrity": "sha512-ya5Ef7XDGbTPBv5ENTwrwkPUexrlPeiAg/EI9kdlUAZhNlRbCdhMKRgjNX1IcmsmiPcqDQZE6BpSaH+cr31FKw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/theming/-/theming-3.3.0.tgz", + "integrity": "sha512-u6l4qTJRDaWZsqa8JugaNt7Xd8PPl9+gonZaIe28vAhqgHMIG/DOyFPqiKN/gQLQYj05tHv+YQdNILL4zoiAVA==", "requires": { - "brcast": "^3.0.1", - "is-function": "^1.0.1", - "is-plain-object": "^2.0.1", - "prop-types": "^15.5.8" + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.8", + "react-display-name": "^0.2.4", + "tiny-warning": "^1.0.2" } }, "throat": { diff --git a/package.json b/package.json index 5f733a501..8135f0ba3 100644 --- a/package.json +++ b/package.json @@ -88,8 +88,8 @@ "minimist": "^1.2.5", "mobx": "^5.15.0", "mobx-localstorage": "^1.2.0", - "mobx-react": "^5.4.2", - "mobx-react-form": "1.35.1", + "mobx-react": "^6.3.1", + "mobx-react-form": "^2.0.9", "mobx-react-router": "^3.1.2", "moment": "^2.29.1", "ms": "^2.1.3", @@ -105,7 +105,7 @@ "react-dropzone": "^11.4.2", "react-electron-web-view": "^2.0.1", "react-intl": "^5.21.0", - "react-jss": "^8.6.1", + "react-jss": "^10.8.2", "react-loader": "^2.4.7", "react-modal": "^3.14.3", "react-router": "^3.2.6", diff --git a/src/I18n.tsx b/src/I18n.tsx index 39b5273c1..5d969da1f 100644 --- a/src/I18n.tsx +++ b/src/I18n.tsx @@ -16,8 +16,6 @@ type Props = { children: ReactNode; }; -@inject('stores') -@observer class I18N extends Component { componentDidUpdate() { window['ferdi'].menu.rebuild(); @@ -39,4 +37,4 @@ class I18N extends Component { } } -export default I18N; +export default inject('stores')(observer(I18N)); diff --git a/src/components/auth/AuthLayout.js b/src/components/auth/AuthLayout.js index f26282cfc..94ff5d54d 100644 --- a/src/components/auth/AuthLayout.js +++ b/src/components/auth/AuthLayout.js @@ -19,7 +19,6 @@ import AppUpdateInfoBar from '../AppUpdateInfoBar'; import { GITHUB_FERDI_URL } from '../../config'; import { Icon } from '../ui/icon'; -@observer class AuthLayout extends Component { static propTypes = { children: oneOrManyChildElements.isRequired, @@ -107,4 +106,4 @@ class AuthLayout extends Component { } } -export default injectIntl(AuthLayout); +export default injectIntl(observer(AuthLayout)); diff --git a/src/components/auth/ChangeServer.js b/src/components/auth/ChangeServer.js index 9aeebc5c8..c284c0d19 100644 --- a/src/components/auth/ChangeServer.js +++ b/src/components/auth/ChangeServer.js @@ -34,7 +34,6 @@ const messages = defineMessages({ }, }); -@observer class ChangeServer extends Component { static propTypes = { onSubmit: PropTypes.func.isRequired, @@ -131,4 +130,4 @@ class ChangeServer extends Component { } } -export default injectIntl(ChangeServer); +export default injectIntl(observer(ChangeServer)); diff --git a/src/components/auth/Import.js b/src/components/auth/Import.js index fe2fe9872..8f70318ed 100644 --- a/src/components/auth/Import.js +++ b/src/components/auth/Import.js @@ -28,7 +28,6 @@ const messages = defineMessages({ }, }); -@observer class Import extends Component { static propTypes = { services: MobxPropTypes.arrayOrObservableArray.isRequired, @@ -166,4 +165,4 @@ class Import extends Component { } } -export default injectIntl(Import); +export default injectIntl(observer(Import)); diff --git a/src/components/auth/Invite.js b/src/components/auth/Invite.js index dd71c2450..a23af7c6b 100644 --- a/src/components/auth/Invite.js +++ b/src/components/auth/Invite.js @@ -43,7 +43,6 @@ const messages = defineMessages({ }, }); -@observer class Invite extends Component { static propTypes = { onSubmit: PropTypes.func.isRequired, @@ -198,4 +197,4 @@ class Invite extends Component { } } -export default injectIntl(Invite); +export default injectIntl(observer(Invite)); diff --git a/src/components/auth/Locked.js b/src/components/auth/Locked.js index 5b36b9fc2..2ed429199 100644 --- a/src/components/auth/Locked.js +++ b/src/components/auth/Locked.js @@ -48,7 +48,6 @@ const messages = defineMessages({ }, }); -@observer class Locked extends Component { static propTypes = { onSubmit: PropTypes.func.isRequired, @@ -149,4 +148,4 @@ class Locked extends Component { } } -export default injectIntl(Locked); +export default injectIntl(observer(Locked)); diff --git a/src/components/auth/Login.js b/src/components/auth/Login.js index 0c327d67e..c1602a047 100644 --- a/src/components/auth/Login.js +++ b/src/components/auth/Login.js @@ -71,8 +71,6 @@ const messages = defineMessages({ }, }); -@inject('actions') -@observer class Login extends Component { static propTypes = { onSubmit: PropTypes.func.isRequired, @@ -215,4 +213,4 @@ class Login extends Component { } } -export default injectIntl(Login); +export default injectIntl(inject('actions')(observer(Login))); diff --git a/src/components/auth/Password.js b/src/components/auth/Password.js index d5bc7fa80..b4d51f43d 100644 --- a/src/components/auth/Password.js +++ b/src/components/auth/Password.js @@ -38,7 +38,6 @@ const messages = defineMessages({ }, }); -@observer class Password extends Component { static propTypes = { onSubmit: PropTypes.func.isRequired, @@ -119,4 +118,4 @@ class Password extends Component { } } -export default injectIntl(Password); +export default injectIntl(observer(Password)); diff --git a/src/components/auth/SetupAssistant.js b/src/components/auth/SetupAssistant.js index 47fe88f43..a24f4e4d5 100644 --- a/src/components/auth/SetupAssistant.js +++ b/src/components/auth/SetupAssistant.js @@ -131,8 +131,6 @@ const styles = theme => ({ }, }); -@injectSheet(styles) -@observer class SetupAssistant extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -327,4 +325,6 @@ class SetupAssistant extends Component { } } -export default injectIntl(SetupAssistant); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(SetupAssistant)), +); diff --git a/src/components/auth/Signup.js b/src/components/auth/Signup.js index 00625a3ac..ac86dcdc3 100644 --- a/src/components/auth/Signup.js +++ b/src/components/auth/Signup.js @@ -75,8 +75,6 @@ const messages = defineMessages({ }, }); -@inject('actions') -@observer class Signup extends Component { static propTypes = { onSubmit: PropTypes.func.isRequired, @@ -217,4 +215,4 @@ class Signup extends Component { } } -export default injectIntl(Signup); +export default injectIntl(inject('actions')(observer(Signup))); diff --git a/src/components/auth/Welcome.js b/src/components/auth/Welcome.js index 809ec67a7..794c78987 100644 --- a/src/components/auth/Welcome.js +++ b/src/components/auth/Welcome.js @@ -22,8 +22,6 @@ const messages = defineMessages({ }, }); -@inject('actions') -@observer class Login extends Component { static propTypes = { loginRoute: PropTypes.string.isRequired, @@ -93,4 +91,4 @@ class Login extends Component { } } -export default injectIntl(Login); +export default injectIntl(inject('actions')(observer(Login))); diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index a31419a5e..084d93ecd 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js @@ -74,8 +74,6 @@ const toggleFullScreen = () => { ipcRenderer.send('window.toolbar-double-clicked'); }; -@injectSheet(styles) -@observer class AppLayout extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -208,4 +206,6 @@ class AppLayout extends Component { } } -export default injectIntl(AppLayout); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(AppLayout)), +); diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index 728613f42..4f67a8719 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js @@ -66,8 +66,6 @@ const messages = defineMessages({ }, }); -@inject('stores', 'actions') -@observer class Sidebar extends Component { static propTypes = { openSettings: PropTypes.func.isRequired, @@ -262,4 +260,4 @@ class Sidebar extends Component { } } -export default injectIntl(Sidebar); +export default injectIntl(inject('stores', 'actions')(observer(Sidebar))); diff --git a/src/components/services/content/ConnectionLostBanner.js b/src/components/services/content/ConnectionLostBanner.js index b9e7eca53..5adb22c84 100644 --- a/src/components/services/content/ConnectionLostBanner.js +++ b/src/components/services/content/ConnectionLostBanner.js @@ -68,8 +68,6 @@ const styles = theme => ({ }, }); -@injectSheet(styles) -@observer class ConnectionLostBanner extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -103,4 +101,4 @@ class ConnectionLostBanner extends Component { } } -export default injectIntl(ConnectionLostBanner); +export default injectIntl(injectSheet(styles)(observer(ConnectionLostBanner))); diff --git a/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js b/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js index 5c93de80f..d605b3a52 100644 --- a/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js +++ b/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js @@ -31,8 +31,6 @@ const messages = defineMessages({ }, }); -@injectSheet(styles) -@observer class WebviewErrorHandler extends Component { static propTypes = { name: PropTypes.string.isRequired, @@ -71,4 +69,6 @@ class WebviewErrorHandler extends Component { } } -export default injectIntl(WebviewErrorHandler); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(WebviewErrorHandler)), +); diff --git a/src/components/services/content/ServiceDisabled.js b/src/components/services/content/ServiceDisabled.js index f60d4bca6..b4658618e 100644 --- a/src/components/services/content/ServiceDisabled.js +++ b/src/components/services/content/ServiceDisabled.js @@ -16,7 +16,6 @@ const messages = defineMessages({ }, }); -@observer class ServiceDisabled extends Component { static propTypes = { name: PropTypes.string.isRequired, @@ -40,4 +39,4 @@ class ServiceDisabled extends Component { } } -export default injectIntl(ServiceDisabled); +export default injectIntl(observer(ServiceDisabled)); diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js index 1ffdd2153..6fc1f1400 100644 --- a/src/components/services/content/ServiceView.js +++ b/src/components/services/content/ServiceView.js @@ -16,8 +16,6 @@ import SettingsStore from '../../../stores/SettingsStore'; import WebControlsScreen from '../../../features/webControls/containers/WebControlsScreen'; import { CUSTOM_WEBSITE_RECIPE_ID } from '../../../config'; -@inject('stores', 'actions') -@observer class ServiceView extends Component { static propTypes = { service: PropTypes.instanceOf(ServiceModel).isRequired, @@ -163,4 +161,4 @@ class ServiceView extends Component { } } -export default ServiceView; +export default inject('stores', 'actions')(observer(ServiceView)); diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index c70494edd..713a0c21d 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js @@ -9,7 +9,6 @@ import ServiceModel from '../../../models/Service'; const debug = require('debug')('Ferdi:Services'); -@observer class ServiceWebview extends Component { static propTypes = { service: PropTypes.instanceOf(ServiceModel).isRequired, @@ -116,4 +115,4 @@ class ServiceWebview extends Component { } } -export default ServiceWebview; +export default observer(ServiceWebview); diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js index 1edf31bd3..0587b553f 100644 --- a/src/components/services/content/Services.js +++ b/src/components/services/content/Services.js @@ -44,9 +44,6 @@ const styles = { }, }; -@injectSheet(styles) -@inject('actions') -@observer class Services extends Component { static propTypes = { services: MobxPropTypes.arrayOrObservableArray, @@ -197,4 +194,8 @@ class Services extends Component { } } -export default injectIntl(Services); +export default injectIntl( + injectSheet(styles, { injectTheme: true })( + inject('actions')(observer(Services)), + ), +); diff --git a/src/components/services/content/WebviewCrashHandler.js b/src/components/services/content/WebviewCrashHandler.js index 3607435b3..1ca5ba415 100644 --- a/src/components/services/content/WebviewCrashHandler.js +++ b/src/components/services/content/WebviewCrashHandler.js @@ -26,7 +26,6 @@ const messages = defineMessages({ }, }); -@observer class WebviewCrashHandler extends Component { static propTypes = { name: PropTypes.string.isRequired, @@ -81,4 +80,4 @@ class WebviewCrashHandler extends Component { } } -export default injectIntl(WebviewCrashHandler); +export default injectIntl(observer(WebviewCrashHandler)); diff --git a/src/components/services/tabs/TabBarSortableList.js b/src/components/services/tabs/TabBarSortableList.js index 3049b6efa..e01461e5c 100644 --- a/src/components/services/tabs/TabBarSortableList.js +++ b/src/components/services/tabs/TabBarSortableList.js @@ -5,7 +5,6 @@ import { SortableContainer } from 'react-sortable-hoc'; import TabItem from './TabItem'; -@observer class TabBarSortableList extends Component { static propTypes = { services: MobxPropTypes.arrayOrObservableArray.isRequired, @@ -75,4 +74,4 @@ class TabBarSortableList extends Component { } } -export default SortableContainer(TabBarSortableList); +export default SortableContainer(observer(TabBarSortableList)); diff --git a/src/components/services/tabs/TabItem.js b/src/components/services/tabs/TabItem.js index 14be37153..8e163bce6 100644 --- a/src/components/services/tabs/TabItem.js +++ b/src/components/services/tabs/TabItem.js @@ -114,9 +114,6 @@ const styles = { }, }; -@injectSheet(styles) -@inject('stores') -@observer class TabItem extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -402,4 +399,10 @@ class TabItem extends Component { } } -export default injectIntl(SortableElement(TabItem)); +export default injectIntl( + SortableElement( + injectSheet(styles, { injectTheme: true })( + inject('stores')(observer(TabItem)), + ), + ), +); diff --git a/src/components/services/tabs/Tabbar.js b/src/components/services/tabs/Tabbar.js index 94d6f33c1..d9e11df41 100644 --- a/src/components/services/tabs/Tabbar.js +++ b/src/components/services/tabs/Tabbar.js @@ -4,7 +4,6 @@ import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; import TabBarSortableList from './TabBarSortableList'; -@observer class TabBar extends Component { static propTypes = { services: MobxPropTypes.arrayOrObservableArray.isRequired, @@ -120,4 +119,4 @@ class TabBar extends Component { } } -export default TabBar; +export default observer(TabBar); diff --git a/src/components/settings/SettingsLayout.js b/src/components/settings/SettingsLayout.js index e9119a944..de13e95ab 100644 --- a/src/components/settings/SettingsLayout.js +++ b/src/components/settings/SettingsLayout.js @@ -16,7 +16,6 @@ const messages = defineMessages({ }, }); -@observer class SettingsLayout extends Component { static propTypes = { navigation: PropTypes.element.isRequired, @@ -78,4 +77,4 @@ class SettingsLayout extends Component { } } -export default injectIntl(SettingsLayout); +export default injectIntl(observer(SettingsLayout)); diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js index 6c489e64b..d0c56af05 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js @@ -64,7 +64,6 @@ const messages = defineMessages({ }, }); -@observer class AccountDashboard extends Component { static propTypes = { user: MobxPropTypes.observableObject.isRequired, @@ -229,4 +228,4 @@ class AccountDashboard extends Component { } } -export default injectIntl(AccountDashboard); +export default injectIntl(observer(AccountDashboard)); diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index dbb1365b0..2fdb6e574 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js @@ -42,8 +42,6 @@ const messages = defineMessages({ }, }); -@inject('stores', 'actions') -@observer class SettingsNavigation extends Component { static propTypes = { stores: PropTypes.shape({ @@ -175,4 +173,4 @@ class SettingsNavigation extends Component { } } -export default injectIntl(SettingsNavigation); +export default injectIntl(inject('stores', 'actions')(observer(SettingsNavigation))); diff --git a/src/components/settings/recipes/RecipeItem.js b/src/components/settings/recipes/RecipeItem.js index 1e910e6dc..df5b42222 100644 --- a/src/components/settings/recipes/RecipeItem.js +++ b/src/components/settings/recipes/RecipeItem.js @@ -4,7 +4,6 @@ import { observer } from 'mobx-react'; import RecipePreviewModel from '../../../models/RecipePreview'; -@observer class RecipeItem extends Component { static propTypes = { recipe: PropTypes.instanceOf(RecipePreviewModel).isRequired, @@ -31,4 +30,4 @@ class RecipeItem extends Component { } } -export default RecipeItem; +export default observer(RecipeItem); diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js index 7ec285431..d9f53d74e 100644 --- a/src/components/settings/recipes/RecipesDashboard.js +++ b/src/components/settings/recipes/RecipesDashboard.js @@ -105,8 +105,6 @@ const styles = { }, }; -@injectSheet(styles) -@observer class RecipesDashboard extends Component { static propTypes = { recipes: MobxPropTypes.arrayOrObservableArray.isRequired, @@ -247,16 +245,18 @@ class RecipesDashboard extends Component { {intl.formatMessage(messages.nothingFound)}

- - isLoggedIn && - showAddServiceInterface({ - recipeId: customWebsiteRecipe.id, - }) - } - /> + {customWebsiteRecipe && customWebsiteRecipe.id && ( + + isLoggedIn && + showAddServiceInterface({ + recipeId: customWebsiteRecipe.id, + }) + } + /> + )} )} {communityRecipes.map(recipe => ( @@ -295,4 +295,6 @@ class RecipesDashboard extends Component { } } -export default injectIntl(RecipesDashboard); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(RecipesDashboard)), +); diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index 6b4cc721d..f0e791b87 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js @@ -134,7 +134,6 @@ const messages = defineMessages({ }, }); -@observer class EditServiceForm extends Component { static propTypes = { recipe: PropTypes.instanceOf(Recipe).isRequired, @@ -500,4 +499,4 @@ class EditServiceForm extends Component { } } -export default injectIntl(EditServiceForm); +export default injectIntl(observer(EditServiceForm)); diff --git a/src/components/settings/services/ServiceError.js b/src/components/settings/services/ServiceError.js index 6dd53a102..bcbbca3de 100644 --- a/src/components/settings/services/ServiceError.js +++ b/src/components/settings/services/ServiceError.js @@ -25,7 +25,6 @@ const messages = defineMessages({ }, }); -@observer class ServiceError extends Component { render() { const { intl } = this.props; @@ -60,4 +59,4 @@ class ServiceError extends Component { } } -export default injectIntl(ServiceError); +export default injectIntl(observer(ServiceError)); diff --git a/src/components/settings/services/ServiceItem.js b/src/components/settings/services/ServiceItem.js index d83e5fd56..23250ad09 100644 --- a/src/components/settings/services/ServiceItem.js +++ b/src/components/settings/services/ServiceItem.js @@ -24,7 +24,6 @@ const messages = defineMessages({ }, }); -@observer class ServiceItem extends Component { static propTypes = { service: PropTypes.instanceOf(ServiceModel).isRequired, @@ -91,4 +90,4 @@ class ServiceItem extends Component { } } -export default injectIntl(ServiceItem); +export default injectIntl(observer(ServiceItem)); diff --git a/src/components/settings/services/ServicesDashboard.js b/src/components/settings/services/ServicesDashboard.js index aae6eb855..81c5faa70 100644 --- a/src/components/settings/services/ServicesDashboard.js +++ b/src/components/settings/services/ServicesDashboard.js @@ -51,7 +51,6 @@ const messages = defineMessages({ }, }); -@observer class ServicesDashboard extends Component { static propTypes = { services: MobxPropTypes.arrayOrObservableArray.isRequired, @@ -188,4 +187,4 @@ class ServicesDashboard extends Component { } } -export default injectIntl(ServicesDashboard); +export default injectIntl(observer(ServicesDashboard)); diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index 9f51b54d5..d9df9c41c 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js @@ -188,7 +188,6 @@ const messages = defineMessages({ const Hr = () =>
; -@observer class EditSettingsForm extends Component { static propTypes = { checkForUpdates: PropTypes.func.isRequired, @@ -847,4 +846,4 @@ class EditSettingsForm extends Component { } } -export default injectIntl(EditSettingsForm); +export default injectIntl(observer(EditSettingsForm)); diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js index 38d124266..802284051 100644 --- a/src/components/settings/team/TeamDashboard.js +++ b/src/components/settings/team/TeamDashboard.js @@ -90,8 +90,6 @@ const styles = { }, }; -@injectSheet(styles) -@observer class TeamDashboard extends Component { static propTypes = { isLoading: PropTypes.bool.isRequired, @@ -197,4 +195,6 @@ class TeamDashboard extends Component { } } -export default injectIntl(TeamDashboard); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(TeamDashboard)), +); diff --git a/src/components/settings/user/EditUserForm.js b/src/components/settings/user/EditUserForm.js index 1b8a4f25a..95498d9bb 100644 --- a/src/components/settings/user/EditUserForm.js +++ b/src/components/settings/user/EditUserForm.js @@ -37,7 +37,6 @@ const messages = defineMessages({ }, }); -@observer class EditUserForm extends Component { static propTypes = { status: MobxPropTypes.observableArray.isRequired, @@ -128,4 +127,4 @@ class EditUserForm extends Component { } } -export default injectIntl(EditUserForm); +export default injectIntl(observer(EditUserForm)); diff --git a/src/components/ui/AppLoader/index.tsx b/src/components/ui/AppLoader/index.tsx index c7c290a57..0bb9cb50f 100644 --- a/src/components/ui/AppLoader/index.tsx +++ b/src/components/ui/AppLoader/index.tsx @@ -1,7 +1,7 @@ import { Component } from 'react'; -import injectSheet, { withTheme } from 'react-jss'; import classnames from 'classnames'; +import injectStyle from 'react-jss'; import FullscreenLoader from '../FullscreenLoader'; import { shuffleArray } from '../../../helpers/array-helpers'; @@ -24,8 +24,6 @@ type Props = { texts: string[]; }; -@injectSheet(styles) -@withTheme class AppLoader extends Component { static defaultProps = { texts: textList, @@ -77,4 +75,4 @@ class AppLoader extends Component { } } -export default AppLoader; +export default injectStyle(styles, { injectTheme: true })(AppLoader); diff --git a/src/components/ui/Button.js b/src/components/ui/Button.js index d90a8d62d..a52f1cadb 100644 --- a/src/components/ui/Button.js +++ b/src/components/ui/Button.js @@ -4,8 +4,6 @@ import { observer, inject } from 'mobx-react'; import Loader from 'react-loader'; import classnames from 'classnames'; -@inject('stores') -@observer class Button extends Component { static propTypes = { className: PropTypes.string, @@ -90,4 +88,4 @@ class Button extends Component { } } -export default Button; +export default inject('stores')(observer(Button)); diff --git a/src/components/ui/FAB.tsx b/src/components/ui/FAB.tsx index 0d871e948..cb9c5f126 100644 --- a/src/components/ui/FAB.tsx +++ b/src/components/ui/FAB.tsx @@ -14,7 +14,6 @@ type Props = { htmlForm: string; }; -@observer class Button extends Component { static defaultProps = { disabled: false, @@ -46,4 +45,4 @@ class Button extends Component { } } -export default Button; +export default observer(Button); diff --git a/src/components/ui/FullscreenLoader/index.js b/src/components/ui/FullscreenLoader/index.js index f5943f3f3..39b6c5a4c 100644 --- a/src/components/ui/FullscreenLoader/index.js +++ b/src/components/ui/FullscreenLoader/index.js @@ -1,16 +1,13 @@ import { Component } from 'react'; import PropTypes from 'prop-types'; import { observer } from 'mobx-react'; -import injectSheet, { withTheme } from 'react-jss'; +import injectStyle from 'react-jss'; import classnames from 'classnames'; import Loader from '../Loader'; import styles from './styles'; -@withTheme -@injectSheet(styles) -@observer class FullscreenLoader extends Component { static propTypes = { className: PropTypes.string, @@ -48,4 +45,6 @@ class FullscreenLoader extends Component { } } -export default FullscreenLoader; +export default injectStyle(styles, { injectTheme: true })( + observer(FullscreenLoader), +); diff --git a/src/components/ui/ImageUpload.tsx b/src/components/ui/ImageUpload.tsx index 52c097ef0..b07e211c2 100644 --- a/src/components/ui/ImageUpload.tsx +++ b/src/components/ui/ImageUpload.tsx @@ -15,7 +15,6 @@ type Props = { textUpload: string; }; -@observer class ImageUpload extends Component { static defaultProps = { multiple: false, @@ -102,4 +101,4 @@ class ImageUpload extends Component { } } -export default ImageUpload; +export default observer(ImageUpload); diff --git a/src/components/ui/InfoBar.js b/src/components/ui/InfoBar.js index 89b085907..c1a6013c2 100644 --- a/src/components/ui/InfoBar.js +++ b/src/components/ui/InfoBar.js @@ -16,7 +16,6 @@ const messages = defineMessages({ }, }); -@observer class InfoBar extends Component { static propTypes = { // eslint-disable-next-line react/forbid-prop-types @@ -102,4 +101,4 @@ class InfoBar extends Component { } } -export default injectIntl(InfoBar); +export default injectIntl(observer(InfoBar)); diff --git a/src/components/ui/Infobox.js b/src/components/ui/Infobox.js index c0ba8f13c..6634a6808 100644 --- a/src/components/ui/Infobox.js +++ b/src/components/ui/Infobox.js @@ -19,7 +19,6 @@ const messages = defineMessages({ }, }); -@observer class Infobox extends Component { static propTypes = { // eslint-disable-next-line react/forbid-prop-types @@ -112,4 +111,4 @@ class Infobox extends Component { } } -export default injectIntl(Infobox); +export default injectIntl(observer(Infobox)); diff --git a/src/components/ui/Input.js b/src/components/ui/Input.js index 8d37d7a05..fa1b44699 100644 --- a/src/components/ui/Input.js +++ b/src/components/ui/Input.js @@ -5,7 +5,9 @@ import { Field } from 'mobx-react-form'; import classnames from 'classnames'; import { defineMessages, injectIntl } from 'react-intl'; +import { mdiEye, mdiEyeOff } from '@mdi/js'; import { scorePassword as scorePasswordFunc } from '../../helpers/password-helpers'; +import { Icon } from './icon'; const messages = defineMessages({ passwordToggle: { @@ -14,7 +16,6 @@ const messages = defineMessages({ }, }); -@observer class Input extends Component { static propTypes = { field: PropTypes.instanceOf(Field).isRequired, @@ -115,9 +116,6 @@ class Input extends Component { type="button" className={classnames({ 'franz-form__input-modifier': true, - mdi: true, - 'mdi-eye': !this.state.showPassword, - 'mdi-eye-off': this.state.showPassword, })} onClick={() => this.setState(prevState => ({ @@ -126,7 +124,9 @@ class Input extends Component { } tabIndex={-1} aria-label={intl.formatMessage(messages.passwordToggle)} - /> + > + + )} {scorePassword && (
@@ -152,4 +152,4 @@ class Input extends Component { } } -export default injectIntl(Input); +export default injectIntl(observer(Input)); diff --git a/src/components/ui/Link.js b/src/components/ui/Link.js index 40766c984..565547736 100644 --- a/src/components/ui/Link.js +++ b/src/components/ui/Link.js @@ -9,8 +9,6 @@ import { matchRoute } from '../../helpers/routing-helpers'; import { openExternalUrl } from '../../helpers/url-helpers'; // TODO: create container component for this component -@inject('stores') -@observer class Link extends Component { onClick(e) { if (this.props.disabled) { @@ -60,7 +58,7 @@ class Link extends Component { } } -Link.wrappedComponent.propTypes = { +Link.propTypes = { stores: PropTypes.shape({ router: PropTypes.instanceOf(RouterStore).isRequired, }).isRequired, @@ -75,7 +73,7 @@ Link.wrappedComponent.propTypes = { disabled: PropTypes.bool, }; -Link.wrappedComponent.defaultProps = { +Link.defaultProps = { className: '', activeClassName: '', strictFilter: false, @@ -84,4 +82,4 @@ Link.wrappedComponent.defaultProps = { style: {}, }; -export default Link; +export default inject('stores')(observer(Link)); diff --git a/src/components/ui/Loader.tsx b/src/components/ui/Loader.tsx index 1173c11e7..171d0e290 100644 --- a/src/components/ui/Loader.tsx +++ b/src/components/ui/Loader.tsx @@ -12,8 +12,6 @@ type Props = { stores: FerdiStores; }; -@inject('stores') -@observer class LoaderComponent extends Component { static defaultProps = { loaded: false, @@ -43,4 +41,4 @@ class LoaderComponent extends Component { } } -export default LoaderComponent; +export default inject('stores')(observer(LoaderComponent)); diff --git a/src/components/ui/Modal/index.tsx b/src/components/ui/Modal/index.tsx index f2f4461b8..c3c78b419 100644 --- a/src/components/ui/Modal/index.tsx +++ b/src/components/ui/Modal/index.tsx @@ -18,7 +18,6 @@ type Props = { showClose: boolean; }; -@injectCSS(styles) class Modal extends Component { static defaultProps = { className: null, @@ -64,4 +63,4 @@ class Modal extends Component { } } -export default Modal; +export default injectCSS(styles)(Modal); diff --git a/src/components/ui/Radio.tsx b/src/components/ui/Radio.tsx index 594ea70e4..a033a5fe0 100644 --- a/src/components/ui/Radio.tsx +++ b/src/components/ui/Radio.tsx @@ -10,7 +10,6 @@ type Props = { showLabel: boolean; }; -@observer class Radio extends Component { static defaultProps = { focus: false, @@ -74,4 +73,4 @@ class Radio extends Component { } } -export default Radio; +export default observer(Radio); diff --git a/src/components/ui/SearchInput.tsx b/src/components/ui/SearchInput.tsx index 49a50a4a0..6a6a1692e 100644 --- a/src/components/ui/SearchInput.tsx +++ b/src/components/ui/SearchInput.tsx @@ -17,7 +17,6 @@ type Props = { autoFocus: boolean; }; -@observer class SearchInput extends Component { static defaultProps = { value: '', @@ -115,4 +114,4 @@ class SearchInput extends Component { } } -export default SearchInput; +export default observer(SearchInput); diff --git a/src/components/ui/Select.js b/src/components/ui/Select.js index a560da332..0fc32e573 100644 --- a/src/components/ui/Select.js +++ b/src/components/ui/Select.js @@ -4,7 +4,6 @@ import { observer } from 'mobx-react'; import { Field } from 'mobx-react-form'; import classnames from 'classnames'; -@observer class Select extends Component { static propTypes = { field: PropTypes.instanceOf(Field).isRequired, @@ -98,4 +97,4 @@ class Select extends Component { } } -export default Select; +export default observer(Select); diff --git a/src/components/ui/ServiceIcon.js b/src/components/ui/ServiceIcon.js index f067f8955..d403d107d 100644 --- a/src/components/ui/ServiceIcon.js +++ b/src/components/ui/ServiceIcon.js @@ -24,8 +24,6 @@ const styles = theme => ({ }, }); -@injectSheet(styles) -@observer class ServiceIcon extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -56,4 +54,6 @@ class ServiceIcon extends Component { } } -export default ServiceIcon; +export default injectSheet(styles, { injectTheme: true })( + observer(ServiceIcon), +); diff --git a/src/components/ui/Slider.js b/src/components/ui/Slider.js index dea6e0563..a581e7a65 100644 --- a/src/components/ui/Slider.js +++ b/src/components/ui/Slider.js @@ -4,7 +4,6 @@ import { observer } from 'mobx-react'; import classnames from 'classnames'; import { Field } from 'mobx-react-form'; -@observer class Slider extends Component { static propTypes = { field: PropTypes.instanceOf(Field).isRequired, @@ -64,4 +63,4 @@ class Slider extends Component { } } -export default Slider; +export default observer(Slider); diff --git a/src/components/ui/StatusBarTargetUrl.js b/src/components/ui/StatusBarTargetUrl.js index 38b436742..d8d329d52 100644 --- a/src/components/ui/StatusBarTargetUrl.js +++ b/src/components/ui/StatusBarTargetUrl.js @@ -5,7 +5,6 @@ import classnames from 'classnames'; import Appear from './effects/Appear'; -@observer class StatusBarTargetUrl extends Component { static propTypes = { className: PropTypes.string, @@ -33,4 +32,4 @@ class StatusBarTargetUrl extends Component { } } -export default StatusBarTargetUrl; +export default observer(StatusBarTargetUrl); diff --git a/src/components/ui/Tabs/Tabs.js b/src/components/ui/Tabs/Tabs.js index 77803974b..5d2da6293 100644 --- a/src/components/ui/Tabs/Tabs.js +++ b/src/components/ui/Tabs/Tabs.js @@ -5,7 +5,6 @@ import classnames from 'classnames'; import { oneOrManyChildElements } from '../../../prop-types'; -@observer class Tab extends Component { constructor(props) { super(props); @@ -69,4 +68,4 @@ class Tab extends Component { } } -export default Tab; +export default observer(Tab); diff --git a/src/components/ui/Toggle.js b/src/components/ui/Toggle.js index dfc319735..a82be690e 100644 --- a/src/components/ui/Toggle.js +++ b/src/components/ui/Toggle.js @@ -4,7 +4,6 @@ import { observer } from 'mobx-react'; import classnames from 'classnames'; import { Field } from 'mobx-react-form'; -@observer class Toggle extends Component { static propTypes = { field: PropTypes.instanceOf(Field).isRequired, @@ -69,4 +68,4 @@ class Toggle extends Component { } } -export default Toggle; +export default observer(Toggle); diff --git a/src/components/ui/ToggleRaw.js b/src/components/ui/ToggleRaw.js index 74292a870..e482b97b4 100644 --- a/src/components/ui/ToggleRaw.js +++ b/src/components/ui/ToggleRaw.js @@ -6,7 +6,6 @@ import PropTypes from 'prop-types'; import { observer } from 'mobx-react'; import classnames from 'classnames'; -@observer class ToggleRaw extends Component { static propTypes = { onChange: PropTypes.func.isRequired, @@ -74,4 +73,4 @@ class ToggleRaw extends Component { } } -export default ToggleRaw; +export default observer(ToggleRaw); diff --git a/src/components/ui/WebviewLoader/index.js b/src/components/ui/WebviewLoader/index.js index 8d4513172..20945d191 100644 --- a/src/components/ui/WebviewLoader/index.js +++ b/src/components/ui/WebviewLoader/index.js @@ -14,8 +14,6 @@ const messages = defineMessages({ }, }); -@injectSheet(styles) -@observer class WebviewLoader extends Component { static propTypes = { name: PropTypes.string.isRequired, @@ -34,4 +32,6 @@ class WebviewLoader extends Component { } } -export default injectIntl(WebviewLoader); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(WebviewLoader)), +); diff --git a/src/components/ui/badge/ProBadge.tsx b/src/components/ui/badge/ProBadge.tsx index dc1e76f7f..410748a64 100644 --- a/src/components/ui/badge/ProBadge.tsx +++ b/src/components/ui/badge/ProBadge.tsx @@ -1,14 +1,13 @@ import { mdiStar } from '@mdi/js'; import classnames from 'classnames'; import { Component } from 'react'; -import injectStyle from 'react-jss'; +import injectStyle, { WithStylesProps } from 'react-jss'; import { Theme } from '../../../themes'; import { Icon } from '../icon'; import { Badge } from './index'; -import { IWithStyle } from '../typings/generic'; -interface IProps extends IWithStyle { +interface IProps extends WithStylesProps { badgeClasses?: string; iconClasses?: string; inverted?: boolean; @@ -61,4 +60,6 @@ class ProBadgeComponent extends Component { } } -export const ProBadge = injectStyle(styles)(ProBadgeComponent); +export const ProBadge = injectStyle(styles, { injectTheme: true })( + ProBadgeComponent, +); diff --git a/src/components/ui/badge/index.tsx b/src/components/ui/badge/index.tsx index 61bede937..a7ed866a5 100644 --- a/src/components/ui/badge/index.tsx +++ b/src/components/ui/badge/index.tsx @@ -1,11 +1,10 @@ import classnames from 'classnames'; import { Component, ReactNode } from 'react'; -import injectStyle from 'react-jss'; +import injectStyle, { WithStylesProps } from 'react-jss'; import { Theme } from '../../../themes'; -import { IWithStyle } from '../typings/generic'; -interface IProps extends IWithStyle { +interface IProps extends WithStylesProps { type: string; className?: string; children: ReactNode; @@ -68,4 +67,4 @@ class BadgeComponent extends Component { } } -export const Badge = injectStyle(styles)(BadgeComponent); +export const Badge = injectStyle(styles, { injectTheme: true })(BadgeComponent); diff --git a/src/components/ui/button/index.tsx b/src/components/ui/button/index.tsx index 12e5e4449..d91b1ee19 100644 --- a/src/components/ui/button/index.tsx +++ b/src/components/ui/button/index.tsx @@ -2,11 +2,11 @@ import Icon from '@mdi/react'; import classnames from 'classnames'; import { Property } from 'csstype'; import { Component, MouseEvent } from 'react'; -import injectStyle, { withTheme } from 'react-jss'; +import injectStyle, { WithStylesProps } from 'react-jss'; import Loader from 'react-loader'; import { Theme } from '../../../themes'; -import { IFormField, IWithStyle } from '../typings/generic'; +import { IFormField } from '../typings/generic'; type ButtonType = | 'primary' @@ -16,7 +16,7 @@ type ButtonType = | 'warning' | 'inverted'; -interface IProps extends IFormField, IWithStyle { +interface IProps extends IFormField, WithStylesProps { className?: string; disabled?: boolean; id?: string; @@ -179,7 +179,7 @@ class ButtonComponent extends Component { const { classes, className, - theme, + // theme, disabled, id, label, @@ -213,7 +213,7 @@ class ButtonComponent extends Component { loaded={false} width={4} scale={0.45} - color={theme.buttonLoaderColor[buttonType!]} + // color={theme.buttonLoaderColor[buttonType!]} parentClassName={classes.loader} /> )} @@ -262,4 +262,6 @@ class ButtonComponent extends Component { } } -export const Button = injectStyle(styles)(withTheme(ButtonComponent)); +export const Button = injectStyle(styles, { injectTheme: true })( + ButtonComponent, +); diff --git a/src/components/ui/error/index.tsx b/src/components/ui/error/index.tsx index 8439bfc8b..ff3bc31c6 100644 --- a/src/components/ui/error/index.tsx +++ b/src/components/ui/error/index.tsx @@ -17,4 +17,4 @@ class ErrorComponent extends Component { } } -export const Error = injectSheet(styles)(ErrorComponent); +export const Error = injectSheet(styles, { injectTheme: true })(ErrorComponent); diff --git a/src/components/ui/headline/index.tsx b/src/components/ui/headline/index.tsx index ea2949102..d9954c38f 100644 --- a/src/components/ui/headline/index.tsx +++ b/src/components/ui/headline/index.tsx @@ -1,11 +1,11 @@ import classnames from 'classnames'; import { Component, createElement, ReactNode } from 'react'; -import injectStyle from 'react-jss'; +import injectStyle, { WithStylesProps } from 'react-jss'; import { Theme } from '../../../themes'; -import { IWithStyle, Omit } from '../typings/generic'; +import { Omit } from '../typings/generic'; -interface IProps extends IWithStyle { +interface IProps extends WithStylesProps { level?: number; className?: string; children: string | ReactNode; @@ -55,9 +55,9 @@ class HeadlineComponent extends Component { } } -const Headline = injectStyle(styles)(HeadlineComponent); +const Headline = injectStyle(styles, { injectTheme: true })(HeadlineComponent); -const createH = (level: number) => (props: Omit) => +const createH = (level: number) => (props: Omit) => ( {props.children} diff --git a/src/components/ui/icon/index.tsx b/src/components/ui/icon/index.tsx index 85bb61d13..52f61d2d7 100644 --- a/src/components/ui/icon/index.tsx +++ b/src/components/ui/icon/index.tsx @@ -1,12 +1,11 @@ import MdiIcon from '@mdi/react'; import classnames from 'classnames'; import { Component } from 'react'; -import injectStyle from 'react-jss'; +import injectStyle, { WithStylesProps } from 'react-jss'; import { Theme } from '../../../themes'; -import { IWithStyle } from '../typings/generic'; -interface IProps extends IWithStyle { +interface IProps extends WithStylesProps { icon: string; size?: number; className?: string; @@ -43,4 +42,4 @@ class IconComponent extends Component { } } -export const Icon = injectStyle(styles)(IconComponent); +export const Icon = injectStyle(styles, { injectTheme: true })(IconComponent); diff --git a/src/components/ui/infobox/index.tsx b/src/components/ui/infobox/index.tsx index 87940c4d4..7b2ce527b 100644 --- a/src/components/ui/infobox/index.tsx +++ b/src/components/ui/infobox/index.tsx @@ -1,13 +1,12 @@ import { mdiClose } from '@mdi/js'; import classnames from 'classnames'; import { Component, ReactNode } from 'react'; -import injectStyle from 'react-jss'; +import injectStyle, { WithStylesProps } from 'react-jss'; import { Theme } from '../../../themes'; import { Icon } from '../icon'; -import { IWithStyle } from '../typings/generic'; -interface IProps extends IWithStyle { +interface IProps extends WithStylesProps { icon?: string; type?: string; dismissable?: boolean; @@ -202,4 +201,6 @@ class InfoboxComponent extends Component { } } -export const Infobox = injectStyle(styles)(InfoboxComponent); +export const Infobox = injectStyle(styles, { injectTheme: true })( + InfoboxComponent, +); diff --git a/src/components/ui/input/index.tsx b/src/components/ui/input/index.tsx index c46cafc5c..bfbee33b9 100644 --- a/src/components/ui/input/index.tsx +++ b/src/components/ui/input/index.tsx @@ -2,9 +2,9 @@ import { mdiEye, mdiEyeOff } from '@mdi/js'; import Icon from '@mdi/react'; import classnames from 'classnames'; import { Component, createRef, InputHTMLAttributes } from 'react'; -import injectSheet from 'react-jss'; +import injectSheet, { WithStylesProps } from 'react-jss'; -import { IFormField, IWithStyle } from '../typings/generic'; +import { IFormField } from '../typings/generic'; import { Error } from '../error'; import { Label } from '../label'; @@ -20,7 +20,7 @@ interface IData { interface IProps extends InputHTMLAttributes, IFormField, - IWithStyle { + WithStylesProps { focus?: boolean; prefix?: string; suffix?: string; @@ -205,4 +205,4 @@ class InputComponent extends Component { } } -export const Input = injectSheet(styles)(InputComponent); +export const Input = injectSheet(styles, { injectTheme: true })(InputComponent); diff --git a/src/components/ui/label/index.tsx b/src/components/ui/label/index.tsx index 4d86f23f7..dcc14bff4 100644 --- a/src/components/ui/label/index.tsx +++ b/src/components/ui/label/index.tsx @@ -1,15 +1,16 @@ import classnames from 'classnames'; -import { Classes } from 'jss'; import { Component, LabelHTMLAttributes } from 'react'; -import injectSheet from 'react-jss'; +import injectSheet, { WithStylesProps } from 'react-jss'; import { IFormField } from '../typings/generic'; import styles from './styles'; -interface ILabel extends IFormField, LabelHTMLAttributes { - classes: Classes; - isRequired: boolean; +interface ILabel + extends IFormField, + LabelHTMLAttributes, + WithStylesProps { + isRequired?: boolean; } class LabelComponent extends Component { @@ -49,4 +50,4 @@ class LabelComponent extends Component { } } -export const Label = injectSheet(styles)(LabelComponent); +export const Label = injectSheet(styles, { injectTheme: true })(LabelComponent); diff --git a/src/components/ui/loader/index.tsx b/src/components/ui/loader/index.tsx index 0607bd48b..d56995ccc 100644 --- a/src/components/ui/loader/index.tsx +++ b/src/components/ui/loader/index.tsx @@ -1,25 +1,25 @@ import classnames from 'classnames'; import { Component } from 'react'; -import injectStyle, { withTheme } from 'react-jss'; +import injectStyle, { WithStylesProps } from 'react-jss'; import ReactLoader from 'react-loader'; -import { IWithStyle } from '../typings/generic'; - -interface IProps extends IWithStyle { +interface IProps extends WithStylesProps { className?: string; color?: string; } -const styles = () => ({ +const styles = theme => ({ container: { position: 'relative', height: 60, }, + loader: {}, + color: theme.colorText, }); class LoaderComponent extends Component { render() { - const { classes, className, color, theme } = this.props; + const { classes, className, color } = this.props; return (
{ loaded={false} width={4} scale={0.75} - color={color || theme.colorText} + color={color || classes.color} parentClassName={classes.loader} />
@@ -41,4 +41,6 @@ class LoaderComponent extends Component { } } -export const Loader = injectStyle(styles)(withTheme(LoaderComponent)); +export const Loader = injectStyle(styles, { injectTheme: true })( + LoaderComponent, +); diff --git a/src/components/ui/select/index.tsx b/src/components/ui/select/index.tsx index 2605503a3..ac509aa7c 100644 --- a/src/components/ui/select/index.tsx +++ b/src/components/ui/select/index.tsx @@ -6,10 +6,10 @@ import { import Icon from '@mdi/react'; import classnames from 'classnames'; import { ChangeEvent, Component, createRef } from 'react'; -import injectStyle from 'react-jss'; +import injectStyle, { WithStylesProps } from 'react-jss'; import { Theme } from '../../../themes'; -import { IFormField, IWithStyle } from '../typings/generic'; +import { IFormField } from '../typings/generic'; import { Error } from '../error'; import { Label } from '../label'; @@ -23,7 +23,7 @@ interface IData { [index: string]: string; } -interface IProps extends IFormField, IWithStyle { +interface IProps extends IFormField, WithStylesProps { actionText: string; className?: string; inputClassName?: string; @@ -146,6 +146,7 @@ const styles = (theme: Theme) => ({ disabled: { opacity: theme.selectDisabledOpacity, }, + input: {}, }); class SelectComponent extends Component { @@ -457,4 +458,6 @@ class SelectComponent extends Component { } } -export const Select = injectStyle(styles)(SelectComponent); +export const Select = injectStyle(styles, { injectTheme: true })( + SelectComponent, +); diff --git a/src/components/ui/textarea/index.tsx b/src/components/ui/textarea/index.tsx index 1b16698eb..a47465806 100644 --- a/src/components/ui/textarea/index.tsx +++ b/src/components/ui/textarea/index.tsx @@ -1,8 +1,8 @@ import classnames from 'classnames'; import { Component, createRef, TextareaHTMLAttributes } from 'react'; -import injectSheet from 'react-jss'; +import injectSheet, { WithStylesProps } from 'react-jss'; -import { IFormField, IWithStyle } from '../typings/generic'; +import { IFormField } from '../typings/generic'; import { Error } from '../error'; import { Label } from '../label'; @@ -17,7 +17,7 @@ interface IData { interface IProps extends TextareaHTMLAttributes, IFormField, - IWithStyle { + WithStylesProps { focus?: boolean; data: IData; textareaClassName?: string; @@ -123,4 +123,6 @@ class TextareaComponent extends Component { } } -export const Textarea = injectSheet(styles)(TextareaComponent); +export const Textarea = injectSheet(styles, { injectTheme: true })( + TextareaComponent, +); diff --git a/src/components/ui/toggle/index.tsx b/src/components/ui/toggle/index.tsx index 7b6ba147f..856581a21 100644 --- a/src/components/ui/toggle/index.tsx +++ b/src/components/ui/toggle/index.tsx @@ -1,10 +1,10 @@ import classnames from 'classnames'; import { Property } from 'csstype'; import { Component, InputHTMLAttributes } from 'react'; -import injectStyle from 'react-jss'; +import injectStyle, { WithStylesProps } from 'react-jss'; import { Theme } from '../../../themes'; -import { IFormField, IWithStyle } from '../typings/generic'; +import { IFormField } from '../typings/generic'; import { Error } from '../error'; import { Label } from '../label'; @@ -13,7 +13,7 @@ import { Wrapper } from '../wrapper'; interface IProps extends InputHTMLAttributes, IFormField, - IWithStyle { + WithStylesProps { className?: string; } @@ -122,4 +122,6 @@ class ToggleComponent extends Component { } } -export const Toggle = injectStyle(styles)(ToggleComponent); +export const Toggle = injectStyle(styles, { injectTheme: true })( + ToggleComponent, +); diff --git a/src/components/ui/typings/generic.ts b/src/components/ui/typings/generic.ts index 65b996d59..3aec0bc40 100644 --- a/src/components/ui/typings/generic.ts +++ b/src/components/ui/typings/generic.ts @@ -1,7 +1,3 @@ -import { Classes } from 'jss'; - -import { Theme } from '../../../themes'; - export interface IFormField { showLabel?: boolean; label?: string; @@ -10,10 +6,5 @@ export interface IFormField { noMargin?: boolean; } -export interface IWithStyle { - classes: Classes; - theme: Theme; -} - export type Merge = Omit> & N; export type Omit = Pick>; diff --git a/src/components/ui/wrapper/index.tsx b/src/components/ui/wrapper/index.tsx index ffcd6fe0b..bc385d319 100644 --- a/src/components/ui/wrapper/index.tsx +++ b/src/components/ui/wrapper/index.tsx @@ -1,9 +1,8 @@ import classnames from 'classnames'; import { Component, ReactNode } from 'react'; -import injectStyle from 'react-jss'; -import { IWithStyle } from '../typings/generic'; +import injectStyle, { WithStylesProps } from 'react-jss'; -interface IProps extends IWithStyle { +interface IProps extends WithStylesProps { children: ReactNode; className?: string; identifier: string; @@ -34,4 +33,6 @@ class WrapperComponent extends Component { } } -export const Wrapper = injectStyle(styles)(WrapperComponent); +export const Wrapper = injectStyle(styles, { injectTheme: true })( + WrapperComponent, +); diff --git a/src/components/util/ErrorBoundary/index.js b/src/components/util/ErrorBoundary/index.js index cddcd91c2..6a8b126f1 100644 --- a/src/components/util/ErrorBoundary/index.js +++ b/src/components/util/ErrorBoundary/index.js @@ -18,7 +18,6 @@ const messages = defineMessages({ }, }); -@injectSheet(styles) class ErrorBoundary extends Component { state = { hasError: false, @@ -56,4 +55,6 @@ class ErrorBoundary extends Component { } } -export default injectIntl(ErrorBoundary); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(ErrorBoundary), +); diff --git a/src/containers/auth/AuthLayoutContainer.js b/src/containers/auth/AuthLayoutContainer.js index aa36e3969..e6d6dcf8a 100644 --- a/src/containers/auth/AuthLayoutContainer.js +++ b/src/containers/auth/AuthLayoutContainer.js @@ -14,8 +14,6 @@ import AppLoader from '../../components/ui/AppLoader'; import { oneOrManyChildElements } from '../../prop-types'; import FeaturesStore from '../../stores/FeaturesStore'; -@inject('stores', 'actions') -@observer class AuthLayoutContainer extends Component { static propTypes = { children: oneOrManyChildElements.isRequired, @@ -71,7 +69,7 @@ class AuthLayoutContainer extends Component { } } -AuthLayoutContainer.wrappedComponent.propTypes = { +AuthLayoutContainer.propTypes = { stores: PropTypes.shape({ app: PropTypes.instanceOf(AppStore).isRequired, features: PropTypes.instanceOf(FeaturesStore).isRequired, @@ -85,4 +83,4 @@ AuthLayoutContainer.wrappedComponent.propTypes = { }).isRequired, }; -export default AuthLayoutContainer; +export default inject('stores', 'actions')(observer(AuthLayoutContainer)); diff --git a/src/containers/auth/ChangeServerScreen.js b/src/containers/auth/ChangeServerScreen.js index dcc913c39..60bfde088 100644 --- a/src/containers/auth/ChangeServerScreen.js +++ b/src/containers/auth/ChangeServerScreen.js @@ -5,8 +5,6 @@ import { RouterStore } from 'mobx-react-router'; import ChangeServer from '../../components/auth/ChangeServer'; import SettingsStore from '../../stores/SettingsStore'; -@inject('stores', 'actions') -@observer class ChangeServerScreen extends Component { constructor(props) { super(props); @@ -34,7 +32,7 @@ class ChangeServerScreen extends Component { } } -ChangeServerScreen.wrappedComponent.propTypes = { +ChangeServerScreen.propTypes = { actions: PropTypes.shape({ settings: PropTypes.instanceOf(SettingsStore).isRequired, }).isRequired, @@ -44,4 +42,4 @@ ChangeServerScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default ChangeServerScreen; +export default inject('stores', 'actions')(observer(ChangeServerScreen)); diff --git a/src/containers/auth/ImportScreen.js b/src/containers/auth/ImportScreen.js index 46e2d41f0..c01c3d355 100644 --- a/src/containers/auth/ImportScreen.js +++ b/src/containers/auth/ImportScreen.js @@ -5,8 +5,6 @@ import { RouterStore } from 'mobx-react-router'; import Import from '../../components/auth/Import'; import UserStore from '../../stores/UserStore'; -@inject('stores', 'actions') -@observer class ImportScreen extends Component { render() { const { actions, stores } = this.props; @@ -26,7 +24,7 @@ class ImportScreen extends Component { } } -ImportScreen.wrappedComponent.propTypes = { +ImportScreen.propTypes = { actions: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, }).isRequired, @@ -36,4 +34,4 @@ ImportScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default ImportScreen; +export default inject('stores', 'actions')(observer(ImportScreen)); diff --git a/src/containers/auth/InviteScreen.js b/src/containers/auth/InviteScreen.js index e252242ae..fc66227cc 100644 --- a/src/containers/auth/InviteScreen.js +++ b/src/containers/auth/InviteScreen.js @@ -3,8 +3,6 @@ import PropTypes from 'prop-types'; import { inject, observer } from 'mobx-react'; import Invite from '../../components/auth/Invite'; -@inject('stores', 'actions') -@observer class InviteScreen extends Component { render() { const { actions } = this.props; @@ -13,7 +11,7 @@ class InviteScreen extends Component { } } -InviteScreen.wrappedComponent.propTypes = { +InviteScreen.propTypes = { actions: PropTypes.shape({ user: PropTypes.shape({ invite: PropTypes.func.isRequired, @@ -21,4 +19,4 @@ InviteScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default InviteScreen; +export default inject('stores', 'actions')(observer(InviteScreen)); diff --git a/src/containers/auth/LockedScreen.js b/src/containers/auth/LockedScreen.js index 945e41284..87a00800f 100644 --- a/src/containers/auth/LockedScreen.js +++ b/src/containers/auth/LockedScreen.js @@ -7,8 +7,6 @@ import SettingsStore from '../../stores/SettingsStore'; import { hash } from '../../helpers/password-helpers'; import UserStore from '../../stores/UserStore'; -@inject('stores', 'actions') -@observer class LockedScreen extends Component { state = { error: false, @@ -76,7 +74,7 @@ class LockedScreen extends Component { } } -LockedScreen.wrappedComponent.propTypes = { +LockedScreen.propTypes = { actions: PropTypes.shape({ settings: PropTypes.instanceOf(SettingsStore).isRequired, }).isRequired, @@ -86,4 +84,4 @@ LockedScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default LockedScreen; +export default inject('stores', 'actions')(observer(LockedScreen)); diff --git a/src/containers/auth/LoginScreen.js b/src/containers/auth/LoginScreen.js index 3f8c67fa8..572a38ea1 100644 --- a/src/containers/auth/LoginScreen.js +++ b/src/containers/auth/LoginScreen.js @@ -6,8 +6,6 @@ import UserStore from '../../stores/UserStore'; import { globalError as globalErrorPropType } from '../../prop-types'; -@inject('stores', 'actions') -@observer class LoginScreen extends Component { static propTypes = { error: globalErrorPropType.isRequired, @@ -32,7 +30,7 @@ class LoginScreen extends Component { } } -LoginScreen.wrappedComponent.propTypes = { +LoginScreen.propTypes = { actions: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, }).isRequired, @@ -41,4 +39,4 @@ LoginScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default LoginScreen; +export default inject('stores', 'actions')(observer(LoginScreen)); diff --git a/src/containers/auth/PasswordScreen.js b/src/containers/auth/PasswordScreen.js index 836d4cc88..4b2c1b4a2 100644 --- a/src/containers/auth/PasswordScreen.js +++ b/src/containers/auth/PasswordScreen.js @@ -4,8 +4,6 @@ import { inject, observer } from 'mobx-react'; import Password from '../../components/auth/Password'; import UserStore from '../../stores/UserStore'; -@inject('stores', 'actions') -@observer class PasswordScreen extends Component { render() { const { actions, stores } = this.props; @@ -22,7 +20,7 @@ class PasswordScreen extends Component { } } -PasswordScreen.wrappedComponent.propTypes = { +PasswordScreen.propTypes = { actions: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, }).isRequired, @@ -31,4 +29,4 @@ PasswordScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default PasswordScreen; +export default inject('stores', 'actions')(observer(PasswordScreen)); diff --git a/src/containers/auth/SetupAssistantScreen.js b/src/containers/auth/SetupAssistantScreen.js index 8cdd95a88..f6392712d 100644 --- a/src/containers/auth/SetupAssistantScreen.js +++ b/src/containers/auth/SetupAssistantScreen.js @@ -14,8 +14,6 @@ import ServicesStore from '../../stores/ServicesStore'; import RecipesStore from '../../stores/RecipesStore'; import UserStore from '../../stores/UserStore'; -@inject('stores', 'actions') -@observer class SetupAssistantScreen extends Component { constructor(props) { super(props); @@ -120,7 +118,7 @@ class SetupAssistantScreen extends Component { } } -SetupAssistantScreen.wrappedComponent.propTypes = { +SetupAssistantScreen.propTypes = { stores: PropTypes.shape({ services: PropTypes.instanceOf(ServicesStore), router: PropTypes.instanceOf(RouterStore).isRequired, @@ -134,4 +132,4 @@ SetupAssistantScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default SetupAssistantScreen; +export default inject('stores', 'actions')(observer(SetupAssistantScreen)); diff --git a/src/containers/auth/SignupScreen.js b/src/containers/auth/SignupScreen.js index 3b19f3c50..1dd8d0772 100644 --- a/src/containers/auth/SignupScreen.js +++ b/src/containers/auth/SignupScreen.js @@ -8,8 +8,6 @@ import FeaturesStore from '../../stores/FeaturesStore'; import { globalError as globalErrorPropType } from '../../prop-types'; -@inject('stores', 'actions') -@observer class SignupScreen extends Component { static propTypes = { error: globalErrorPropType.isRequired, @@ -36,7 +34,7 @@ class SignupScreen extends Component { } } -SignupScreen.wrappedComponent.propTypes = { +SignupScreen.propTypes = { actions: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, }).isRequired, @@ -46,4 +44,4 @@ SignupScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default SignupScreen; +export default inject('stores', 'actions')(observer(SignupScreen)); diff --git a/src/containers/auth/WelcomeScreen.js b/src/containers/auth/WelcomeScreen.js index 7a23d9ba9..18b6b2eda 100644 --- a/src/containers/auth/WelcomeScreen.js +++ b/src/containers/auth/WelcomeScreen.js @@ -6,8 +6,6 @@ import Welcome from '../../components/auth/Welcome'; import UserStore from '../../stores/UserStore'; import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; -@inject('stores', 'actions') -@observer class LoginScreen extends Component { render() { const { user, recipePreviews } = this.props.stores; @@ -23,11 +21,11 @@ class LoginScreen extends Component { } } -LoginScreen.wrappedComponent.propTypes = { +LoginScreen.propTypes = { stores: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, recipePreviews: PropTypes.instanceOf(RecipePreviewsStore).isRequired, }).isRequired, }; -export default LoginScreen; +export default inject('stores', 'actions')(observer(LoginScreen)); diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index 50a28803f..9b0edc85e 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js @@ -24,8 +24,6 @@ import WorkspaceDrawer from '../../features/workspaces/components/WorkspaceDrawe import { workspaceStore } from '../../features/workspaces'; import WorkspacesStore from '../../features/workspaces/store'; -@inject('stores', 'actions') -@observer class AppLayoutContainer extends Component { static defaultProps = { children: null, @@ -171,7 +169,7 @@ class AppLayoutContainer extends Component { } } -AppLayoutContainer.wrappedComponent.propTypes = { +AppLayoutContainer.propTypes = { stores: PropTypes.shape({ services: PropTypes.instanceOf(ServicesStore).isRequired, features: PropTypes.instanceOf(FeaturesStore).isRequired, @@ -194,4 +192,4 @@ AppLayoutContainer.wrappedComponent.propTypes = { children: oneOrManyChildElements, }; -export default AppLayoutContainer; +export default inject('stores', 'actions')(observer(AppLayoutContainer)); diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js index f7c9b8164..aae230577 100644 --- a/src/containers/settings/AccountScreen.js +++ b/src/containers/settings/AccountScreen.js @@ -12,8 +12,6 @@ import ErrorBoundary from '../../components/util/ErrorBoundary'; import { LIVE_FRANZ_API } from '../../config'; import { WEBSITE } from '../../environment-remote'; -@inject('stores', 'actions') -@observer class AccountScreen extends Component { onCloseWindow() { const { user, features } = this.props.stores; @@ -74,7 +72,7 @@ class AccountScreen extends Component { } } -AccountScreen.wrappedComponent.propTypes = { +AccountScreen.propTypes = { stores: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, features: PropTypes.instanceOf(FeaturesStore).isRequired, @@ -87,4 +85,4 @@ AccountScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default AccountScreen; +export default inject('stores', 'actions')(observer(AccountScreen)); diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js index ddf7fab36..24b827993 100644 --- a/src/containers/settings/EditServiceScreen.js +++ b/src/containers/settings/EditServiceScreen.js @@ -111,8 +111,6 @@ const messages = defineMessages({ }, }); -@inject('stores', 'actions') -@observer class EditServiceScreen extends Component { onSubmit(data) { const { action } = this.props.router.params; @@ -438,7 +436,7 @@ class EditServiceScreen extends Component { } } -EditServiceScreen.wrappedComponent.propTypes = { +EditServiceScreen.propTypes = { stores: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, recipes: PropTypes.instanceOf(RecipesStore).isRequired, @@ -451,4 +449,6 @@ EditServiceScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default injectIntl(EditServiceScreen); +export default injectIntl( + inject('stores', 'actions')(observer(EditServiceScreen)), +); diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js index 720f2c8a1..ddf6876b9 100644 --- a/src/containers/settings/EditSettingsScreen.js +++ b/src/containers/settings/EditSettingsScreen.js @@ -245,8 +245,6 @@ const messages = defineMessages({ }, }); -@inject('stores', 'actions') -@observer class EditSettingsScreen extends Component { constructor(props) { super(props); @@ -753,7 +751,7 @@ class EditSettingsScreen extends Component { } } -EditSettingsScreen.wrappedComponent.propTypes = { +EditSettingsScreen.propTypes = { stores: PropTypes.shape({ app: PropTypes.instanceOf(AppStore).isRequired, user: PropTypes.instanceOf(UserStore).isRequired, @@ -771,4 +769,6 @@ EditSettingsScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default injectIntl(EditSettingsScreen); +export default injectIntl( + inject('stores', 'actions')(observer(EditSettingsScreen)), +); diff --git a/src/containers/settings/EditUserScreen.js b/src/containers/settings/EditUserScreen.js index 1dc0aa8e6..baa2d7b71 100644 --- a/src/containers/settings/EditUserScreen.js +++ b/src/containers/settings/EditUserScreen.js @@ -49,8 +49,6 @@ const messages = defineMessages({ }, }); -@inject('stores', 'actions') -@observer class EditUserScreen extends Component { componentWillUnmount() { this.props.actions.user.resetStatus(); @@ -150,7 +148,7 @@ class EditUserScreen extends Component { } } -EditUserScreen.wrappedComponent.propTypes = { +EditUserScreen.propTypes = { stores: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, }).isRequired, @@ -159,4 +157,6 @@ EditUserScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default injectIntl(EditUserScreen); +export default injectIntl( + inject('stores', 'actions')(observer(EditUserScreen)), +); diff --git a/src/containers/settings/InviteScreen.js b/src/containers/settings/InviteScreen.js index 592b4b11c..86723554c 100644 --- a/src/containers/settings/InviteScreen.js +++ b/src/containers/settings/InviteScreen.js @@ -6,8 +6,6 @@ import Invite from '../../components/auth/Invite'; import ErrorBoundary from '../../components/util/ErrorBoundary'; import UserStore from '../../stores/UserStore'; -@inject('stores', 'actions') -@observer class InviteScreen extends Component { componentWillUnmount() { this.props.stores.user.inviteRequest.reset(); @@ -32,7 +30,7 @@ class InviteScreen extends Component { } } -InviteScreen.wrappedComponent.propTypes = { +InviteScreen.propTypes = { actions: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, }).isRequired, @@ -41,4 +39,4 @@ InviteScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default InviteScreen; +export default inject('stores', 'actions')(observer(InviteScreen)); diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.js index 7f55e54c5..6b629d3d8 100644 --- a/src/containers/settings/RecipesScreen.js +++ b/src/containers/settings/RecipesScreen.js @@ -19,8 +19,6 @@ import RecipePreview from '../../models/RecipePreview'; import AppStore from '../../stores/AppStore'; import { openPath } from '../../helpers/url-helpers'; -@inject('stores', 'actions') -@observer class RecipesScreen extends Component { static propTypes = { params: PropTypes.shape({ @@ -182,7 +180,7 @@ class RecipesScreen extends Component { } } -RecipesScreen.wrappedComponent.propTypes = { +RecipesScreen.propTypes = { stores: PropTypes.shape({ recipePreviews: PropTypes.instanceOf(RecipePreviewsStore).isRequired, recipes: PropTypes.instanceOf(RecipeStore).isRequired, @@ -198,4 +196,4 @@ RecipesScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default RecipesScreen; +export default inject('stores', 'actions')(observer(RecipesScreen)); diff --git a/src/containers/settings/ServicesScreen.js b/src/containers/settings/ServicesScreen.js index a657b6e6c..2970b2a54 100644 --- a/src/containers/settings/ServicesScreen.js +++ b/src/containers/settings/ServicesScreen.js @@ -10,8 +10,6 @@ import ServiceStore from '../../stores/ServicesStore'; import ServicesDashboard from '../../components/settings/services/ServicesDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; -@inject('stores', 'actions') -@observer class ServicesScreen extends Component { componentWillUnmount() { this.props.actions.service.resetFilter(); @@ -57,7 +55,7 @@ class ServicesScreen extends Component { } } -ServicesScreen.wrappedComponent.propTypes = { +ServicesScreen.propTypes = { stores: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, services: PropTypes.instanceOf(ServiceStore).isRequired, @@ -68,4 +66,4 @@ ServicesScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default ServicesScreen; +export default inject('stores', 'actions')(observer(ServicesScreen)); diff --git a/src/containers/settings/SettingsWindow.js b/src/containers/settings/SettingsWindow.js index 35db3a434..0e6ce4df3 100644 --- a/src/containers/settings/SettingsWindow.js +++ b/src/containers/settings/SettingsWindow.js @@ -11,8 +11,6 @@ import ErrorBoundary from '../../components/util/ErrorBoundary'; import { workspaceStore } from '../../features/workspaces'; import UIStore from '../../stores/UIStore'; -@inject('stores', 'actions') -@observer class SettingsContainer extends Component { portalRoot = document.querySelector('#portalContainer'); @@ -48,7 +46,7 @@ class SettingsContainer extends Component { } } -SettingsContainer.wrappedComponent.propTypes = { +SettingsContainer.propTypes = { children: PropTypes.element.isRequired, stores: PropTypes.shape({ services: PropTypes.instanceOf(ServicesStore).isRequired, @@ -58,4 +56,4 @@ SettingsContainer.wrappedComponent.propTypes = { }).isRequired, }; -export default SettingsContainer; +export default inject('stores', 'actions')(observer(SettingsContainer)); diff --git a/src/containers/settings/SupportScreen.js b/src/containers/settings/SupportScreen.js index d3600f8ea..b4ad952b2 100644 --- a/src/containers/settings/SupportScreen.js +++ b/src/containers/settings/SupportScreen.js @@ -6,7 +6,6 @@ import SupportFerdi from '../../components/settings/supportFerdi/SupportFerdiDas import ErrorBoundary from '../../components/util/ErrorBoundary'; import AppStore from '../../stores/AppStore'; -@inject('actions') class SupportScreen extends Component { constructor(props) { super(props); @@ -27,10 +26,10 @@ class SupportScreen extends Component { } } -SupportScreen.wrappedComponent.propTypes = { +SupportScreen.propTypes = { actions: PropTypes.shape({ app: PropTypes.instanceOf(AppStore).isRequired, }).isRequired, }; -export default SupportScreen; +export default inject('actions')(SupportScreen); diff --git a/src/containers/settings/TeamScreen.js b/src/containers/settings/TeamScreen.js index 928262a59..0a8b92b47 100644 --- a/src/containers/settings/TeamScreen.js +++ b/src/containers/settings/TeamScreen.js @@ -10,8 +10,6 @@ import TeamDashboard from '../../components/settings/team/TeamDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; import { DEV_API_FRANZ_WEBSITE } from '../../config'; -@inject('stores', 'actions') -@observer class TeamScreen extends Component { handleWebsiteLink(route) { const { actions, stores } = this.props; @@ -44,7 +42,7 @@ class TeamScreen extends Component { } } -TeamScreen.wrappedComponent.propTypes = { +TeamScreen.propTypes = { stores: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, app: PropTypes.instanceOf(AppStore).isRequired, @@ -56,4 +54,4 @@ TeamScreen.wrappedComponent.propTypes = { }).isRequired, }; -export default TeamScreen; +export default inject('stores', 'actions')(observer(TeamScreen)); diff --git a/src/electron/ipc-api/download.ts b/src/electron/ipc-api/download.ts index af15b157e..95f211e52 100644 --- a/src/electron/ipc-api/download.ts +++ b/src/electron/ipc-api/download.ts @@ -48,7 +48,7 @@ export default (params: { mainWindow: BrowserWindow }) => { debug('File blob saved to', saveDialog.filePath); } catch (error) { - console.log(error); + console.error(error); } } } catch (error) { diff --git a/src/features/basicAuth/Component.js b/src/features/basicAuth/Component.js index 652233e55..89b0a4e72 100644 --- a/src/features/basicAuth/Component.js +++ b/src/features/basicAuth/Component.js @@ -22,8 +22,6 @@ const messages = defineMessages({ }, }); -@injectSheet(styles) -@observer class BasicAuthModal extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -97,4 +95,6 @@ class BasicAuthModal extends Component { ); } } -export default injectIntl(BasicAuthModal); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(BasicAuthModal)), +); diff --git a/src/features/nightlyBuilds/Component.js b/src/features/nightlyBuilds/Component.js index 64f782c8f..0966480d0 100644 --- a/src/features/nightlyBuilds/Component.js +++ b/src/features/nightlyBuilds/Component.js @@ -29,7 +29,7 @@ const messages = defineMessages({ }, }); -const styles = () => ({ +const styles = { info: { paddingTop: 20, paddingBottom: 20, @@ -51,11 +51,8 @@ const styles = () => ({ background: '#c45a5a !important', color: '#ffffff !important', }, -}); +}; -@injectSheet(styles) -@inject('stores', 'actions') -@observer class NightlyBuildsModal extends Component { close() { ModalState.isModalVisible = false; @@ -119,7 +116,7 @@ class NightlyBuildsModal extends Component { } } -NightlyBuildsModal.wrappedComponent.propTypes = { +NightlyBuildsModal.propTypes = { stores: PropTypes.shape({ settings: PropTypes.instanceOf(SettingsStore).isRequired, }).isRequired, @@ -131,4 +128,8 @@ NightlyBuildsModal.wrappedComponent.propTypes = { classes: PropTypes.object.isRequired, }; -export default injectIntl(NightlyBuildsModal); +export default injectIntl( + injectSheet(styles)( + inject('stores', 'actions')(observer(NightlyBuildsModal)), + ), +); diff --git a/src/features/publishDebugInfo/Component.js b/src/features/publishDebugInfo/Component.js index 30bdc13b6..953fc7c21 100644 --- a/src/features/publishDebugInfo/Component.js +++ b/src/features/publishDebugInfo/Component.js @@ -85,14 +85,7 @@ const styles = theme => ({ }, }); -@injectSheet(styles) -@inject('stores', 'actions') -@observer class PublishDebugLogModal extends Component { - static propTypes = { - classes: PropTypes.object.isRequired, - }; - state = { log: null, error: false, @@ -221,13 +214,18 @@ class PublishDebugLogModal extends Component { } } -PublishDebugLogModal.wrappedComponent.propTypes = { +PublishDebugLogModal.propTypes = { stores: PropTypes.shape({ app: PropTypes.instanceOf(AppStore).isRequired, }).isRequired, actions: PropTypes.shape({ service: PropTypes.instanceOf(ServicesStore).isRequired, }).isRequired, + classes: PropTypes.object.isRequired, }; -export default injectIntl(PublishDebugLogModal); +export default injectIntl( + injectSheet(styles, { injectTheme: true })( + inject('stores', 'actions')(observer(PublishDebugLogModal)), + ), +); diff --git a/src/features/quickSwitch/Component.js b/src/features/quickSwitch/Component.js index 75587cc1d..7f9424b6d 100644 --- a/src/features/quickSwitch/Component.js +++ b/src/features/quickSwitch/Component.js @@ -81,9 +81,6 @@ const styles = theme => ({ }, }); -@injectSheet(styles) -@inject('stores', 'actions') -@observer class QuickSwitchModal extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -349,13 +346,18 @@ class QuickSwitchModal extends Component { } } -QuickSwitchModal.wrappedComponent.propTypes = { +QuickSwitchModal.propTypes = { stores: PropTypes.shape({ services: PropTypes.instanceOf(ServicesStore).isRequired, }).isRequired, actions: PropTypes.shape({ service: PropTypes.instanceOf(ServicesStore).isRequired, }).isRequired, + classes: PropTypes.object.isRequired, }; -export default injectIntl(QuickSwitchModal); +export default injectIntl( + injectSheet(styles, { injectTheme: true })( + inject('stores', 'actions')(observer(QuickSwitchModal)), + ), +); diff --git a/src/features/todos/components/TodosWebview.js b/src/features/todos/components/TodosWebview.js index 1d423544b..780864b91 100644 --- a/src/features/todos/components/TodosWebview.js +++ b/src/features/todos/components/TodosWebview.js @@ -48,8 +48,6 @@ const styles = theme => ({ }, }); -@injectSheet(styles) -@observer class TodosWebview extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -128,7 +126,6 @@ class TodosWebview extends Component { const { handleClientMessage } = this.props; if (!this.webview) return; this.webview.addEventListener('ipc-message', e => { - // console.log(e); handleClientMessage({ channel: e.channel, message: e.args[0] }); }); } @@ -201,4 +198,6 @@ class TodosWebview extends Component { } } -export default TodosWebview; +export default injectSheet(styles, { injectTheme: true })( + observer(TodosWebview), +); diff --git a/src/features/todos/containers/TodosScreen.js b/src/features/todos/containers/TodosScreen.js index 536810d2d..b97506767 100644 --- a/src/features/todos/containers/TodosScreen.js +++ b/src/features/todos/containers/TodosScreen.js @@ -10,8 +10,6 @@ import { TODOS_MIN_WIDTH } from '../../../config'; import { todoActions } from '../actions'; import ServicesStore from '../../../stores/ServicesStore'; -@inject('stores', 'actions') -@observer class TodosScreen extends Component { render() { if ( @@ -44,9 +42,9 @@ class TodosScreen extends Component { } } -export default TodosScreen; +export default inject('stores', 'actions')(observer(TodosScreen)); -TodosScreen.wrappedComponent.propTypes = { +TodosScreen.propTypes = { stores: PropTypes.shape({ features: PropTypes.instanceOf(FeaturesStore).isRequired, services: PropTypes.instanceOf(ServicesStore).isRequired, diff --git a/src/features/todos/store.js b/src/features/todos/store.js index d158ed480..2bf4e8fab 100644 --- a/src/features/todos/store.js +++ b/src/features/todos/store.js @@ -187,10 +187,6 @@ export default class TodoStore extends FeatureStore { break; default: debug('Other message received', channel, message); - console.log( - 'this.stores.services.isTodosServiceAdded', - this.stores.services.isTodosServiceAdded, - ); if (this.stores.services.isTodosServiceAdded) { this.actions.service.handleIPCMessage({ serviceId: this.stores.services.isTodosServiceAdded.id, diff --git a/src/features/webControls/components/WebControls.js b/src/features/webControls/components/WebControls.js index 5650d4cd1..99d78eda0 100644 --- a/src/features/webControls/components/WebControls.js +++ b/src/features/webControls/components/WebControls.js @@ -94,8 +94,6 @@ const styles = theme => ({ }, }); -@injectSheet(styles) -@observer class WebControls extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -238,4 +236,6 @@ class WebControls extends Component { } } -export default injectIntl(WebControls); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(WebControls)), +); diff --git a/src/features/webControls/containers/WebControlsScreen.js b/src/features/webControls/containers/WebControlsScreen.js index 6fba5db86..3dac6997c 100644 --- a/src/features/webControls/containers/WebControlsScreen.js +++ b/src/features/webControls/containers/WebControlsScreen.js @@ -16,8 +16,6 @@ const URL_EVENTS = [ 'did-navigate-in-page', ]; -@inject('stores', 'actions') -@observer class WebControlsScreen extends Component { @observable url = ''; @@ -125,9 +123,9 @@ class WebControlsScreen extends Component { } } -export default WebControlsScreen; +export default inject('stores', 'actions')(observer(WebControlsScreen)); -WebControlsScreen.wrappedComponent.propTypes = { +WebControlsScreen.propTypes = { service: PropTypes.instanceOf(Service).isRequired, stores: PropTypes.shape({ services: PropTypes.instanceOf(ServicesStore).isRequired, diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js index 75f6d9f4a..54475eccb 100644 --- a/src/features/workspaces/components/CreateWorkspaceForm.js +++ b/src/features/workspaces/components/CreateWorkspaceForm.js @@ -21,7 +21,7 @@ const messages = defineMessages({ }, }); -const styles = () => ({ +const styles = { form: { display: 'flex', }, @@ -32,10 +32,8 @@ const styles = () => ({ submitButton: { height: 'inherit', }, -}); +}; -@injectSheet(styles) -@observer class CreateWorkspaceForm extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -94,4 +92,6 @@ class CreateWorkspaceForm extends Component { } } -export default injectIntl(CreateWorkspaceForm); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(CreateWorkspaceForm)), +); diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js index fa3ea4289..e8bd9d60c 100644 --- a/src/features/workspaces/components/EditWorkspaceForm.js +++ b/src/features/workspaces/components/EditWorkspaceForm.js @@ -58,7 +58,7 @@ const messages = defineMessages({ }, }); -const styles = () => ({ +const styles = { nameInput: { height: 'auto', }, @@ -68,10 +68,8 @@ const styles = () => ({ keepLoadedInfo: { marginBottom: '2rem !important', }, -}); +}; -@injectSheet(styles) -@observer class EditWorkspaceForm extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -230,4 +228,6 @@ class EditWorkspaceForm extends Component { } } -export default injectIntl(EditWorkspaceForm); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(EditWorkspaceForm)), +); diff --git a/src/features/workspaces/components/WorkspaceDrawer.js b/src/features/workspaces/components/WorkspaceDrawer.js index d66e0f10d..4fd2b1153 100644 --- a/src/features/workspaces/components/WorkspaceDrawer.js +++ b/src/features/workspaces/components/WorkspaceDrawer.js @@ -88,8 +88,6 @@ const styles = theme => ({ }, }); -@injectSheet(styles) -@observer class WorkspaceDrawer extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -175,4 +173,6 @@ class WorkspaceDrawer extends Component { } } -export default injectIntl(WorkspaceDrawer); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(WorkspaceDrawer)), +); diff --git a/src/features/workspaces/components/WorkspaceDrawerItem.js b/src/features/workspaces/components/WorkspaceDrawerItem.js index d3c9fa767..22c0a39d9 100644 --- a/src/features/workspaces/components/WorkspaceDrawerItem.js +++ b/src/features/workspaces/components/WorkspaceDrawerItem.js @@ -65,8 +65,6 @@ const styles = theme => ({ }, }); -@injectSheet(styles) -@observer class WorkspaceDrawerItem extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -150,4 +148,6 @@ class WorkspaceDrawerItem extends Component { } } -export default injectIntl(WorkspaceDrawerItem); +export default injectIntl( + injectSheet(styles, { injectTheme: true })(observer(WorkspaceDrawerItem)), +); diff --git a/src/features/workspaces/components/WorkspaceItem.tsx b/src/features/workspaces/components/WorkspaceItem.tsx index 6fb02d2f5..f46375c7a 100644 --- a/src/features/workspaces/components/WorkspaceItem.tsx +++ b/src/features/workspaces/components/WorkspaceItem.tsx @@ -22,8 +22,6 @@ type Props = { onItemClick: (workspace) => void; }; -@injectSheet(styles) -@observer class WorkspaceItem extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -42,4 +40,6 @@ class WorkspaceItem extends Component { } } -export default WorkspaceItem; +export default injectSheet(styles, { injectTheme: true })( + observer(WorkspaceItem), +); diff --git a/src/features/workspaces/components/WorkspaceServiceListItem.tsx b/src/features/workspaces/components/WorkspaceServiceListItem.tsx index 6e012eb1e..46fda0103 100644 --- a/src/features/workspaces/components/WorkspaceServiceListItem.tsx +++ b/src/features/workspaces/components/WorkspaceServiceListItem.tsx @@ -36,8 +36,6 @@ type Props = { service: any; }; -@injectSheet(styles) -@observer class WorkspaceServiceListItem extends Component { render() { const { classes, isInWorkspace, onToggle, service } = this.props; @@ -63,4 +61,6 @@ class WorkspaceServiceListItem extends Component { } } -export default WorkspaceServiceListItem; +export default injectSheet(styles, { injectTheme: true })( + observer(WorkspaceServiceListItem), +); diff --git a/src/features/workspaces/components/WorkspaceSwitchingIndicator.js b/src/features/workspaces/components/WorkspaceSwitchingIndicator.js index ff4e9475a..b2e0adfe7 100644 --- a/src/features/workspaces/components/WorkspaceSwitchingIndicator.js +++ b/src/features/workspaces/components/WorkspaceSwitchingIndicator.js @@ -53,8 +53,6 @@ const styles = theme => ({ }, }); -@injectSheet(styles) -@observer class WorkspaceSwitchingIndicator extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -85,4 +83,8 @@ class WorkspaceSwitchingIndicator extends Component { } } -export default injectIntl(WorkspaceSwitchingIndicator); +export default injectIntl( + injectSheet(styles, { injectTheme: true })( + observer(WorkspaceSwitchingIndicator), + ), +); diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js index 1087580b1..9c2f65731 100644 --- a/src/features/workspaces/components/WorkspacesDashboard.js +++ b/src/features/workspaces/components/WorkspacesDashboard.js @@ -49,7 +49,7 @@ const messages = defineMessages({ }, }); -const styles = () => ({ +const styles = { table: { width: '100%', '& td': { @@ -67,11 +67,8 @@ const styles = () => ({ margin: [-8, 0, 0, 20], alignSelf: 'center', }, -}); +}; -@inject('stores') -@injectSheet(styles) -@observer class WorkspacesDashboard extends Component { static propTypes = { classes: PropTypes.object.isRequired, @@ -190,9 +187,13 @@ class WorkspacesDashboard extends Component { } } -export default injectIntl(WorkspacesDashboard); +export default injectIntl( + inject('stores')( + injectSheet(styles, { injectTheme: true })(observer(WorkspacesDashboard)), + ), +); -WorkspacesDashboard.wrappedComponent.propTypes = { +WorkspacesDashboard.propTypes = { stores: PropTypes.shape({ ui: PropTypes.instanceOf(UIStore).isRequired, }).isRequired, diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.tsx b/src/features/workspaces/containers/EditWorkspaceScreen.tsx index 8e8f8179d..0351ddafb 100644 --- a/src/features/workspaces/containers/EditWorkspaceScreen.tsx +++ b/src/features/workspaces/containers/EditWorkspaceScreen.tsx @@ -17,8 +17,6 @@ type Props = { }; }; -@inject('stores', 'actions') -@observer class EditWorkspaceScreen extends Component { // @ts-expect-error Not all code paths return a value. onDelete = () => { @@ -58,4 +56,4 @@ class EditWorkspaceScreen extends Component { } } -export default EditWorkspaceScreen; +export default inject('stores', 'actions')(observer(EditWorkspaceScreen)); diff --git a/src/features/workspaces/containers/WorkspacesScreen.tsx b/src/features/workspaces/containers/WorkspacesScreen.tsx index a07e92439..33808b69d 100644 --- a/src/features/workspaces/containers/WorkspacesScreen.tsx +++ b/src/features/workspaces/containers/WorkspacesScreen.tsx @@ -17,8 +17,6 @@ type Props = { }; }; -@inject('stores', 'actions') -@observer class WorkspacesScreen extends Component { render() { const { actions } = this.props; @@ -38,4 +36,4 @@ class WorkspacesScreen extends Component { } } -export default WorkspacesScreen; +export default inject('stores', 'actions')(observer(WorkspacesScreen)); diff --git a/src/lib/Form.ts b/src/lib/Form.ts index 9b8321948..14ea82948 100644 --- a/src/lib/Form.ts +++ b/src/lib/Form.ts @@ -1,4 +1,5 @@ import Form from 'mobx-react-form'; +import vjf from 'mobx-react-form/lib/validators/VJF'; export default class DefaultForm extends Form { bindings() { @@ -29,4 +30,10 @@ export default class DefaultForm extends Form { // // }, }; } + + plugins() { + return { + vjf: vjf(), + }; + } } diff --git a/src/routes.tsx b/src/routes.tsx index 569da06a7..192090737 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -36,8 +36,6 @@ type Props = { history: any; }; -@inject('stores', 'actions') -@observer class Routes extends Component { render() { const { locked } = this.props.stores.settings.app; @@ -94,4 +92,4 @@ class Routes extends Component { } } -export default Routes; +export default inject('stores', 'actions')(observer(Routes)); diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 3d418c4c5..09ee8890a 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -799,8 +799,6 @@ export default class ServicesStore extends Store { options.icon = '/assets/img/notification-badge.gif'; } - console.log(title, options); - this.actions.app.notify({ notificationId: args[0].notificationId, title, -- cgit v1.2.3-70-g09d2 From f53fe4ee6cb169ab688e4d8562a94532753a5382 Mon Sep 17 00:00:00 2001 From: kytwb Date: Wed, 15 Dec 2021 19:02:35 +0100 Subject: Enable hibernate/wake-up calls of active service via context menu --- src/stores/ServicesStore.js | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/stores/ServicesStore.js') diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 09ee8890a..e546850f9 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -1036,10 +1036,6 @@ export default class ServicesStore extends Store { if (!service.canHibernate) { return; } - if (service.isActive) { - debug(`Skipping service hibernation for ${service.name}`); - return; - } debug(`Hibernate ${service.name}`); -- cgit v1.2.3-70-g09d2