From c32090618e535eb48fb4dc377659ff97dae1a9ee Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Mon, 10 Dec 2018 16:34:53 +0100 Subject: merge default and fetched feature configs --- src/stores/FeaturesStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index 0adee6adf..eb2b21af3 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js @@ -37,7 +37,7 @@ export default class FeaturesStore extends Store { @computed get features() { if (this.stores.user.isLoggedIn) { - return this.featuresRequest.execute().result || DEFAULT_FEATURES_CONFIG; + return Object.assign({}, DEFAULT_FEATURES_CONFIG, this.featuresRequest.execute().result); } return DEFAULT_FEATURES_CONFIG; -- cgit v1.2.3-54-g00ecf From 4a537e890d95e8666985ce77df4c6327582332be Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Mon, 10 Dec 2018 17:15:37 +0100 Subject: basic setup for workspaces feature --- src/config.js | 1 + src/features/workspaces/api.js | 9 +++++++++ src/features/workspaces/index.js | 34 ++++++++++++++++++++++++++++++++++ src/features/workspaces/store.js | 29 +++++++++++++++++++++++++++++ src/stores/FeaturesStore.js | 2 ++ 5 files changed, 75 insertions(+) create mode 100644 src/features/workspaces/api.js create mode 100644 src/features/workspaces/index.js create mode 100644 src/features/workspaces/store.js (limited to 'src') diff --git a/src/config.js b/src/config.js index 789ddd1a0..d7a485b8a 100644 --- a/src/config.js +++ b/src/config.js @@ -37,6 +37,7 @@ export const DEFAULT_FEATURES_CONFIG = { }, isServiceProxyEnabled: false, isServiceProxyPremiumFeature: true, + isWorkspaceEnabled: true, }; export const DEFAULT_WINDOW_OPTIONS = { diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js new file mode 100644 index 000000000..1ee2440fe --- /dev/null +++ b/src/features/workspaces/api.js @@ -0,0 +1,9 @@ +// TODO: use real server instead +const workspaces = [ + { id: 'workspace-1', name: 'Private' }, + { id: 'workspace-2', name: 'Office' }, +]; + +export default { + getUserWorkspaces: () => Promise.resolve(workspaces), +}; diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js new file mode 100644 index 000000000..b7e1090e8 --- /dev/null +++ b/src/features/workspaces/index.js @@ -0,0 +1,34 @@ +import { observable, reaction } from 'mobx'; +import { merge } from 'lodash'; +import WorkspacesStore from './store'; +import api from './api'; + +const debug = require('debug')('Franz:feature:workspaces'); + +let store = null; +const defaultState = { workspaces: [] }; + +export const state = observable(defaultState); + +export default function initWorkspaces(stores, actions) { + const { features, user } = stores; + reaction( + () => features.features.isWorkspaceEnabled && user.isLoggedIn, + (isEnabled) => { + if (isEnabled) { + debug('Initializing `workspaces` feature'); + store = new WorkspacesStore(stores, api, actions, state); + store.initialize(); + } else if (store) { + debug('Disabling `workspaces` feature'); + store.teardown(); + store = null; + // Reset state to default + merge(state, defaultState); + } + }, + { + fireImmediately: true, + }, + ); +} diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js new file mode 100644 index 000000000..4b4e729ed --- /dev/null +++ b/src/features/workspaces/store.js @@ -0,0 +1,29 @@ +import { observable, reaction } from 'mobx'; +import Store from '../../stores/lib/Store'; +import CachedRequest from '../../stores/lib/CachedRequest'; + +const debug = require('debug')('Franz:feature:workspaces'); + +export default class WorkspacesStore extends Store { + @observable allWorkspacesRequest = new CachedRequest(this.api, 'getUserWorkspaces'); + + constructor(stores, api, actions, state) { + super(stores, api, actions); + this.state = state; + } + + setup() { + debug('fetching user workspaces'); + this.allWorkspacesRequest.execute(); + + reaction( + () => this.allWorkspacesRequest.result, + workspaces => this.setWorkspaces(workspaces), + ); + } + + setWorkspaces = (workspaces) => { + debug('setting user workspaces', workspaces.slice()); + this.state.workspaces = workspaces; + }; +} diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index eb2b21af3..05a620f0b 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js @@ -7,6 +7,7 @@ import delayApp from '../features/delayApp'; import spellchecker from '../features/spellchecker'; import serviceProxy from '../features/serviceProxy'; import basicAuth from '../features/basicAuth'; +import workspaces from '../features/workspaces'; import { DEFAULT_FEATURES_CONFIG } from '../config'; @@ -56,5 +57,6 @@ export default class FeaturesStore extends Store { spellchecker(this.stores, this.actions); serviceProxy(this.stores, this.actions); basicAuth(this.stores, this.actions); + workspaces(this.stores, this.actions); } } -- cgit v1.2.3-54-g00ecf From fd04044be1fe7207e75ed7cb1ddb622cc9cc93bf Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 10 Jan 2019 13:43:23 +0100 Subject: define workspaces as premium feature --- src/config.js | 1 + src/features/workspaces/index.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/config.js b/src/config.js index d7a485b8a..d327185f0 100644 --- a/src/config.js +++ b/src/config.js @@ -37,6 +37,7 @@ export const DEFAULT_FEATURES_CONFIG = { }, isServiceProxyEnabled: false, isServiceProxyPremiumFeature: true, + isWorkspacePremiumFeature: true, isWorkspaceEnabled: true, }; diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js index b7e1090e8..b4cfd3c2d 100644 --- a/src/features/workspaces/index.js +++ b/src/features/workspaces/index.js @@ -13,7 +13,11 @@ export const state = observable(defaultState); export default function initWorkspaces(stores, actions) { const { features, user } = stores; reaction( - () => features.features.isWorkspaceEnabled && user.isLoggedIn, + () => ( + features.features.isWorkspaceEnabled && ( + !features.features.isWorkspacePremiumFeature || user.data.isPremium + ) + ), (isEnabled) => { if (isEnabled) { debug('Initializing `workspaces` feature'); -- cgit v1.2.3-54-g00ecf From 912bca432ebf005a1680e9cc28bf7ee92cb0d36b Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 10 Jan 2019 13:43:45 +0100 Subject: add workspaces menu item in settings dialog --- src/components/settings/navigation/SettingsNavigation.js | 12 ++++++++++++ src/i18n/locales/en-US.json | 1 + 2 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 953f702f8..4a80bb126 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js @@ -14,6 +14,10 @@ const messages = defineMessages({ id: 'settings.navigation.yourServices', defaultMessage: '!!!Your services', }, + yourWorkspaces: { + id: 'settings.navigation.yourWorkspaces', + defaultMessage: '!!!Your workspaces', + }, account: { id: 'settings.navigation.account', defaultMessage: '!!!Account', @@ -63,6 +67,14 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp {' '} {serviceCount} + + {intl.formatMessage(messages.yourWorkspaces)} + {' '} + Date: Mon, 14 Jan 2019 17:11:27 +0100 Subject: basic setup of workspaces settings screen --- src/api/utils/auth.js | 24 ++++++++++ src/app.js | 2 + .../settings/workspaces/WorkspaceItem.js | 41 ++++++++++++++++ .../settings/workspaces/WorkspacesDashboard.js | 56 ++++++++++++++++++++++ src/containers/settings/WorkspacesScreen.js | 29 +++++++++++ src/environment.js | 1 + src/features/workspaces/api.js | 16 ++++--- src/features/workspaces/index.js | 10 ++-- src/features/workspaces/state.js | 12 +++++ src/features/workspaces/store.js | 15 ++++-- src/i18n/locales/en-US.json | 1 + src/models/Workspace.js | 25 ++++++++++ 12 files changed, 216 insertions(+), 16 deletions(-) create mode 100644 src/api/utils/auth.js create mode 100644 src/components/settings/workspaces/WorkspaceItem.js create mode 100644 src/components/settings/workspaces/WorkspacesDashboard.js create mode 100644 src/containers/settings/WorkspacesScreen.js create mode 100644 src/features/workspaces/state.js create mode 100644 src/models/Workspace.js (limited to 'src') diff --git a/src/api/utils/auth.js b/src/api/utils/auth.js new file mode 100644 index 000000000..47ac94c19 --- /dev/null +++ b/src/api/utils/auth.js @@ -0,0 +1,24 @@ +import { remote } from 'electron'; +import localStorage from 'mobx-localstorage'; + +const { app } = remote; + +export const prepareAuthRequest = (options, auth = true) => { + const request = Object.assign(options, { + mode: 'cors', + headers: Object.assign({ + 'Content-Type': 'application/json', + 'X-Franz-Source': 'desktop', + 'X-Franz-Version': app.getVersion(), + 'X-Franz-platform': process.platform, + 'X-Franz-Timezone-Offset': new Date().getTimezoneOffset(), + 'X-Franz-System-Locale': app.getLocale(), + }, options.headers), + }); + + if (auth) { + request.headers.Authorization = `Bearer ${localStorage.getItem('authToken')}`; + } + + return request; +}; diff --git a/src/app.js b/src/app.js index 6660feb46..ee1b12939 100644 --- a/src/app.js +++ b/src/app.js @@ -39,6 +39,7 @@ import PricingScreen from './containers/auth/PricingScreen'; import InviteScreen from './containers/auth/InviteScreen'; import AuthLayoutContainer from './containers/auth/AuthLayoutContainer'; import SubscriptionPopupScreen from './containers/subscription/SubscriptionPopupScreen'; +import WorkspacesScreen from './containers/settings/WorkspacesScreen'; // Add Polyfills smoothScroll.polyfill(); @@ -75,6 +76,7 @@ window.addEventListener('load', () => { + diff --git a/src/components/settings/workspaces/WorkspaceItem.js b/src/components/settings/workspaces/WorkspaceItem.js new file mode 100644 index 000000000..82a578ebd --- /dev/null +++ b/src/components/settings/workspaces/WorkspaceItem.js @@ -0,0 +1,41 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { defineMessages, intlShape } from 'react-intl'; +import { observer } from 'mobx-react'; +import classnames from 'classnames'; +import Workspace from '../../../models/Workspace'; + +// const messages = defineMessages({}); + +@observer +class WorkspaceItem extends Component { + static propTypes = { + workspace: PropTypes.instanceOf(Workspace).isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + render() { + const { workspace } = this.props; + // const { intl } = this.context; + + return ( + + console.log('go to workspace', workspace.name)} + > + {workspace.name} + + + ); + } +} + +export default WorkspaceItem; diff --git a/src/components/settings/workspaces/WorkspacesDashboard.js b/src/components/settings/workspaces/WorkspacesDashboard.js new file mode 100644 index 000000000..830f32f08 --- /dev/null +++ b/src/components/settings/workspaces/WorkspacesDashboard.js @@ -0,0 +1,56 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; +import { defineMessages, intlShape } from 'react-intl'; + +import Loader from '../../ui/Loader'; +import WorkspaceItem from './WorkspaceItem'; + +const messages = defineMessages({ + headline: { + id: 'settings.workspaces.headline', + defaultMessage: '!!!Your workspaces', + }, + noServicesAdded: { + id: 'settings.workspaces.noWorkspacesAdded', + defaultMessage: '!!!You haven\'t added any workspaces yet.', + }, +}); + +@observer +class WorkspacesDashboard extends Component { + static propTypes = { + workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, + isLoading: PropTypes.bool.isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + render() { + const { workspaces, isLoading } = this.props; + const { intl } = this.context; + + return ( +
+
+

{intl.formatMessage(messages.headline)}

+
+
+ {isLoading ? ( + + ) : ( + + + {workspaces.map(workspace => )} + +
+ )} +
+
+ ); + } +} + +export default WorkspacesDashboard; diff --git a/src/containers/settings/WorkspacesScreen.js b/src/containers/settings/WorkspacesScreen.js new file mode 100644 index 000000000..e767fdfbe --- /dev/null +++ b/src/containers/settings/WorkspacesScreen.js @@ -0,0 +1,29 @@ +import React, { Component } from 'react'; +import { observer } from 'mobx-react'; +import { gaPage } from '../../lib/analytics'; +import { state } from '../../features/workspaces/state'; + +import WorkspacesDashboard from '../../components/settings/workspaces/WorkspacesDashboard'; +import ErrorBoundary from '../../components/util/ErrorBoundary'; + +@observer +class WorkspacesScreen extends Component { + static propTypes = {}; + + componentDidMount() { + gaPage('Settings/Workspaces Dashboard'); + } + + render() { + return ( + + + + ); + } +} + +export default WorkspacesScreen; diff --git a/src/environment.js b/src/environment.js index 73b1c7ab2..d67fd6adb 100644 --- a/src/environment.js +++ b/src/environment.js @@ -28,3 +28,4 @@ if (!isDevMode || (isDevMode && useLiveAPI)) { } export const API = api; +export const API_VERSION = 'v1'; diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js index 1ee2440fe..97badbd01 100644 --- a/src/features/workspaces/api.js +++ b/src/features/workspaces/api.js @@ -1,9 +1,13 @@ -// TODO: use real server instead -const workspaces = [ - { id: 'workspace-1', name: 'Private' }, - { id: 'workspace-2', name: 'Office' }, -]; +import { prepareAuthRequest } from '../../api/utils/auth'; +import { API, API_VERSION } from '../../environment'; export default { - getUserWorkspaces: () => Promise.resolve(workspaces), + getUserWorkspaces: async () => { + const url = `${API}/${API_VERSION}/workspace`; + const request = await window.fetch(url, prepareAuthRequest({ + method: 'GET', + })); + if (!request.ok) throw request; + return request.json(); + }, }; diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js index b4cfd3c2d..50ac3b414 100644 --- a/src/features/workspaces/index.js +++ b/src/features/workspaces/index.js @@ -1,14 +1,11 @@ -import { observable, reaction } from 'mobx'; -import { merge } from 'lodash'; +import { reaction } from 'mobx'; import WorkspacesStore from './store'; import api from './api'; +import { state, resetState } from './state'; const debug = require('debug')('Franz:feature:workspaces'); let store = null; -const defaultState = { workspaces: [] }; - -export const state = observable(defaultState); export default function initWorkspaces(stores, actions) { const { features, user } = stores; @@ -27,8 +24,7 @@ export default function initWorkspaces(stores, actions) { debug('Disabling `workspaces` feature'); store.teardown(); store = null; - // Reset state to default - merge(state, defaultState); + resetState(); // Reset state to default } }, { diff --git a/src/features/workspaces/state.js b/src/features/workspaces/state.js new file mode 100644 index 000000000..ed3fe9f00 --- /dev/null +++ b/src/features/workspaces/state.js @@ -0,0 +1,12 @@ +import { observable } from 'mobx'; + +const defaultState = { + isLoading: false, + workspaces: [], +}; + +export const state = observable(defaultState); + +export function resetState() { + Object.assign(state, defaultState); +} diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 4b4e729ed..2b6d55cc7 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -1,6 +1,7 @@ import { observable, reaction } from 'mobx'; import Store from '../../stores/lib/Store'; import CachedRequest from '../../stores/lib/CachedRequest'; +import Workspace from '../../models/Workspace'; const debug = require('debug')('Franz:feature:workspaces'); @@ -18,12 +19,20 @@ export default class WorkspacesStore extends Store { reaction( () => this.allWorkspacesRequest.result, - workspaces => this.setWorkspaces(workspaces), + workspaces => this._setWorkspaces(workspaces), + ); + reaction( + () => this.allWorkspacesRequest.isExecuting, + isExecuting => this._setIsLoading(isExecuting), ); } - setWorkspaces = (workspaces) => { + _setWorkspaces = (workspaces) => { debug('setting user workspaces', workspaces.slice()); - this.state.workspaces = workspaces; + this.state.workspaces = workspaces.map(data => new Workspace(data)); + }; + + _setIsLoading = (isLoading) => { + this.state.isLoading = isLoading; }; } diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 1b869aff1..1652b5585 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -196,6 +196,7 @@ "settings.user.form.accountType.individual": "Individual", "settings.user.form.accountType.non-profit": "Non-Profit", "settings.user.form.accountType.company": "Company", + "settings.workspaces.headline": "Your workspaces", "subscription.type.free": "free", "subscription.type.month": "month", "subscription.type.year": "year", diff --git a/src/models/Workspace.js b/src/models/Workspace.js new file mode 100644 index 000000000..ede2710dc --- /dev/null +++ b/src/models/Workspace.js @@ -0,0 +1,25 @@ +import { observable } from 'mobx'; + +export default class Workspace { + id = null; + + @observable name = null; + + @observable order = null; + + @observable services = []; + + @observable userId = null; + + constructor(data) { + if (!data.id) { + throw Error('Workspace requires Id'); + } + + this.id = data.id; + this.name = data.name; + this.order = data.order; + this.services = data.services; + this.userId = data.userId; + } +} -- cgit v1.2.3-54-g00ecf From e3a9a93581c52e93ad984c39e80bf3e456797a0b Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Mon, 14 Jan 2019 17:12:22 +0100 Subject: fix eslint error --- src/components/settings/workspaces/WorkspaceItem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/settings/workspaces/WorkspaceItem.js b/src/components/settings/workspaces/WorkspaceItem.js index 82a578ebd..49d67d429 100644 --- a/src/components/settings/workspaces/WorkspaceItem.js +++ b/src/components/settings/workspaces/WorkspaceItem.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { defineMessages, intlShape } from 'react-intl'; +import { intlShape } from 'react-intl'; import { observer } from 'mobx-react'; import classnames from 'classnames'; import Workspace from '../../../models/Workspace'; -- cgit v1.2.3-54-g00ecf From 73fcc05f34d5e707df5abbc744f7fe3313efb226 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Mon, 14 Jan 2019 17:56:03 +0100 Subject: assign react key prop to workspace items --- src/components/settings/workspaces/WorkspacesDashboard.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/settings/workspaces/WorkspacesDashboard.js b/src/components/settings/workspaces/WorkspacesDashboard.js index 830f32f08..c6378ac1e 100644 --- a/src/components/settings/workspaces/WorkspacesDashboard.js +++ b/src/components/settings/workspaces/WorkspacesDashboard.js @@ -43,7 +43,12 @@ class WorkspacesDashboard extends Component { ) : ( - {workspaces.map(workspace => )} + {workspaces.map(workspace => ( + + ))}
)} -- cgit v1.2.3-54-g00ecf From 981679154096517037c6732c9ecca1fe89733d00 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Mon, 14 Jan 2019 17:56:19 +0100 Subject: add styles for workspace table --- .../settings/workspaces/WorkspaceItem.js | 4 +- .../settings/workspaces/WorkspacesDashboard.js | 2 +- src/styles/main.scss | 1 + src/styles/workspace-table.scss | 53 ++++++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/styles/workspace-table.scss (limited to 'src') diff --git a/src/components/settings/workspaces/WorkspaceItem.js b/src/components/settings/workspaces/WorkspaceItem.js index 49d67d429..a71e6583d 100644 --- a/src/components/settings/workspaces/WorkspaceItem.js +++ b/src/components/settings/workspaces/WorkspaceItem.js @@ -24,11 +24,11 @@ class WorkspaceItem extends Component { return ( console.log('go to workspace', workspace.name)} > {workspace.name} diff --git a/src/components/settings/workspaces/WorkspacesDashboard.js b/src/components/settings/workspaces/WorkspacesDashboard.js index c6378ac1e..b286adc68 100644 --- a/src/components/settings/workspaces/WorkspacesDashboard.js +++ b/src/components/settings/workspaces/WorkspacesDashboard.js @@ -41,7 +41,7 @@ class WorkspacesDashboard extends Component { {isLoading ? ( ) : ( - +
{workspaces.map(workspace => ( Date: Mon, 14 Jan 2019 19:01:46 +0100 Subject: setup logic to display workspace edit page --- src/actions/index.js | 2 + src/actions/workspace.js | 8 ++++ src/app.js | 2 + .../settings/workspaces/WorkspaceItem.js | 5 +- .../settings/workspaces/WorkspacesDashboard.js | 4 +- src/containers/settings/EditWorkspaceScreen.js | 54 ++++++++++++++++++++++ src/containers/settings/WorkspacesScreen.js | 16 +++++-- src/features/workspaces/state.js | 1 + src/features/workspaces/store.js | 32 ++++++++++++- 9 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 src/actions/workspace.js create mode 100644 src/containers/settings/EditWorkspaceScreen.js (limited to 'src') diff --git a/src/actions/index.js b/src/actions/index.js index 59acabb0b..a406af50a 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -11,6 +11,7 @@ import payment from './payment'; import news from './news'; import settings from './settings'; import requests from './requests'; +import workspace from './workspace'; const actions = Object.assign({}, { service, @@ -23,6 +24,7 @@ const actions = Object.assign({}, { news, settings, requests, + workspace, }); export default defineActions(actions, PropTypes.checkPropTypes); diff --git a/src/actions/workspace.js b/src/actions/workspace.js new file mode 100644 index 000000000..ab07a96c0 --- /dev/null +++ b/src/actions/workspace.js @@ -0,0 +1,8 @@ +import PropTypes from 'prop-types'; +import Workspace from '../models/Workspace'; + +export default { + edit: { + workspace: PropTypes.instanceOf(Workspace).isRequired, + }, +}; diff --git a/src/app.js b/src/app.js index ee1b12939..320ba679f 100644 --- a/src/app.js +++ b/src/app.js @@ -40,6 +40,7 @@ import InviteScreen from './containers/auth/InviteScreen'; import AuthLayoutContainer from './containers/auth/AuthLayoutContainer'; import SubscriptionPopupScreen from './containers/subscription/SubscriptionPopupScreen'; import WorkspacesScreen from './containers/settings/WorkspacesScreen'; +import EditWorkspaceScreen from './containers/settings/EditWorkspaceScreen'; // Add Polyfills smoothScroll.polyfill(); @@ -77,6 +78,7 @@ window.addEventListener('load', () => { + diff --git a/src/components/settings/workspaces/WorkspaceItem.js b/src/components/settings/workspaces/WorkspaceItem.js index a71e6583d..088d61433 100644 --- a/src/components/settings/workspaces/WorkspaceItem.js +++ b/src/components/settings/workspaces/WorkspaceItem.js @@ -11,6 +11,7 @@ import Workspace from '../../../models/Workspace'; class WorkspaceItem extends Component { static propTypes = { workspace: PropTypes.instanceOf(Workspace).isRequired, + onItemClick: PropTypes.func.isRequired, }; static contextTypes = { @@ -18,7 +19,7 @@ class WorkspaceItem extends Component { }; render() { - const { workspace } = this.props; + const { workspace, onItemClick } = this.props; // const { intl } = this.context; return ( @@ -29,7 +30,7 @@ class WorkspaceItem extends Component { > diff --git a/src/components/settings/workspaces/WorkspacesDashboard.js b/src/components/settings/workspaces/WorkspacesDashboard.js index b286adc68..a5bb18cb7 100644 --- a/src/components/settings/workspaces/WorkspacesDashboard.js +++ b/src/components/settings/workspaces/WorkspacesDashboard.js @@ -22,6 +22,7 @@ class WorkspacesDashboard extends Component { static propTypes = { workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, isLoading: PropTypes.bool.isRequired, + onWorkspaceClick: PropTypes.func.isRequired, }; static contextTypes = { @@ -29,7 +30,7 @@ class WorkspacesDashboard extends Component { }; render() { - const { workspaces, isLoading } = this.props; + const { workspaces, isLoading, onWorkspaceClick } = this.props; const { intl } = this.context; return ( @@ -47,6 +48,7 @@ class WorkspacesDashboard extends Component { onWorkspaceClick(w)} /> ))} diff --git a/src/containers/settings/EditWorkspaceScreen.js b/src/containers/settings/EditWorkspaceScreen.js new file mode 100644 index 000000000..665b405bd --- /dev/null +++ b/src/containers/settings/EditWorkspaceScreen.js @@ -0,0 +1,54 @@ +import React, { Component } from 'react'; +import { inject, observer } from 'mobx-react'; +import { defineMessages, intlShape } from 'react-intl'; +import Form from '../../lib/Form'; +import ErrorBoundary from '../../components/util/ErrorBoundary'; +import { gaPage } from '../../lib/analytics'; +import { state } from '../../features/workspaces/state'; + +const messages = defineMessages({ + name: { + id: 'settings.workspace.form.name', + defaultMessage: '!!!Name', + }, +}); + +@inject('stores', 'actions') @observer +class EditWorkspaceScreen extends Component { + static contextTypes = { + intl: intlShape, + }; + + componentDidMount() { + gaPage('Settings/Workspace/Edit'); + } + + prepareForm(workspace) { + const { intl } = this.context; + const config = { + fields: { + name: { + label: intl.formatMessage(messages.name), + placeholder: intl.formatMessage(messages.name), + value: workspace.name, + }, + }, + }; + return new Form(config); + } + + render() { + const { workspaceBeingEdited } = state; + if (!workspaceBeingEdited) return null; + + // const form = this.prepareForm(workspaceBeingEdited); + + return ( + +
{workspaceBeingEdited.name}
+
+ ); + } +} + +export default EditWorkspaceScreen; diff --git a/src/containers/settings/WorkspacesScreen.js b/src/containers/settings/WorkspacesScreen.js index e767fdfbe..5e91f7673 100644 --- a/src/containers/settings/WorkspacesScreen.js +++ b/src/containers/settings/WorkspacesScreen.js @@ -1,25 +1,33 @@ import React, { Component } from 'react'; -import { observer } from 'mobx-react'; +import { inject, observer } from 'mobx-react'; +import PropTypes from 'prop-types'; import { gaPage } from '../../lib/analytics'; import { state } from '../../features/workspaces/state'; - import WorkspacesDashboard from '../../components/settings/workspaces/WorkspacesDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; -@observer +@inject('actions') @observer class WorkspacesScreen extends Component { - static propTypes = {}; + static propTypes = { + actions: PropTypes.shape({ + workspace: PropTypes.shape({ + edit: PropTypes.func.isRequired, + }), + }).isRequired, + }; componentDidMount() { gaPage('Settings/Workspaces Dashboard'); } render() { + const { workspace } = this.props.actions; return ( workspace.edit({ workspace: w })} /> ); diff --git a/src/features/workspaces/state.js b/src/features/workspaces/state.js index ed3fe9f00..f938c1470 100644 --- a/src/features/workspaces/state.js +++ b/src/features/workspaces/state.js @@ -3,6 +3,7 @@ import { observable } from 'mobx'; const defaultState = { isLoading: false, workspaces: [], + workspaceBeingEdited: null, }; export const state = observable(defaultState); diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 2b6d55cc7..aab66708b 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -2,6 +2,7 @@ import { observable, reaction } from 'mobx'; import Store from '../../stores/lib/Store'; import CachedRequest from '../../stores/lib/CachedRequest'; import Workspace from '../../models/Workspace'; +import { matchRoute } from '../../helpers/routing-helpers'; const debug = require('debug')('Franz:feature:workspaces'); @@ -14,17 +15,40 @@ export default class WorkspacesStore extends Store { } setup() { - debug('fetching user workspaces'); + debug('fetching workspaces'); this.allWorkspacesRequest.execute(); + /** + * Update the state workspaces array when workspaces request has results. + */ reaction( () => this.allWorkspacesRequest.result, workspaces => this._setWorkspaces(workspaces), ); + /** + * Update the loading state when workspace request is executing. + */ reaction( () => this.allWorkspacesRequest.isExecuting, isExecuting => this._setIsLoading(isExecuting), ); + /** + * Update the state with the workspace to be edited when route matches. + */ + reaction( + () => ({ + pathname: this.stores.router.location.pathname, + workspaces: this.state.workspaces, + }), + ({ pathname }) => { + const match = matchRoute('/settings/workspaces/edit/:id', pathname); + if (match) { + this.state.workspaceBeingEdited = this._getWorkspaceById(match.id); + } + }, + ); + + this.actions.workspace.edit.listen(this._edit); } _setWorkspaces = (workspaces) => { @@ -35,4 +59,10 @@ export default class WorkspacesStore extends Store { _setIsLoading = (isLoading) => { this.state.isLoading = isLoading; }; + + _getWorkspaceById = id => this.state.workspaces.find(w => w.id === id); + + _edit = ({ workspace }) => { + this.stores.router.push(`/settings/workspaces/edit/${workspace.id}`); + } } -- cgit v1.2.3-54-g00ecf From 90399cc608b93cc185b0ee1c9b79e98cfafb8bc1 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Tue, 12 Feb 2019 14:59:58 +0100 Subject: consolidate workspace feature for further development --- src/actions/index.js | 2 +- src/actions/workspace.js | 8 --- src/app.js | 4 +- .../settings/workspaces/WorkspaceItem.js | 42 ------------ .../settings/workspaces/WorkspacesDashboard.js | 63 ------------------ src/containers/settings/EditWorkspaceScreen.js | 54 ---------------- src/containers/settings/WorkspacesScreen.js | 37 ----------- src/features/workspaces/actions.js | 8 +++ .../workspaces/components/WorkspaceItem.js | 42 ++++++++++++ .../workspaces/components/WorkspacesDashboard.js | 63 ++++++++++++++++++ .../workspaces/containers/EditWorkspaceScreen.js | 75 ++++++++++++++++++++++ .../workspaces/containers/WorkspacesScreen.js | 37 +++++++++++ src/features/workspaces/models/Workspace.js | 25 ++++++++ src/features/workspaces/store.js | 2 +- .../workspaces/styles/workspaces-table.scss | 53 +++++++++++++++ src/i18n/locales/de.json | 3 + src/i18n/locales/en-US.json | 1 + src/models/Workspace.js | 25 -------- src/styles/main.scss | 2 +- src/styles/workspace-table.scss | 53 --------------- 20 files changed, 312 insertions(+), 287 deletions(-) delete mode 100644 src/actions/workspace.js delete mode 100644 src/components/settings/workspaces/WorkspaceItem.js delete mode 100644 src/components/settings/workspaces/WorkspacesDashboard.js delete mode 100644 src/containers/settings/EditWorkspaceScreen.js delete mode 100644 src/containers/settings/WorkspacesScreen.js create mode 100644 src/features/workspaces/actions.js create mode 100644 src/features/workspaces/components/WorkspaceItem.js create mode 100644 src/features/workspaces/components/WorkspacesDashboard.js create mode 100644 src/features/workspaces/containers/EditWorkspaceScreen.js create mode 100644 src/features/workspaces/containers/WorkspacesScreen.js create mode 100644 src/features/workspaces/models/Workspace.js create mode 100644 src/features/workspaces/styles/workspaces-table.scss delete mode 100644 src/models/Workspace.js delete mode 100644 src/styles/workspace-table.scss (limited to 'src') diff --git a/src/actions/index.js b/src/actions/index.js index a406af50a..45e6da515 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -11,7 +11,7 @@ import payment from './payment'; import news from './news'; import settings from './settings'; import requests from './requests'; -import workspace from './workspace'; +import workspace from '../features/workspaces/actions'; const actions = Object.assign({}, { service, diff --git a/src/actions/workspace.js b/src/actions/workspace.js deleted file mode 100644 index ab07a96c0..000000000 --- a/src/actions/workspace.js +++ /dev/null @@ -1,8 +0,0 @@ -import PropTypes from 'prop-types'; -import Workspace from '../models/Workspace'; - -export default { - edit: { - workspace: PropTypes.instanceOf(Workspace).isRequired, - }, -}; diff --git a/src/app.js b/src/app.js index 320ba679f..d3b540f62 100644 --- a/src/app.js +++ b/src/app.js @@ -39,8 +39,8 @@ import PricingScreen from './containers/auth/PricingScreen'; import InviteScreen from './containers/auth/InviteScreen'; import AuthLayoutContainer from './containers/auth/AuthLayoutContainer'; import SubscriptionPopupScreen from './containers/subscription/SubscriptionPopupScreen'; -import WorkspacesScreen from './containers/settings/WorkspacesScreen'; -import EditWorkspaceScreen from './containers/settings/EditWorkspaceScreen'; +import WorkspacesScreen from './features/workspaces/containers/WorkspacesScreen'; +import EditWorkspaceScreen from './features/workspaces/containers/EditWorkspaceScreen'; // Add Polyfills smoothScroll.polyfill(); diff --git a/src/components/settings/workspaces/WorkspaceItem.js b/src/components/settings/workspaces/WorkspaceItem.js deleted file mode 100644 index 088d61433..000000000 --- a/src/components/settings/workspaces/WorkspaceItem.js +++ /dev/null @@ -1,42 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { intlShape } from 'react-intl'; -import { observer } from 'mobx-react'; -import classnames from 'classnames'; -import Workspace from '../../../models/Workspace'; - -// const messages = defineMessages({}); - -@observer -class WorkspaceItem extends Component { - static propTypes = { - workspace: PropTypes.instanceOf(Workspace).isRequired, - onItemClick: PropTypes.func.isRequired, - }; - - static contextTypes = { - intl: intlShape, - }; - - render() { - const { workspace, onItemClick } = this.props; - // const { intl } = this.context; - - return ( - - - - ); - } -} - -export default WorkspaceItem; diff --git a/src/components/settings/workspaces/WorkspacesDashboard.js b/src/components/settings/workspaces/WorkspacesDashboard.js deleted file mode 100644 index a5bb18cb7..000000000 --- a/src/components/settings/workspaces/WorkspacesDashboard.js +++ /dev/null @@ -1,63 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; -import { defineMessages, intlShape } from 'react-intl'; - -import Loader from '../../ui/Loader'; -import WorkspaceItem from './WorkspaceItem'; - -const messages = defineMessages({ - headline: { - id: 'settings.workspaces.headline', - defaultMessage: '!!!Your workspaces', - }, - noServicesAdded: { - id: 'settings.workspaces.noWorkspacesAdded', - defaultMessage: '!!!You haven\'t added any workspaces yet.', - }, -}); - -@observer -class WorkspacesDashboard extends Component { - static propTypes = { - workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, - isLoading: PropTypes.bool.isRequired, - onWorkspaceClick: PropTypes.func.isRequired, - }; - - static contextTypes = { - intl: intlShape, - }; - - render() { - const { workspaces, isLoading, onWorkspaceClick } = this.props; - const { intl } = this.context; - - return ( -
-
-

{intl.formatMessage(messages.headline)}

-
-
- {isLoading ? ( - - ) : ( -
console.log('go to workspace', workspace.name)} + onClick={() => onItemClick(workspace)} > {workspace.name}
onItemClick(workspace)} - > - {workspace.name} -
- - {workspaces.map(workspace => ( - onWorkspaceClick(w)} - /> - ))} - -
- )} - - - ); - } -} - -export default WorkspacesDashboard; diff --git a/src/containers/settings/EditWorkspaceScreen.js b/src/containers/settings/EditWorkspaceScreen.js deleted file mode 100644 index 665b405bd..000000000 --- a/src/containers/settings/EditWorkspaceScreen.js +++ /dev/null @@ -1,54 +0,0 @@ -import React, { Component } from 'react'; -import { inject, observer } from 'mobx-react'; -import { defineMessages, intlShape } from 'react-intl'; -import Form from '../../lib/Form'; -import ErrorBoundary from '../../components/util/ErrorBoundary'; -import { gaPage } from '../../lib/analytics'; -import { state } from '../../features/workspaces/state'; - -const messages = defineMessages({ - name: { - id: 'settings.workspace.form.name', - defaultMessage: '!!!Name', - }, -}); - -@inject('stores', 'actions') @observer -class EditWorkspaceScreen extends Component { - static contextTypes = { - intl: intlShape, - }; - - componentDidMount() { - gaPage('Settings/Workspace/Edit'); - } - - prepareForm(workspace) { - const { intl } = this.context; - const config = { - fields: { - name: { - label: intl.formatMessage(messages.name), - placeholder: intl.formatMessage(messages.name), - value: workspace.name, - }, - }, - }; - return new Form(config); - } - - render() { - const { workspaceBeingEdited } = state; - if (!workspaceBeingEdited) return null; - - // const form = this.prepareForm(workspaceBeingEdited); - - return ( - -
{workspaceBeingEdited.name}
-
- ); - } -} - -export default EditWorkspaceScreen; diff --git a/src/containers/settings/WorkspacesScreen.js b/src/containers/settings/WorkspacesScreen.js deleted file mode 100644 index 5e91f7673..000000000 --- a/src/containers/settings/WorkspacesScreen.js +++ /dev/null @@ -1,37 +0,0 @@ -import React, { Component } from 'react'; -import { inject, observer } from 'mobx-react'; -import PropTypes from 'prop-types'; -import { gaPage } from '../../lib/analytics'; -import { state } from '../../features/workspaces/state'; -import WorkspacesDashboard from '../../components/settings/workspaces/WorkspacesDashboard'; -import ErrorBoundary from '../../components/util/ErrorBoundary'; - -@inject('actions') @observer -class WorkspacesScreen extends Component { - static propTypes = { - actions: PropTypes.shape({ - workspace: PropTypes.shape({ - edit: PropTypes.func.isRequired, - }), - }).isRequired, - }; - - componentDidMount() { - gaPage('Settings/Workspaces Dashboard'); - } - - render() { - const { workspace } = this.props.actions; - return ( - - workspace.edit({ workspace: w })} - /> - - ); - } -} - -export default WorkspacesScreen; diff --git a/src/features/workspaces/actions.js b/src/features/workspaces/actions.js new file mode 100644 index 000000000..30866af96 --- /dev/null +++ b/src/features/workspaces/actions.js @@ -0,0 +1,8 @@ +import PropTypes from 'prop-types'; +import Workspace from './models/Workspace'; + +export default { + edit: { + workspace: PropTypes.instanceOf(Workspace).isRequired, + }, +}; diff --git a/src/features/workspaces/components/WorkspaceItem.js b/src/features/workspaces/components/WorkspaceItem.js new file mode 100644 index 000000000..b2c2a4830 --- /dev/null +++ b/src/features/workspaces/components/WorkspaceItem.js @@ -0,0 +1,42 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { intlShape } from 'react-intl'; +import { observer } from 'mobx-react'; +import classnames from 'classnames'; +import Workspace from '../models/Workspace'; + +// const messages = defineMessages({}); + +@observer +class WorkspaceItem extends Component { + static propTypes = { + workspace: PropTypes.instanceOf(Workspace).isRequired, + onItemClick: PropTypes.func.isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + render() { + const { workspace, onItemClick } = this.props; + // const { intl } = this.context; + + return ( + + onItemClick(workspace)} + > + {workspace.name} + + + ); + } +} + +export default WorkspaceItem; diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js new file mode 100644 index 000000000..2a8b3a5ee --- /dev/null +++ b/src/features/workspaces/components/WorkspacesDashboard.js @@ -0,0 +1,63 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; +import { defineMessages, intlShape } from 'react-intl'; + +import Loader from '../../../components/ui/Loader'; +import WorkspaceItem from './WorkspaceItem'; + +const messages = defineMessages({ + headline: { + id: 'settings.workspaces.headline', + defaultMessage: '!!!Your workspaces', + }, + noServicesAdded: { + id: 'settings.workspaces.noWorkspacesAdded', + defaultMessage: '!!!You haven\'t added any workspaces yet.', + }, +}); + +@observer +class WorkspacesDashboard extends Component { + static propTypes = { + workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, + isLoading: PropTypes.bool.isRequired, + onWorkspaceClick: PropTypes.func.isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + render() { + const { workspaces, isLoading, onWorkspaceClick } = this.props; + const { intl } = this.context; + + return ( +
+
+

{intl.formatMessage(messages.headline)}

+
+
+ {isLoading ? ( + + ) : ( + + + {workspaces.map(workspace => ( + onWorkspaceClick(w)} + /> + ))} + +
+ )} +
+
+ ); + } +} + +export default WorkspacesDashboard; diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js new file mode 100644 index 000000000..d8c52f586 --- /dev/null +++ b/src/features/workspaces/containers/EditWorkspaceScreen.js @@ -0,0 +1,75 @@ +import React, { Component } from 'react'; +import { inject, observer } from 'mobx-react'; +import { defineMessages, intlShape } from 'react-intl'; +import { Link } from 'react-router'; +import Form from '../../../lib/Form'; +import ErrorBoundary from '../../../components/util/ErrorBoundary'; +import { gaPage } from '../../../lib/analytics'; +import { state } from '../state'; + +const messages = defineMessages({ + name: { + id: 'settings.workspace.form.name', + defaultMessage: '!!!Name', + }, + yourWorkspaces: { + id: 'settings.workspace.form.yourWorkspaces', + defaultMessage: '!!!Your workspaces', + }, +}); + +@inject('stores', 'actions') @observer +class EditWorkspaceScreen extends Component { + static contextTypes = { + intl: intlShape, + }; + + componentDidMount() { + gaPage('Settings/Workspace/Edit'); + } + + prepareForm(workspace) { + const { intl } = this.context; + const config = { + fields: { + name: { + label: intl.formatMessage(messages.name), + placeholder: intl.formatMessage(messages.name), + value: workspace.name, + }, + }, + }; + return new Form(config); + } + + render() { + const { intl } = this.context; + const { workspaceBeingEdited } = state; + if (!workspaceBeingEdited) return null; + + // const form = this.prepareForm(workspaceBeingEdited); + + return ( + +
+
+ + + {intl.formatMessage(messages.yourWorkspaces)} + + + + + {workspaceBeingEdited.name} + +
+
+ test +
+
+
+ ); + } +} + +export default EditWorkspaceScreen; diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js new file mode 100644 index 000000000..f129edec5 --- /dev/null +++ b/src/features/workspaces/containers/WorkspacesScreen.js @@ -0,0 +1,37 @@ +import React, { Component } from 'react'; +import { inject, observer } from 'mobx-react'; +import PropTypes from 'prop-types'; +import { gaPage } from '../../../lib/analytics'; +import { state } from '../state'; +import WorkspacesDashboard from '../components/WorkspacesDashboard'; +import ErrorBoundary from '../../../components/util/ErrorBoundary'; + +@inject('actions') @observer +class WorkspacesScreen extends Component { + static propTypes = { + actions: PropTypes.shape({ + workspace: PropTypes.shape({ + edit: PropTypes.func.isRequired, + }), + }).isRequired, + }; + + componentDidMount() { + gaPage('Settings/Workspaces Dashboard'); + } + + render() { + const { workspace } = this.props.actions; + return ( + + workspace.edit({ workspace: w })} + /> + + ); + } +} + +export default WorkspacesScreen; diff --git a/src/features/workspaces/models/Workspace.js b/src/features/workspaces/models/Workspace.js new file mode 100644 index 000000000..ede2710dc --- /dev/null +++ b/src/features/workspaces/models/Workspace.js @@ -0,0 +1,25 @@ +import { observable } from 'mobx'; + +export default class Workspace { + id = null; + + @observable name = null; + + @observable order = null; + + @observable services = []; + + @observable userId = null; + + constructor(data) { + if (!data.id) { + throw Error('Workspace requires Id'); + } + + this.id = data.id; + this.name = data.name; + this.order = data.order; + this.services = data.services; + this.userId = data.userId; + } +} diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index aab66708b..ea61cec31 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -1,7 +1,7 @@ import { observable, reaction } from 'mobx'; import Store from '../../stores/lib/Store'; import CachedRequest from '../../stores/lib/CachedRequest'; -import Workspace from '../../models/Workspace'; +import Workspace from './models/Workspace'; import { matchRoute } from '../../helpers/routing-helpers'; const debug = require('debug')('Franz:feature:workspaces'); diff --git a/src/features/workspaces/styles/workspaces-table.scss b/src/features/workspaces/styles/workspaces-table.scss new file mode 100644 index 000000000..6d0e7b4f5 --- /dev/null +++ b/src/features/workspaces/styles/workspaces-table.scss @@ -0,0 +1,53 @@ +@import '../../../styles/config'; + +.theme__dark .workspace-table { + .workspace-table__column-info .mdi { color: $dark-theme-gray-lightest; } + + .workspace-table__row { + border-bottom: 1px solid $dark-theme-gray-darker; + + &:hover { background: $dark-theme-gray-darker; } + &.workspace-table__row--disabled { color: $dark-theme-gray; } + } +} + +.workspace-table { + width: 100%; + + .workspace-table__toggle { + width: 60px; + + .franz-form__field { + margin-bottom: 0; + } + } + + .workspace-table__column-action { + width: 40px + } + + .workspace-table__column-info { + width: 40px; + + .mdi { + color: $theme-gray-light; + display: block; + font-size: 18px; + } + } + + .workspace-table__row { + border-bottom: 1px solid $theme-gray-lightest; + + &:hover { + cursor: initial; + background: $theme-gray-lightest; + } + + &.workspace-table__row--disabled { + color: $theme-gray-light; + } + } + + td { padding: 10px; } +} diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index b5abb56d4..5cb8c6bd3 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -158,6 +158,7 @@ "settings.navigation.logout" : "Abmelden", "settings.navigation.settings" : "Einstellungen", "settings.navigation.yourServices" : "Deine Dienste", + "settings.navigation.yourWorkspaces": "Deine Workspaces", "settings.recipes.all" : "Alle Dienste", "settings.recipes.dev" : "Entwicklung", "settings.recipes.headline" : "Verfügbare Dienste", @@ -216,6 +217,8 @@ "settings.services.tooltip.isMuted" : "Alle Töne sind deaktiviert", "settings.services.tooltip.notificationsDisabled" : "Benachrichtigungen deaktiviert", "settings.services.updatedInfo" : "Deine Änderungen wurden gespeichert", + "settings.workspaces.headline": "Deine Workspaces", + "settings.workspace.form.yourWorkspaces": "Deine Workspaces", "settings.user.form.accountType.company" : "Firma", "settings.user.form.accountType.individual" : "Einzelperson", "settings.user.form.accountType.label" : "Konto-Typ", diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 1652b5585..9b323e323 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -197,6 +197,7 @@ "settings.user.form.accountType.non-profit": "Non-Profit", "settings.user.form.accountType.company": "Company", "settings.workspaces.headline": "Your workspaces", + "settings.workspace.form.yourWorkspaces": "Your workspaces", "subscription.type.free": "free", "subscription.type.month": "month", "subscription.type.year": "year", diff --git a/src/models/Workspace.js b/src/models/Workspace.js deleted file mode 100644 index ede2710dc..000000000 --- a/src/models/Workspace.js +++ /dev/null @@ -1,25 +0,0 @@ -import { observable } from 'mobx'; - -export default class Workspace { - id = null; - - @observable name = null; - - @observable order = null; - - @observable services = []; - - @observable userId = null; - - constructor(data) { - if (!data.id) { - throw Error('Workspace requires Id'); - } - - this.id = data.id; - this.name = data.name; - this.order = data.order; - this.services = data.services; - this.userId = data.userId; - } -} diff --git a/src/styles/main.scss b/src/styles/main.scss index 30f43532f..a941d89d0 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -30,7 +30,7 @@ $mdi-font-path: '../node_modules/mdi/fonts'; @import './content-tabs.scss'; @import './invite.scss'; @import './title-bar.scss'; -@import './workspace-table.scss'; +@import '../features/workspaces/styles/workspaces-table'; // form @import './input.scss'; diff --git a/src/styles/workspace-table.scss b/src/styles/workspace-table.scss deleted file mode 100644 index 05ebfa629..000000000 --- a/src/styles/workspace-table.scss +++ /dev/null @@ -1,53 +0,0 @@ -@import './config.scss'; - -.theme__dark .workspace-table { - .workspace-table__column-info .mdi { color: $dark-theme-gray-lightest; } - - .workspace-table__row { - border-bottom: 1px solid $dark-theme-gray-darker; - - &:hover { background: $dark-theme-gray-darker; } - &.workspace-table__row--disabled { color: $dark-theme-gray; } - } -} - -.workspace-table { - width: 100%; - - .workspace-table__toggle { - width: 60px; - - .franz-form__field { - margin-bottom: 0; - } - } - - .workspace-table__column-action { - width: 40px - } - - .workspace-table__column-info { - width: 40px; - - .mdi { - color: $theme-gray-light; - display: block; - font-size: 18px; - } - } - - .workspace-table__row { - border-bottom: 1px solid $theme-gray-lightest; - - &:hover { - cursor: initial; - background: $theme-gray-lightest; - } - - &.workspace-table__row--disabled { - color: $theme-gray-light; - } - } - - td { padding: 10px; } -} -- cgit v1.2.3-54-g00ecf From a421ba151f40695f54a4890219c5ec8af0a24a45 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Tue, 19 Feb 2019 15:02:11 +0100 Subject: prepare basic workspace edit form --- .../workspaces/components/EditWorkspaceForm.js | 142 +++++++++++++++++++++ .../workspaces/containers/EditWorkspaceScreen.js | 67 +++------- src/i18n/locales/de.json | 3 + src/i18n/locales/en-US.json | 3 + 4 files changed, 164 insertions(+), 51 deletions(-) create mode 100644 src/features/workspaces/components/EditWorkspaceForm.js (limited to 'src') diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js new file mode 100644 index 000000000..9e87b56dd --- /dev/null +++ b/src/features/workspaces/components/EditWorkspaceForm.js @@ -0,0 +1,142 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { observer } from 'mobx-react'; +import { defineMessages, intlShape } from 'react-intl'; +import { Link } from 'react-router'; +import { Input, Button } from '@meetfranz/forms'; + +import Form from '../../../lib/Form'; +import Workspace from '../models/Workspace'; + +const messages = defineMessages({ + buttonDelete: { + id: 'settings.workspace.form.buttonDelete', + defaultMessage: '!!!Delete workspace', + }, + buttonSave: { + id: 'settings.workspace.form.buttonSave', + defaultMessage: '!!!Save workspace', + }, + name: { + id: 'settings.workspace.form.name', + defaultMessage: '!!!Name', + }, + yourWorkspaces: { + id: 'settings.workspace.form.yourWorkspaces', + defaultMessage: '!!!Your workspaces', + }, +}); + +@observer +class EditWorkspaceForm extends Component { + static contextTypes = { + intl: intlShape, + }; + + static propTypes = { + workspace: PropTypes.instanceOf(Workspace).isRequired, + onSave: PropTypes.func.isRequired, + onDelete: PropTypes.func.isRequired, + isSaving: PropTypes.bool.isRequired, + isDeleting: PropTypes.bool.isRequired, + }; + + prepareForm(workspace) { + const { intl } = this.context; + const config = { + fields: { + name: { + label: intl.formatMessage(messages.name), + placeholder: intl.formatMessage(messages.name), + value: workspace.name, + }, + }, + }; + return new Form(config); + } + + submitForm(submitEvent, form) { + submitEvent.preventDefault(); + form.submit({ + onSuccess: async (f) => { + const { onSave } = this.props; + const values = f.values(); + onSave(values); + }, + onError: async () => {}, + }); + } + + render() { + const { intl } = this.context; + const { + workspace, + isDeleting, + isSaving, + onDelete, + } = this.props; + if (!workspace) return null; + + const form = this.prepareForm(workspace); + + return ( +
+
+ + + {intl.formatMessage(messages.yourWorkspaces)} + + + + + {workspace.name} + +
+
+
this.submitForm(e, form)} id="form"> +
+ +
+
+
+
+ {/* ===== Delete Button ===== */} + {isDeleting ? ( +
+
+ ); + } +} + +export default EditWorkspaceForm; diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js index d8c52f586..ed54b194e 100644 --- a/src/features/workspaces/containers/EditWorkspaceScreen.js +++ b/src/features/workspaces/containers/EditWorkspaceScreen.js @@ -1,72 +1,37 @@ import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; -import { defineMessages, intlShape } from 'react-intl'; -import { Link } from 'react-router'; -import Form from '../../../lib/Form'; + import ErrorBoundary from '../../../components/util/ErrorBoundary'; import { gaPage } from '../../../lib/analytics'; import { state } from '../state'; - -const messages = defineMessages({ - name: { - id: 'settings.workspace.form.name', - defaultMessage: '!!!Name', - }, - yourWorkspaces: { - id: 'settings.workspace.form.yourWorkspaces', - defaultMessage: '!!!Your workspaces', - }, -}); +import EditWorkspaceForm from '../components/EditWorkspaceForm'; @inject('stores', 'actions') @observer class EditWorkspaceScreen extends Component { - static contextTypes = { - intl: intlShape, - }; - componentDidMount() { gaPage('Settings/Workspace/Edit'); } - prepareForm(workspace) { - const { intl } = this.context; - const config = { - fields: { - name: { - label: intl.formatMessage(messages.name), - placeholder: intl.formatMessage(messages.name), - value: workspace.name, - }, - }, - }; - return new Form(config); - } + onDelete = () => { + console.log('delete workspace'); + }; + + onSave = (values) => { + console.log('save workspace', values); + }; render() { - const { intl } = this.context; const { workspaceBeingEdited } = state; if (!workspaceBeingEdited) return null; - - // const form = this.prepareForm(workspaceBeingEdited); - return ( -
-
- - - {intl.formatMessage(messages.yourWorkspaces)} - - - - - {workspaceBeingEdited.name} - -
-
- test -
-
+
); } diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 5cb8c6bd3..ffad8b835 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -219,6 +219,9 @@ "settings.services.updatedInfo" : "Deine Änderungen wurden gespeichert", "settings.workspaces.headline": "Deine Workspaces", "settings.workspace.form.yourWorkspaces": "Deine Workspaces", + "settings.workspace.form.name": "Name", + "settings.workspace.form.buttonDelete": "Workspace löschen", + "settings.workspace.form.buttonSave": "Workspace speichern", "settings.user.form.accountType.company" : "Firma", "settings.user.form.accountType.individual" : "Einzelperson", "settings.user.form.accountType.label" : "Konto-Typ", diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 9b323e323..899c62651 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -198,6 +198,9 @@ "settings.user.form.accountType.company": "Company", "settings.workspaces.headline": "Your workspaces", "settings.workspace.form.yourWorkspaces": "Your workspaces", + "settings.workspace.form.name": "Name", + "settings.workspace.form.buttonDelete": "Delete Workspace", + "settings.workspace.form.buttonSave": "Save Workspace", "subscription.type.free": "free", "subscription.type.month": "month", "subscription.type.year": "year", -- cgit v1.2.3-54-g00ecf From 7e40b08e2f8ab2448dcbe2ce7b4e38ca66764b9c Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Fri, 22 Feb 2019 12:34:27 +0100 Subject: add form for creating workspaces --- .eslintrc | 2 +- src/features/delayApp/Component.js | 2 +- src/features/workspaces/actions.js | 3 + src/features/workspaces/api.js | 9 +++ .../workspaces/components/CreateWorkspaceForm.js | 94 ++++++++++++++++++++++ .../workspaces/components/WorkspacesDashboard.js | 58 ++++++++----- .../workspaces/containers/WorkspacesScreen.js | 1 + src/features/workspaces/store.js | 14 +++- src/i18n/locales/de.json | 6 +- src/i18n/locales/en-US.json | 2 + src/styles/main.scss | 2 + 11 files changed, 170 insertions(+), 23 deletions(-) create mode 100644 src/features/workspaces/components/CreateWorkspaceForm.js (limited to 'src') diff --git a/.eslintrc b/.eslintrc index e15148e96..48fb21250 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,7 +13,7 @@ "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], - "react/forbid-prop-types": 1, + "react/forbid-prop-types": 0, "react/destructuring-assignment": 1, "prefer-destructuring": 1, "no-underscore-dangle": 0, diff --git a/src/features/delayApp/Component.js b/src/features/delayApp/Component.js index ff84510e8..ff0f1f2f8 100644 --- a/src/features/delayApp/Component.js +++ b/src/features/delayApp/Component.js @@ -38,7 +38,7 @@ export default @inject('actions') @injectSheet(styles) @observer class DelayApp state = { countdown: config.delayDuration, - } + }; countdownInterval = null; diff --git a/src/features/workspaces/actions.js b/src/features/workspaces/actions.js index 30866af96..390af0696 100644 --- a/src/features/workspaces/actions.js +++ b/src/features/workspaces/actions.js @@ -5,4 +5,7 @@ export default { edit: { workspace: PropTypes.instanceOf(Workspace).isRequired, }, + create: { + name: PropTypes.string.isRequired, + }, }; diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js index 97badbd01..65108a077 100644 --- a/src/features/workspaces/api.js +++ b/src/features/workspaces/api.js @@ -10,4 +10,13 @@ export default { if (!request.ok) throw request; return request.json(); }, + createWorkspace: async (name) => { + const url = `${API}/${API_VERSION}/workspace`; + const request = await window.fetch(url, prepareAuthRequest({ + method: 'POST', + body: JSON.stringify({ name }), + })); + if (!request.ok) throw request; + return request.json(); + }, }; diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js new file mode 100644 index 000000000..d440b9bae --- /dev/null +++ b/src/features/workspaces/components/CreateWorkspaceForm.js @@ -0,0 +1,94 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { observer } from 'mobx-react'; +import { defineMessages, intlShape } from 'react-intl'; +import { Input, Button } from '@meetfranz/forms'; +import injectSheet from 'react-jss'; + +import Form from '../../../lib/Form'; + +const messages = defineMessages({ + submitButton: { + id: 'settings.workspace.add.form.submitButton', + defaultMessage: '!!!Save workspace', + }, + name: { + id: 'settings.workspace.add.form.name', + defaultMessage: '!!!Name', + }, +}); + +const styles = () => ({ + form: { + display: 'flex', + }, + input: { + flexGrow: 1, + marginRight: '10px', + }, + submitButton: { + height: 'inherit', + marginTop: '17px', + }, +}); + +@observer @injectSheet(styles) +class CreateWorkspaceForm extends Component { + static contextTypes = { + intl: intlShape, + }; + + static propTypes = { + classes: PropTypes.object.isRequired, + onSubmit: PropTypes.func.isRequired, + }; + + prepareForm() { + const { intl } = this.context; + const config = { + fields: { + name: { + label: intl.formatMessage(messages.name), + placeholder: intl.formatMessage(messages.name), + value: '', + }, + }, + }; + return new Form(config); + } + + submitForm(form) { + form.submit({ + onSuccess: async (f) => { + const { onSubmit } = this.props; + const values = f.values(); + onSubmit(values); + }, + onError: async () => {}, + }); + } + + render() { + const { intl } = this.context; + const { classes } = this.props; + const form = this.prepareForm(); + + return ( +
+ +
+ ); + } +} + +export default CreateWorkspaceForm; diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js index 2a8b3a5ee..917807302 100644 --- a/src/features/workspaces/components/WorkspacesDashboard.js +++ b/src/features/workspaces/components/WorkspacesDashboard.js @@ -2,9 +2,11 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; import { defineMessages, intlShape } from 'react-intl'; +import injectSheet from 'react-jss'; import Loader from '../../../components/ui/Loader'; import WorkspaceItem from './WorkspaceItem'; +import CreateWorkspaceForm from './CreateWorkspaceForm'; const messages = defineMessages({ headline: { @@ -17,12 +19,21 @@ const messages = defineMessages({ }, }); -@observer +const styles = () => ({ + createForm: { + height: 'auto', + marginBottom: '20px', + }, +}); + +@observer @injectSheet(styles) class WorkspacesDashboard extends Component { static propTypes = { - workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, + classes: PropTypes.object.isRequired, isLoading: PropTypes.bool.isRequired, + onCreateWorkspaceSubmit: PropTypes.func.isRequired, onWorkspaceClick: PropTypes.func.isRequired, + workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, }; static contextTypes = { @@ -30,7 +41,13 @@ class WorkspacesDashboard extends Component { }; render() { - const { workspaces, isLoading, onWorkspaceClick } = this.props; + const { + workspaces, + isLoading, + onCreateWorkspaceSubmit, + onWorkspaceClick, + classes, + } = this.props; const { intl } = this.context; return ( @@ -39,21 +56,26 @@ class WorkspacesDashboard extends Component {

{intl.formatMessage(messages.headline)}

- {isLoading ? ( - - ) : ( - - - {workspaces.map(workspace => ( - onWorkspaceClick(w)} - /> - ))} - -
- )} +
+
+ +
+ {isLoading ? ( + + ) : ( + + + {workspaces.map(workspace => ( + onWorkspaceClick(w)} + /> + ))} + +
+ )} +
); diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js index f129edec5..eb3287952 100644 --- a/src/features/workspaces/containers/WorkspacesScreen.js +++ b/src/features/workspaces/containers/WorkspacesScreen.js @@ -27,6 +27,7 @@ class WorkspacesScreen extends Component { workspace.create(data)} onWorkspaceClick={w => workspace.edit({ workspace: w })} /> diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index ea61cec31..d90f9caac 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -49,6 +49,7 @@ export default class WorkspacesStore extends Store { ); this.actions.workspace.edit.listen(this._edit); + this.actions.workspace.create.listen(this._create); } _setWorkspaces = (workspaces) => { @@ -64,5 +65,16 @@ export default class WorkspacesStore extends Store { _edit = ({ workspace }) => { this.stores.router.push(`/settings/workspaces/edit/${workspace.id}`); - } + }; + + _create = async ({ name }) => { + try { + const result = await this.api.createWorkspace(name); + const workspace = new Workspace(result); + this.state.workspaces.push(workspace); + this._edit({ workspace }); + } catch (error) { + throw error; + } + }; } diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index ffad8b835..b795b90f8 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -218,10 +218,12 @@ "settings.services.tooltip.notificationsDisabled" : "Benachrichtigungen deaktiviert", "settings.services.updatedInfo" : "Deine Änderungen wurden gespeichert", "settings.workspaces.headline": "Deine Workspaces", + "settings.workspace.add.form.submitButton": "Create Workspace", + "settings.workspace.add.form.name": "Name", "settings.workspace.form.yourWorkspaces": "Deine Workspaces", "settings.workspace.form.name": "Name", - "settings.workspace.form.buttonDelete": "Workspace löschen", - "settings.workspace.form.buttonSave": "Workspace speichern", + "settings.workspace.form.buttonDelete": "Workspace löschen", + "settings.workspace.form.buttonSave": "Workspace speichern", "settings.user.form.accountType.company" : "Firma", "settings.user.form.accountType.individual" : "Einzelperson", "settings.user.form.accountType.label" : "Konto-Typ", diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 899c62651..24c96cb26 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -197,6 +197,8 @@ "settings.user.form.accountType.non-profit": "Non-Profit", "settings.user.form.accountType.company": "Company", "settings.workspaces.headline": "Your workspaces", + "settings.workspace.add.form.submitButton": "Create Workspace", + "settings.workspace.add.form.name": "Name", "settings.workspace.form.yourWorkspaces": "Your workspaces", "settings.workspace.form.name": "Name", "settings.workspace.form.buttonDelete": "Delete Workspace", diff --git a/src/styles/main.scss b/src/styles/main.scss index a941d89d0..9ba7f5827 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -30,6 +30,8 @@ $mdi-font-path: '../node_modules/mdi/fonts'; @import './content-tabs.scss'; @import './invite.scss'; @import './title-bar.scss'; + +// Workspaces legacy css @import '../features/workspaces/styles/workspaces-table'; // form -- cgit v1.2.3-54-g00ecf From 18d2b0f988792632d8b9395d06613d08c582ad7b Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Fri, 22 Feb 2019 13:03:40 +0100 Subject: small fixes --- .eslintrc | 1 + src/i18n/locales/de.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/.eslintrc b/.eslintrc index 48fb21250..f1051723d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,6 +2,7 @@ "parser": "babel-eslint", "extends": "eslint-config-airbnb", "rules": { + "consistent-return": 0, "import/extensions": 0, "import/no-extraneous-dependencies": 0, "import/no-unresolved": [2, { diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index b795b90f8..e1a955176 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -218,7 +218,7 @@ "settings.services.tooltip.notificationsDisabled" : "Benachrichtigungen deaktiviert", "settings.services.updatedInfo" : "Deine Änderungen wurden gespeichert", "settings.workspaces.headline": "Deine Workspaces", - "settings.workspace.add.form.submitButton": "Create Workspace", + "settings.workspace.add.form.submitButton": "Workspace erstellen", "settings.workspace.add.form.name": "Name", "settings.workspace.form.yourWorkspaces": "Deine Workspaces", "settings.workspace.form.name": "Name", -- cgit v1.2.3-54-g00ecf From 3de31efa29b8f2729f968d9d63c42d21c7d8dcf5 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Fri, 22 Feb 2019 13:04:51 +0100 Subject: adds flow for deleting workspaces --- src/api/utils/auth.js | 4 ++++ src/features/workspaces/actions.js | 3 +++ src/features/workspaces/api.js | 18 ++++++++++++------ .../workspaces/containers/EditWorkspaceScreen.js | 14 +++++++++++++- src/features/workspaces/containers/WorkspacesScreen.js | 6 +++--- src/features/workspaces/store.js | 11 +++++++++++ 6 files changed, 46 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/api/utils/auth.js b/src/api/utils/auth.js index 47ac94c19..d469853a5 100644 --- a/src/api/utils/auth.js +++ b/src/api/utils/auth.js @@ -22,3 +22,7 @@ export const prepareAuthRequest = (options, auth = true) => { return request; }; + +export const sendAuthRequest = (url, options) => ( + window.fetch(url, prepareAuthRequest(options)) +); diff --git a/src/features/workspaces/actions.js b/src/features/workspaces/actions.js index 390af0696..83d3447c3 100644 --- a/src/features/workspaces/actions.js +++ b/src/features/workspaces/actions.js @@ -8,4 +8,7 @@ export default { create: { name: PropTypes.string.isRequired, }, + delete: { + workspace: PropTypes.instanceOf(Workspace).isRequired, + }, }; diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js index 65108a077..fabc12455 100644 --- a/src/features/workspaces/api.js +++ b/src/features/workspaces/api.js @@ -1,21 +1,27 @@ -import { prepareAuthRequest } from '../../api/utils/auth'; +import { sendAuthRequest } from '../../api/utils/auth'; import { API, API_VERSION } from '../../environment'; export default { getUserWorkspaces: async () => { const url = `${API}/${API_VERSION}/workspace`; - const request = await window.fetch(url, prepareAuthRequest({ - method: 'GET', - })); + const request = await sendAuthRequest(url, { method: 'GET' }); if (!request.ok) throw request; return request.json(); }, + createWorkspace: async (name) => { const url = `${API}/${API_VERSION}/workspace`; - const request = await window.fetch(url, prepareAuthRequest({ + const request = await sendAuthRequest(url, { method: 'POST', body: JSON.stringify({ name }), - })); + }); + if (!request.ok) throw request; + return request.json(); + }, + + deleteWorkspace: async (workspace) => { + const url = `${API}/${API_VERSION}/workspace/${workspace.id}`; + const request = await sendAuthRequest(url, { method: 'DELETE' }); if (!request.ok) throw request; return request.json(); }, diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js index ed54b194e..87b6062fb 100644 --- a/src/features/workspaces/containers/EditWorkspaceScreen.js +++ b/src/features/workspaces/containers/EditWorkspaceScreen.js @@ -5,15 +5,27 @@ import ErrorBoundary from '../../../components/util/ErrorBoundary'; import { gaPage } from '../../../lib/analytics'; import { state } from '../state'; import EditWorkspaceForm from '../components/EditWorkspaceForm'; +import PropTypes from 'prop-types'; @inject('stores', 'actions') @observer class EditWorkspaceScreen extends Component { + static propTypes = { + actions: PropTypes.shape({ + workspace: PropTypes.shape({ + delete: PropTypes.func.isRequired, + }), + }).isRequired, + }; + componentDidMount() { gaPage('Settings/Workspace/Edit'); } onDelete = () => { - console.log('delete workspace'); + const { workspaceBeingEdited } = state; + const { actions } = this.props; + if (!workspaceBeingEdited) return null; + actions.workspace.delete({ workspace: workspaceBeingEdited }); }; onSave = (values) => { diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js index eb3287952..a3876a01a 100644 --- a/src/features/workspaces/containers/WorkspacesScreen.js +++ b/src/features/workspaces/containers/WorkspacesScreen.js @@ -21,14 +21,14 @@ class WorkspacesScreen extends Component { } render() { - const { workspace } = this.props.actions; + const { actions } = this.props; return ( workspace.create(data)} - onWorkspaceClick={w => workspace.edit({ workspace: w })} + onCreateWorkspaceSubmit={data => actions.workspace.create(data)} + onWorkspaceClick={w => actions.workspace.edit({ workspace: w })} /> ); diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index d90f9caac..a9b93f904 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -50,6 +50,7 @@ export default class WorkspacesStore extends Store { this.actions.workspace.edit.listen(this._edit); this.actions.workspace.create.listen(this._create); + this.actions.workspace.delete.listen(this._delete); } _setWorkspaces = (workspaces) => { @@ -77,4 +78,14 @@ export default class WorkspacesStore extends Store { throw error; } }; + + _delete = async ({ workspace }) => { + try { + await this.api.deleteWorkspace(workspace); + this.state.workspaces.remove(workspace); + this.stores.router.push('/settings/workspaces'); + } catch (error) { + throw error; + } + }; } -- cgit v1.2.3-54-g00ecf From d06c28489168e64c1a4124cedcf205b320b72708 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Fri, 22 Feb 2019 16:34:42 +0100 Subject: stop tracking google analytics in components --- src/features/workspaces/containers/EditWorkspaceScreen.js | 7 +------ src/features/workspaces/containers/WorkspacesScreen.js | 5 ----- 2 files changed, 1 insertion(+), 11 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js index 87b6062fb..1ddf8dfcb 100644 --- a/src/features/workspaces/containers/EditWorkspaceScreen.js +++ b/src/features/workspaces/containers/EditWorkspaceScreen.js @@ -1,11 +1,10 @@ import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; +import PropTypes from 'prop-types'; import ErrorBoundary from '../../../components/util/ErrorBoundary'; -import { gaPage } from '../../../lib/analytics'; import { state } from '../state'; import EditWorkspaceForm from '../components/EditWorkspaceForm'; -import PropTypes from 'prop-types'; @inject('stores', 'actions') @observer class EditWorkspaceScreen extends Component { @@ -17,10 +16,6 @@ class EditWorkspaceScreen extends Component { }).isRequired, }; - componentDidMount() { - gaPage('Settings/Workspace/Edit'); - } - onDelete = () => { const { workspaceBeingEdited } = state; const { actions } = this.props; diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js index a3876a01a..b89cbcf67 100644 --- a/src/features/workspaces/containers/WorkspacesScreen.js +++ b/src/features/workspaces/containers/WorkspacesScreen.js @@ -1,7 +1,6 @@ import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; import PropTypes from 'prop-types'; -import { gaPage } from '../../../lib/analytics'; import { state } from '../state'; import WorkspacesDashboard from '../components/WorkspacesDashboard'; import ErrorBoundary from '../../../components/util/ErrorBoundary'; @@ -16,10 +15,6 @@ class WorkspacesScreen extends Component { }).isRequired, }; - componentDidMount() { - gaPage('Settings/Workspaces Dashboard'); - } - render() { const { actions } = this.props; return ( -- cgit v1.2.3-54-g00ecf From ff4c9c7f527e911c37cf02a5d048f5e6652ed253 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Tue, 26 Feb 2019 13:31:43 +0100 Subject: improve workspace form setup --- .../workspaces/components/CreateWorkspaceForm.js | 29 ++++++------- .../workspaces/components/EditWorkspaceForm.js | 50 ++++++++++++++-------- .../workspaces/containers/EditWorkspaceScreen.js | 2 +- 3 files changed, 46 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js index d440b9bae..83f6e07f7 100644 --- a/src/features/workspaces/components/CreateWorkspaceForm.js +++ b/src/features/workspaces/components/CreateWorkspaceForm.js @@ -4,8 +4,8 @@ import { observer } from 'mobx-react'; import { defineMessages, intlShape } from 'react-intl'; import { Input, Button } from '@meetfranz/forms'; import injectSheet from 'react-jss'; - import Form from '../../../lib/Form'; +import { required } from '../../../helpers/validation-helpers'; const messages = defineMessages({ submitButton: { @@ -28,11 +28,11 @@ const styles = () => ({ }, submitButton: { height: 'inherit', - marginTop: '17px', + marginTop: '3px', }, }); -@observer @injectSheet(styles) +@injectSheet(styles) @observer class CreateWorkspaceForm extends Component { static contextTypes = { intl: intlShape, @@ -43,46 +43,45 @@ class CreateWorkspaceForm extends Component { onSubmit: PropTypes.func.isRequired, }; - prepareForm() { + form = (() => { const { intl } = this.context; - const config = { + return new Form({ fields: { name: { label: intl.formatMessage(messages.name), placeholder: intl.formatMessage(messages.name), value: '', + validators: [required], }, }, - }; - return new Form(config); - } + }); + })(); - submitForm(form) { + submitForm() { + const { form } = this; form.submit({ onSuccess: async (f) => { const { onSubmit } = this.props; - const values = f.values(); - onSubmit(values); + onSubmit(f.values()); }, - onError: async () => {}, }); } render() { const { intl } = this.context; const { classes } = this.props; - const form = this.prepareForm(); - + const { form } = this; return (
diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js index 1ddf8dfcb..17b723303 100644 --- a/src/features/workspaces/containers/EditWorkspaceScreen.js +++ b/src/features/workspaces/containers/EditWorkspaceScreen.js @@ -3,8 +3,8 @@ import { inject, observer } from 'mobx-react'; import PropTypes from 'prop-types'; import ErrorBoundary from '../../../components/util/ErrorBoundary'; -import { state } from '../state'; import EditWorkspaceForm from '../components/EditWorkspaceForm'; +import { state } from '../state'; @inject('stores', 'actions') @observer class EditWorkspaceScreen extends Component { -- cgit v1.2.3-54-g00ecf From dca7437b45c8eb67692a1df563fb4e969826b1cc Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Tue, 26 Feb 2019 15:29:34 +0100 Subject: finish basic workspace settings --- src/features/workspaces/actions.js | 3 ++ src/features/workspaces/api.js | 11 +++++ .../workspaces/components/EditWorkspaceForm.js | 46 +++++++++++++++++++-- .../workspaces/components/ServiceListItem.js | 48 ++++++++++++++++++++++ .../workspaces/containers/EditWorkspaceScreen.js | 14 ++++++- src/features/workspaces/models/Workspace.js | 2 +- src/features/workspaces/store.js | 12 ++++++ src/i18n/locales/de.json | 1 + src/i18n/locales/en-US.json | 1 + 9 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 src/features/workspaces/components/ServiceListItem.js (limited to 'src') diff --git a/src/features/workspaces/actions.js b/src/features/workspaces/actions.js index 83d3447c3..84de2b011 100644 --- a/src/features/workspaces/actions.js +++ b/src/features/workspaces/actions.js @@ -11,4 +11,7 @@ export default { delete: { workspace: PropTypes.instanceOf(Workspace).isRequired, }, + update: { + workspace: PropTypes.instanceOf(Workspace).isRequired, + }, }; diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js index fabc12455..733cb5593 100644 --- a/src/features/workspaces/api.js +++ b/src/features/workspaces/api.js @@ -1,3 +1,4 @@ +import { pick } from 'lodash'; import { sendAuthRequest } from '../../api/utils/auth'; import { API, API_VERSION } from '../../environment'; @@ -25,4 +26,14 @@ export default { if (!request.ok) throw request; return request.json(); }, + + updateWorkspace: async (workspace) => { + const url = `${API}/${API_VERSION}/workspace/${workspace.id}`; + const request = await sendAuthRequest(url, { + method: 'PUT', + body: JSON.stringify(pick(workspace, ['name', 'services'])), + }); + if (!request.ok) throw request; + return request.json(); + }, }; diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js index 05ca65403..48090f608 100644 --- a/src/features/workspaces/components/EditWorkspaceForm.js +++ b/src/features/workspaces/components/EditWorkspaceForm.js @@ -7,8 +7,10 @@ import { Input, Button } from '@meetfranz/forms'; import injectSheet from 'react-jss'; import Workspace from '../models/Workspace'; +import Service from '../../../models/Service'; import Form from '../../../lib/Form'; import { required } from '../../../helpers/validation-helpers'; +import ServiceListItem from './ServiceListItem'; const messages = defineMessages({ buttonDelete: { @@ -27,12 +29,19 @@ const messages = defineMessages({ id: 'settings.workspace.form.yourWorkspaces', defaultMessage: '!!!Your workspaces', }, + servicesInWorkspaceHeadline: { + id: 'settings.workspace.form.servicesInWorkspaceHeadline', + defaultMessage: '!!!Services in this Workspace', + }, }); const styles = () => ({ nameInput: { height: 'auto', }, + serviceList: { + height: 'auto', + }, }); @injectSheet(styles) @observer @@ -42,11 +51,13 @@ class EditWorkspaceForm extends Component { }; static propTypes = { - workspace: PropTypes.instanceOf(Workspace).isRequired, - onSave: PropTypes.func.isRequired, - onDelete: PropTypes.func.isRequired, - isSaving: PropTypes.bool.isRequired, + classes: PropTypes.object.isRequired, isDeleting: PropTypes.bool.isRequired, + isSaving: PropTypes.bool.isRequired, + onDelete: PropTypes.func.isRequired, + onSave: PropTypes.func.isRequired, + services: PropTypes.arrayOf(PropTypes.instanceOf(Service)).isRequired, + workspace: PropTypes.instanceOf(Workspace).isRequired, }; form = this.prepareWorkspaceForm(this.props.workspace); @@ -68,6 +79,9 @@ class EditWorkspaceForm extends Component { value: workspace.name, validators: [required], }, + services: { + value: workspace.services.slice(), + }, }, }); } @@ -83,6 +97,17 @@ class EditWorkspaceForm extends Component { }); } + toggleService(service) { + const servicesField = this.form.$('services'); + const serviceIds = servicesField.value; + if (serviceIds.includes(service.id)) { + serviceIds.splice(serviceIds.indexOf(service.id), 1); + } else { + serviceIds.push(service.id); + } + servicesField.set(serviceIds); + } + render() { const { intl } = this.context; const { @@ -91,8 +116,10 @@ class EditWorkspaceForm extends Component { isSaving, onDelete, workspace, + services, } = this.props; const { form } = this; + const workspaceServices = form.$('services').value; return (
@@ -110,6 +137,17 @@ class EditWorkspaceForm extends Component {
+

{intl.formatMessage(messages.servicesInWorkspaceHeadline)}

+
+ {services.map(s => ( + this.toggleService(s)} + /> + ))} +
{/* ===== Delete Button ===== */} diff --git a/src/features/workspaces/components/ServiceListItem.js b/src/features/workspaces/components/ServiceListItem.js new file mode 100644 index 000000000..146cc5a36 --- /dev/null +++ b/src/features/workspaces/components/ServiceListItem.js @@ -0,0 +1,48 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { observer } from 'mobx-react'; +import injectSheet from 'react-jss'; +import { Toggle } from '@meetfranz/forms'; + +import Service from '../../../models/Service'; + +const styles = () => ({ + service: { + height: 'auto', + display: 'flex', + }, + name: { + marginTop: '4px', + }, +}); + +@injectSheet(styles) @observer +class ServiceListItem extends Component { + static propTypes = { + classes: PropTypes.object.isRequired, + isInWorkspace: PropTypes.bool.isRequired, + onToggle: PropTypes.func.isRequired, + service: PropTypes.instanceOf(Service).isRequired, + }; + + render() { + const { + classes, + isInWorkspace, + onToggle, + service, + } = this.props; + + return ( +
+ +
+ ); + } +} + +export default ServiceListItem; diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js index 17b723303..790b8a0fe 100644 --- a/src/features/workspaces/containers/EditWorkspaceScreen.js +++ b/src/features/workspaces/containers/EditWorkspaceScreen.js @@ -5,6 +5,8 @@ import PropTypes from 'prop-types'; import ErrorBoundary from '../../../components/util/ErrorBoundary'; import EditWorkspaceForm from '../components/EditWorkspaceForm'; import { state } from '../state'; +import ServicesStore from '../../../stores/ServicesStore'; +import Workspace from '../models/Workspace'; @inject('stores', 'actions') @observer class EditWorkspaceScreen extends Component { @@ -14,6 +16,9 @@ class EditWorkspaceScreen extends Component { delete: PropTypes.func.isRequired, }), }).isRequired, + stores: PropTypes.shape({ + services: PropTypes.instanceOf(ServicesStore).isRequired, + }).isRequired, }; onDelete = () => { @@ -24,16 +29,23 @@ class EditWorkspaceScreen extends Component { }; onSave = (values) => { - console.log('save workspace', values); + const { workspaceBeingEdited } = state; + const { actions } = this.props; + const workspace = new Workspace( + Object.assign({}, workspaceBeingEdited, values), + ); + actions.workspace.update({ workspace }); }; render() { const { workspaceBeingEdited } = state; + const { stores } = this.props; if (!workspaceBeingEdited) return null; return ( { @@ -88,4 +89,15 @@ export default class WorkspacesStore extends Store { throw error; } }; + + _update = async ({ workspace }) => { + try { + await this.api.updateWorkspace(workspace); + const localWorkspace = this.state.workspaces.find(ws => ws.id === workspace.id); + Object.assign(localWorkspace, workspace); + this.stores.router.push('/settings/workspaces'); + } catch (error) { + throw error; + } + }; } diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index e1a955176..4906070a3 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -224,6 +224,7 @@ "settings.workspace.form.name": "Name", "settings.workspace.form.buttonDelete": "Workspace löschen", "settings.workspace.form.buttonSave": "Workspace speichern", + "settings.workspace.form.servicesInWorkspaceHeadline": "Services in diesem Workspace", "settings.user.form.accountType.company" : "Firma", "settings.user.form.accountType.individual" : "Einzelperson", "settings.user.form.accountType.label" : "Konto-Typ", diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index fe16e916f..cd5c417e3 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -207,6 +207,7 @@ "settings.workspace.form.name": "Name", "settings.workspace.form.buttonDelete": "Delete Workspace", "settings.workspace.form.buttonSave": "Save Workspace", + "settings.workspace.form.servicesInWorkspaceHeadline": "Services in this Workspace", "subscription.type.free": "free", "subscription.type.month": "month", "subscription.type.year": "year", -- cgit v1.2.3-54-g00ecf From 739ef2e8a2dec94c3e10c3d26d797fe759fac7aa Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Fri, 1 Mar 2019 14:25:44 +0100 Subject: finish workspaces mvp --- src/actions/index.js | 8 ++- src/actions/lib/actions.js | 29 +++++---- src/components/layout/Sidebar.js | 2 +- src/components/services/tabs/Tabbar.js | 4 +- src/features/workspaces/actions.js | 9 ++- .../workspaces/containers/EditWorkspaceScreen.js | 12 ++-- .../workspaces/containers/WorkspacesScreen.js | 10 +-- src/features/workspaces/index.js | 40 +++++++++++- src/features/workspaces/state.js | 6 +- src/features/workspaces/store.js | 37 +++++++---- src/i18n/locales/de.json | 5 +- src/i18n/locales/en-US.json | 5 +- src/lib/Menu.js | 71 +++++++++++++++++++++- src/stores/ServicesStore.js | 12 ++-- 14 files changed, 193 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/actions/index.js b/src/actions/index.js index 45e6da515..00f843cd6 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -11,7 +11,7 @@ import payment from './payment'; import news from './news'; import settings from './settings'; import requests from './requests'; -import workspace from '../features/workspaces/actions'; +import workspaces from '../features/workspaces/actions'; const actions = Object.assign({}, { service, @@ -24,7 +24,9 @@ const actions = Object.assign({}, { news, settings, requests, - workspace, }); -export default defineActions(actions, PropTypes.checkPropTypes); +export default Object.assign( + defineActions(actions, PropTypes.checkPropTypes), + { workspaces }, +); diff --git a/src/actions/lib/actions.js b/src/actions/lib/actions.js index 499018d70..6571e9441 100644 --- a/src/actions/lib/actions.js +++ b/src/actions/lib/actions.js @@ -1,18 +1,23 @@ +export const createActionsFromDefinitions = (actionDefinitions, validate) => { + const actions = {}; + Object.keys(actionDefinitions).forEach((actionName) => { + const action = (params) => { + const schema = actionDefinitions[actionName]; + validate(schema, params, actionName); + action.notify(params); + }; + actions[actionName] = action; + action.listeners = []; + action.listen = listener => action.listeners.push(listener); + action.notify = params => action.listeners.forEach(listener => listener(params)); + }); + return actions; +}; + export default (definitions, validate) => { const newActions = {}; Object.keys(definitions).forEach((scopeName) => { - newActions[scopeName] = {}; - Object.keys(definitions[scopeName]).forEach((actionName) => { - const action = (params) => { - const schema = definitions[scopeName][actionName]; - validate(schema, params, actionName); - action.notify(params); - }; - newActions[scopeName][actionName] = action; - action.listeners = []; - action.listen = listener => action.listeners.push(listener); - action.notify = params => action.listeners.forEach(listener => listener(params)); - }); + newActions[scopeName] = createActionsFromDefinitions(definitions[scopeName], validate); }); return newActions; }; diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index 609a3b604..fcc5b0001 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js @@ -31,7 +31,7 @@ export default @observer class Sidebar extends Component { openSettings: PropTypes.func.isRequired, toggleMuteApp: PropTypes.func.isRequired, isAppMuted: PropTypes.bool.isRequired, - } + }; static contextTypes = { intl: intlShape, diff --git a/src/components/services/tabs/Tabbar.js b/src/components/services/tabs/Tabbar.js index dd5c2140f..5e8260ad0 100644 --- a/src/components/services/tabs/Tabbar.js +++ b/src/components/services/tabs/Tabbar.js @@ -19,7 +19,7 @@ export default @observer class TabBar extends Component { updateService: PropTypes.func.isRequired, showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired, showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired, - } + }; onSortEnd = ({ oldIndex, newIndex }) => { const { @@ -45,7 +45,7 @@ export default @observer class TabBar extends Component { redirect: false, }); } - } + }; disableService({ serviceId }) { this.toggleService({ serviceId, isEnabled: false }); diff --git a/src/features/workspaces/actions.js b/src/features/workspaces/actions.js index 84de2b011..25246de09 100644 --- a/src/features/workspaces/actions.js +++ b/src/features/workspaces/actions.js @@ -1,7 +1,8 @@ import PropTypes from 'prop-types'; import Workspace from './models/Workspace'; +import { createActionsFromDefinitions } from '../../actions/lib/actions'; -export default { +export default createActionsFromDefinitions({ edit: { workspace: PropTypes.instanceOf(Workspace).isRequired, }, @@ -14,4 +15,8 @@ export default { update: { workspace: PropTypes.instanceOf(Workspace).isRequired, }, -}; + activate: { + workspace: PropTypes.instanceOf(Workspace).isRequired, + }, + deactivate: {}, +}, PropTypes.checkPropTypes); diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js index 790b8a0fe..1b13bc2d4 100644 --- a/src/features/workspaces/containers/EditWorkspaceScreen.js +++ b/src/features/workspaces/containers/EditWorkspaceScreen.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import ErrorBoundary from '../../../components/util/ErrorBoundary'; import EditWorkspaceForm from '../components/EditWorkspaceForm'; -import { state } from '../state'; +import { workspacesState } from '../state'; import ServicesStore from '../../../stores/ServicesStore'; import Workspace from '../models/Workspace'; @@ -22,23 +22,23 @@ class EditWorkspaceScreen extends Component { }; onDelete = () => { - const { workspaceBeingEdited } = state; + const { workspaceBeingEdited } = workspacesState; const { actions } = this.props; if (!workspaceBeingEdited) return null; - actions.workspace.delete({ workspace: workspaceBeingEdited }); + actions.workspaces.delete({ workspace: workspaceBeingEdited }); }; onSave = (values) => { - const { workspaceBeingEdited } = state; + const { workspaceBeingEdited } = workspacesState; const { actions } = this.props; const workspace = new Workspace( Object.assign({}, workspaceBeingEdited, values), ); - actions.workspace.update({ workspace }); + actions.workspaces.update({ workspace }); }; render() { - const { workspaceBeingEdited } = state; + const { workspaceBeingEdited } = workspacesState; const { stores } = this.props; if (!workspaceBeingEdited) return null; return ( diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js index b89cbcf67..94e714255 100644 --- a/src/features/workspaces/containers/WorkspacesScreen.js +++ b/src/features/workspaces/containers/WorkspacesScreen.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; import PropTypes from 'prop-types'; -import { state } from '../state'; +import { workspacesState } from '../state'; import WorkspacesDashboard from '../components/WorkspacesDashboard'; import ErrorBoundary from '../../../components/util/ErrorBoundary'; @@ -20,10 +20,10 @@ class WorkspacesScreen extends Component { return ( actions.workspace.create(data)} - onWorkspaceClick={w => actions.workspace.edit({ workspace: w })} + workspaces={workspacesState.workspaces} + isLoading={workspacesState.isLoading} + onCreateWorkspaceSubmit={data => actions.workspaces.create(data)} + onWorkspaceClick={w => actions.workspaces.edit({ workspace: w })} /> ); diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js index 50ac3b414..8091f49fc 100644 --- a/src/features/workspaces/index.js +++ b/src/features/workspaces/index.js @@ -1,14 +1,28 @@ -import { reaction } from 'mobx'; +import { reaction, runInAction } from 'mobx'; import WorkspacesStore from './store'; import api from './api'; -import { state, resetState } from './state'; +import { workspacesState, resetState } from './state'; const debug = require('debug')('Franz:feature:workspaces'); let store = null; +export const filterServicesByActiveWorkspace = (services) => { + const { isFeatureActive, activeWorkspace } = workspacesState; + if (isFeatureActive && activeWorkspace) { + return services.filter(s => activeWorkspace.services.includes(s.id)); + } + return services; +}; + +export const getActiveWorkspaceServices = (services) => { + return filterServicesByActiveWorkspace(services); +}; + export default function initWorkspaces(stores, actions) { const { features, user } = stores; + + // Toggle workspace feature reaction( () => ( features.features.isWorkspaceEnabled && ( @@ -18,10 +32,12 @@ export default function initWorkspaces(stores, actions) { (isEnabled) => { if (isEnabled) { debug('Initializing `workspaces` feature'); - store = new WorkspacesStore(stores, api, actions, state); + store = new WorkspacesStore(stores, api, actions, workspacesState); store.initialize(); + runInAction(() => { workspacesState.isFeatureActive = true; }); } else if (store) { debug('Disabling `workspaces` feature'); + runInAction(() => { workspacesState.isFeatureActive = false; }); store.teardown(); store = null; resetState(); // Reset state to default @@ -31,4 +47,22 @@ export default function initWorkspaces(stores, actions) { fireImmediately: true, }, ); + + // Update active service on workspace switches + reaction(() => ({ + isFeatureActive: workspacesState.isFeatureActive, + activeWorkspace: workspacesState.activeWorkspace, + }), ({ isFeatureActive, activeWorkspace }) => { + if (!isFeatureActive) return; + if (activeWorkspace) { + const services = stores.services.allDisplayed; + const activeService = services.find(s => s.isActive); + const workspaceServices = filterServicesByActiveWorkspace(services); + const isActiveServiceInWorkspace = workspaceServices.includes(activeService); + if (!isActiveServiceInWorkspace) { + console.log(workspaceServices[0].id); + actions.service.setActive({ serviceId: workspaceServices[0].id }); + } + } + }); } diff --git a/src/features/workspaces/state.js b/src/features/workspaces/state.js index f938c1470..963b96f81 100644 --- a/src/features/workspaces/state.js +++ b/src/features/workspaces/state.js @@ -1,13 +1,15 @@ import { observable } from 'mobx'; const defaultState = { + activeWorkspace: null, isLoading: false, + isFeatureActive: false, workspaces: [], workspaceBeingEdited: null, }; -export const state = observable(defaultState); +export const workspacesState = observable(defaultState); export function resetState() { - Object.assign(state, defaultState); + Object.assign(workspacesState, defaultState); } diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 5cccb2ab7..a2997a0d2 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -1,8 +1,9 @@ -import { observable, reaction } from 'mobx'; +import { observable, reaction, action } from 'mobx'; import Store from '../../stores/lib/Store'; import CachedRequest from '../../stores/lib/CachedRequest'; import Workspace from './models/Workspace'; import { matchRoute } from '../../helpers/routing-helpers'; +import workspaceActions from './actions'; const debug = require('debug')('Franz:feature:workspaces'); @@ -48,28 +49,30 @@ export default class WorkspacesStore extends Store { }, ); - this.actions.workspace.edit.listen(this._edit); - this.actions.workspace.create.listen(this._create); - this.actions.workspace.delete.listen(this._delete); - this.actions.workspace.update.listen(this._update); + workspaceActions.edit.listen(this._edit); + workspaceActions.create.listen(this._create); + workspaceActions.delete.listen(this._delete); + workspaceActions.update.listen(this._update); + workspaceActions.activate.listen(this._setActiveWorkspace); + workspaceActions.deactivate.listen(this._deactivateActiveWorkspace); } - _setWorkspaces = (workspaces) => { + _getWorkspaceById = id => this.state.workspaces.find(w => w.id === id); + + @action _setWorkspaces = (workspaces) => { debug('setting user workspaces', workspaces.slice()); this.state.workspaces = workspaces.map(data => new Workspace(data)); }; - _setIsLoading = (isLoading) => { + @action _setIsLoading = (isLoading) => { this.state.isLoading = isLoading; }; - _getWorkspaceById = id => this.state.workspaces.find(w => w.id === id); - - _edit = ({ workspace }) => { + @action _edit = ({ workspace }) => { this.stores.router.push(`/settings/workspaces/edit/${workspace.id}`); }; - _create = async ({ name }) => { + @action _create = async ({ name }) => { try { const result = await this.api.createWorkspace(name); const workspace = new Workspace(result); @@ -80,7 +83,7 @@ export default class WorkspacesStore extends Store { } }; - _delete = async ({ workspace }) => { + @action _delete = async ({ workspace }) => { try { await this.api.deleteWorkspace(workspace); this.state.workspaces.remove(workspace); @@ -90,7 +93,7 @@ export default class WorkspacesStore extends Store { } }; - _update = async ({ workspace }) => { + @action _update = async ({ workspace }) => { try { await this.api.updateWorkspace(workspace); const localWorkspace = this.state.workspaces.find(ws => ws.id === workspace.id); @@ -100,4 +103,12 @@ export default class WorkspacesStore extends Store { throw error; } }; + + @action _setActiveWorkspace = ({ workspace }) => { + this.state.activeWorkspace = workspace; + }; + + @action _deactivateActiveWorkspace = () => { + this.state.activeWorkspace = null; + }; } diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 4906070a3..0c1fb8aa6 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -74,6 +74,9 @@ "menu.window" : "Fenster", "menu.window.close" : "Schließen", "menu.window.minimize" : "Minimieren", + "menu.workspaces": "Workspaces", + "menu.workspaces.defaultWorkspace": "All services", + "menu.workspaces.addNewWorkspace": "Add New Workspace", "password.email.label" : "E-Mail Adresse", "password.headline" : "Passwort zurücksetzen", "password.link.login" : "An Deinem Konto anmelden", @@ -224,7 +227,7 @@ "settings.workspace.form.name": "Name", "settings.workspace.form.buttonDelete": "Workspace löschen", "settings.workspace.form.buttonSave": "Workspace speichern", - "settings.workspace.form.servicesInWorkspaceHeadline": "Services in diesem Workspace", + "settings.workspace.form.servicesInWorkspaceHeadline": "Services in diesem Workspace", "settings.user.form.accountType.company" : "Firma", "settings.user.form.accountType.individual" : "Einzelperson", "settings.user.form.accountType.label" : "Konto-Typ", diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 988ac46f2..2a51662a2 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -276,7 +276,10 @@ "menu.app.hideOthers": "Hide Others", "menu.app.unhide": "Unhide", "menu.app.quit": "Quit", - "menu.services.addNewService": "Add New Service...", + "menu.services.addNewService": "Add New Service", + "menu.workspaces": "Workspaces", + "menu.workspaces.defaultWorkspace": "All services", + "menu.workspaces.addNewWorkspace": "Add New Workspace", "validation.required": "{field} is required", "validation.email": "{field} is not valid", "validation.url": "{field} is not a valid URL", diff --git a/src/lib/Menu.js b/src/lib/Menu.js index c378619ad..1560dd285 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js @@ -3,6 +3,8 @@ import { observable, autorun, computed } from 'mobx'; import { defineMessages } from 'react-intl'; import { isMac, ctrlKey, cmdKey } from '../environment'; +import { workspacesState } from '../features/workspaces/state'; +import workspaceActions from '../features/workspaces/actions'; const { app, Menu, dialog } = remote; @@ -179,6 +181,18 @@ const menuItems = defineMessages({ id: 'menu.services.addNewService', defaultMessage: '!!!Add New Service...', }, + workspaces: { + id: 'menu.workspaces', + defaultMessage: '!!!Workspaces', + }, + defaultWorkspace: { + id: 'menu.workspaces.defaultWorkspace', + defaultMessage: '!!!Default', + }, + addNewWorkspace: { + id: 'menu.workspaces.addNewWorkspace', + defaultMessage: '!!!Add New Workspace...', + }, }); function getActiveWebview() { @@ -265,6 +279,10 @@ const _templateFactory = intl => [ label: intl.formatMessage(menuItems.services), submenu: [], }, + { + label: intl.formatMessage(menuItems.workspaces), + submenu: [], + }, { label: intl.formatMessage(menuItems.window), role: 'window', @@ -499,7 +517,9 @@ export default class FranzMenu { } _build() { - const serviceTpl = Object.assign([], this.serviceTpl); // need to clone object so we don't modify computed (cached) object + // need to clone object so we don't modify computed (cached) object + const serviceTpl = Object.assign([], this.serviceTpl); + const workspacesMenu = Object.assign([], this.workspacesMenu); if (window.franz === undefined) { return; @@ -632,7 +652,7 @@ export default class FranzMenu { }, ); - tpl[4].submenu.unshift(about, { + tpl[5].submenu.unshift(about, { type: 'separator', }); } else { @@ -678,6 +698,8 @@ export default class FranzMenu { tpl[3].submenu = serviceTpl; } + tpl[4].submenu = workspacesMenu; + this.currentTemplate = tpl; const menu = Menu.buildFromTemplate(tpl); Menu.setApplicationMenu(menu); @@ -701,6 +723,51 @@ export default class FranzMenu { return []; } + @computed get workspacesMenu() { + const { workspaces, activeWorkspace } = workspacesState; + const { intl } = window.franz; + const menu = []; + + // Add new workspace item: + menu.push({ + label: intl.formatMessage(menuItems.addNewWorkspace), + accelerator: `${cmdKey}+Shift+N`, + click: () => { + this.actions.ui.openSettings({ path: 'workspaces' }); + }, + enabled: this.stores.user.isLoggedIn, + }, { + type: 'separator', + }); + + // Default workspace + menu.push({ + label: intl.formatMessage(menuItems.defaultWorkspace), + accelerator: `${cmdKey}+Alt+1`, + type: 'radio', + checked: !activeWorkspace, + click: () => { + workspaceActions.deactivate(); + }, + }); + + // Workspace items + if (this.stores.user.isLoggedIn) { + workspaces.forEach((workspace, i) => menu.push({ + label: workspace.name, + accelerator: i < 9 ? `${cmdKey}+Alt+${i + 2}` : null, + type: 'radio', + checked: activeWorkspace ? workspace.id === activeWorkspace.id : false, + click: () => { + workspaceActions.activate({ workspace }); + }, + })); + } + + console.log(menu); + return menu; + } + _getServiceName(service) { if (service.name) { return service.name; diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index c63bef196..a86db8103 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -2,7 +2,7 @@ import { action, reaction, computed, - observable, + observable, runInAction, } from 'mobx'; import { debounce, remove } from 'lodash'; import ms from 'ms'; @@ -12,6 +12,8 @@ import Request from './lib/Request'; import CachedRequest from './lib/CachedRequest'; import { matchRoute } from '../helpers/routing-helpers'; import { gaEvent } from '../lib/analytics'; +import { workspacesState } from '../features/workspaces/state'; +import { filterServicesByActiveWorkspace, getActiveWorkspaceServices } from '../features/workspaces'; const debug = require('debug')('Franz:ServiceStore'); @@ -98,7 +100,6 @@ export default class ServicesStore extends Store { return observable(services.slice().slice().sort((a, b) => a.order - b.order)); } } - return []; } @@ -107,13 +108,16 @@ export default class ServicesStore extends Store { } @computed get allDisplayed() { - return this.stores.settings.all.app.showDisabledServices ? this.all : this.enabled; + const services = this.stores.settings.all.app.showDisabledServices ? this.all : this.enabled; + return filterServicesByActiveWorkspace(services); } // This is just used to avoid unnecessary rerendering of resource-heavy webviews @computed get allDisplayedUnordered() { + const { showDisabledServices } = this.stores.settings.all.app; const services = this.allServicesRequest.execute().result || []; - return this.stores.settings.all.app.showDisabledServices ? services : services.filter(service => service.isEnabled); + const filteredServices = showDisabledServices ? services : services.filter(service => service.isEnabled); + return getActiveWorkspaceServices(filteredServices); } @computed get filtered() { -- cgit v1.2.3-54-g00ecf From 1947cad07e0d9c32ffb874bdea482e7ff037888b Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Fri, 1 Mar 2019 14:27:40 +0100 Subject: fix eslint issues --- src/features/workspaces/index.js | 6 +++--- src/stores/ServicesStore.js | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js index 8091f49fc..79c9b8ac9 100644 --- a/src/features/workspaces/index.js +++ b/src/features/workspaces/index.js @@ -15,9 +15,9 @@ export const filterServicesByActiveWorkspace = (services) => { return services; }; -export const getActiveWorkspaceServices = (services) => { - return filterServicesByActiveWorkspace(services); -}; +export const getActiveWorkspaceServices = services => ( + filterServicesByActiveWorkspace(services) +); export default function initWorkspaces(stores, actions) { const { features, user } = stores; diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index a86db8103..da4b19c0d 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -2,7 +2,7 @@ import { action, reaction, computed, - observable, runInAction, + observable, } from 'mobx'; import { debounce, remove } from 'lodash'; import ms from 'ms'; @@ -12,7 +12,6 @@ import Request from './lib/Request'; import CachedRequest from './lib/CachedRequest'; import { matchRoute } from '../helpers/routing-helpers'; import { gaEvent } from '../lib/analytics'; -import { workspacesState } from '../features/workspaces/state'; import { filterServicesByActiveWorkspace, getActiveWorkspaceServices } from '../features/workspaces'; const debug = require('debug')('Franz:ServiceStore'); -- cgit v1.2.3-54-g00ecf From 2c67a242c660b925a5c97d7844db1e43347ab6ba Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Mon, 4 Mar 2019 13:05:55 +0100 Subject: remove dev logs --- src/features/workspaces/index.js | 1 - src/lib/Menu.js | 1 - 2 files changed, 2 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js index 79c9b8ac9..26cadea64 100644 --- a/src/features/workspaces/index.js +++ b/src/features/workspaces/index.js @@ -60,7 +60,6 @@ export default function initWorkspaces(stores, actions) { const workspaceServices = filterServicesByActiveWorkspace(services); const isActiveServiceInWorkspace = workspaceServices.includes(activeService); if (!isActiveServiceInWorkspace) { - console.log(workspaceServices[0].id); actions.service.setActive({ serviceId: workspaceServices[0].id }); } } diff --git a/src/lib/Menu.js b/src/lib/Menu.js index 1560dd285..c572bbb70 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js @@ -764,7 +764,6 @@ export default class FranzMenu { })); } - console.log(menu); return menu; } -- cgit v1.2.3-54-g00ecf From cf9d7a30fed4fe50c346e652073464b07277a81e Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Fri, 8 Mar 2019 14:48:46 +0100 Subject: detach service when underlying webview unmounts --- src/actions/service.js | 4 + src/components/services/content/ServiceView.js | 136 ++++++++++++++++++++ src/components/services/content/ServiceWebview.js | 145 ++++------------------ src/components/services/content/Services.js | 7 +- src/containers/layout/AppLayoutContainer.js | 3 + src/stores/ServicesStore.js | 6 + 6 files changed, 179 insertions(+), 122 deletions(-) create mode 100644 src/components/services/content/ServiceView.js (limited to 'src') diff --git a/src/actions/service.js b/src/actions/service.js index 5d483b12a..ceaabc31e 100644 --- a/src/actions/service.js +++ b/src/actions/service.js @@ -1,4 +1,5 @@ import PropTypes from 'prop-types'; +import ServiceModel from '../models/Service'; export default { setActive: { @@ -36,6 +37,9 @@ export default { serviceId: PropTypes.string.isRequired, webview: PropTypes.object.isRequired, }, + detachService: { + service: PropTypes.instanceOf(ServiceModel).isRequired, + }, focusService: { serviceId: PropTypes.string.isRequired, }, diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js new file mode 100644 index 000000000..5afc54f9d --- /dev/null +++ b/src/components/services/content/ServiceView.js @@ -0,0 +1,136 @@ +import React, { Component, Fragment } from 'react'; +import PropTypes from 'prop-types'; +import { autorun } from 'mobx'; +import { observer } from 'mobx-react'; +import classnames from 'classnames'; + +import ServiceModel from '../../../models/Service'; +import StatusBarTargetUrl from '../../ui/StatusBarTargetUrl'; +import WebviewLoader from '../../ui/WebviewLoader'; +import WebviewCrashHandler from './WebviewCrashHandler'; +import WebviewErrorHandler from './ErrorHandlers/WebviewErrorHandler'; +import ServiceDisabled from './ServiceDisabled'; +import ServiceWebview from './ServiceWebview'; + +export default @observer class ServiceView extends Component { + static propTypes = { + service: PropTypes.instanceOf(ServiceModel).isRequired, + setWebviewReference: PropTypes.func.isRequired, + detachService: PropTypes.func.isRequired, + reload: PropTypes.func.isRequired, + edit: PropTypes.func.isRequired, + enable: PropTypes.func.isRequired, + isActive: PropTypes.bool, + }; + + static defaultProps = { + isActive: false, + }; + + state = { + forceRepaint: false, + targetUrl: '', + statusBarVisible: false, + }; + + autorunDisposer = null; + + componentDidMount() { + this.autorunDisposer = autorun(() => { + if (this.props.service.isActive) { + this.setState({ forceRepaint: true }); + setTimeout(() => { + this.setState({ forceRepaint: false }); + }, 100); + } + }); + } + + componentWillUnmount() { + this.autorunDisposer(); + } + + updateTargetUrl = (event) => { + let visible = true; + if (event.url === '' || event.url === '#') { + visible = false; + } + this.setState({ + targetUrl: event.url, + statusBarVisible: visible, + }); + }; + + render() { + const { + detachService, + service, + setWebviewReference, + reload, + edit, + enable, + } = this.props; + + const webviewClasses = classnames({ + services__webview: true, + 'services__webview-wrapper': true, + 'is-active': service.isActive, + 'services__webview--force-repaint': this.state.forceRepaint, + }); + + let statusBar = null; + if (this.state.statusBarVisible) { + statusBar = ( + + ); + } + + return ( +
+ {service.isActive && service.isEnabled && ( + + {service.hasCrashed && ( + + )} + {service.isEnabled && service.isLoading && service.isFirstLoad && ( + + )} + {service.isError && ( + + )} + + )} + {!service.isEnabled ? ( + + {service.isActive && ( + + )} + + ) : ( + + )} + {statusBar} +
+ ); + } +} diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index bb577e4cc..7252c695f 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js @@ -1,145 +1,50 @@ -import React, { Component, Fragment } from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { autorun } from 'mobx'; import { observer } from 'mobx-react'; -import Webview from 'react-electron-web-view'; -import classnames from 'classnames'; +import ElectronWebView from 'react-electron-web-view'; import ServiceModel from '../../../models/Service'; -import StatusBarTargetUrl from '../../ui/StatusBarTargetUrl'; -import WebviewLoader from '../../ui/WebviewLoader'; -import WebviewCrashHandler from './WebviewCrashHandler'; -import WebviewErrorHandler from './ErrorHandlers/WebviewErrorHandler'; -import ServiceDisabled from './ServiceDisabled'; -export default @observer class ServiceWebview extends Component { +@observer +class ServiceWebview extends Component { static propTypes = { service: PropTypes.instanceOf(ServiceModel).isRequired, setWebviewReference: PropTypes.func.isRequired, - reload: PropTypes.func.isRequired, - edit: PropTypes.func.isRequired, - enable: PropTypes.func.isRequired, - isActive: PropTypes.bool, + detachService: PropTypes.func.isRequired, }; - static defaultProps = { - isActive: false, - }; - - state = { - forceRepaint: false, - targetUrl: '', - statusBarVisible: false, - }; - - autorunDisposer = null; - webview = null; - componentDidMount() { - this.autorunDisposer = autorun(() => { - if (this.props.service.isActive) { - this.setState({ forceRepaint: true }); - setTimeout(() => { - this.setState({ forceRepaint: false }); - }, 100); - } - }); - } - componentWillUnmount() { - this.autorunDisposer(); - } - - updateTargetUrl = (event) => { - let visible = true; - if (event.url === '' || event.url === '#') { - visible = false; - } - this.setState({ - targetUrl: event.url, - statusBarVisible: visible, - }); + const { service, detachService } = this.props; + detachService({ service }); } render() { const { service, setWebviewReference, - reload, - edit, - enable, } = this.props; - const webviewClasses = classnames({ - services__webview: true, - 'services__webview-wrapper': true, - 'is-active': service.isActive, - 'services__webview--force-repaint': this.state.forceRepaint, - }); - - let statusBar = null; - if (this.state.statusBarVisible) { - statusBar = ( - - ); - } - return ( -
- {service.isActive && service.isEnabled && ( - - {service.hasCrashed && ( - - )} - {service.isEnabled && service.isLoading && service.isFirstLoad && ( - - )} - {service.isError && ( - - )} - - )} - {!service.isEnabled ? ( - - {service.isActive && ( - - )} - - ) : ( - { this.webview = element; }} - autosize - src={service.url} - preload="./webview/recipe.js" - partition={`persist:service-${service.id}`} - onDidAttach={() => setWebviewReference({ - serviceId: service.id, - webview: this.webview.view, - })} - onUpdateTargetUrl={this.updateTargetUrl} - useragent={service.userAgent} - allowpopups - /> - )} - {statusBar} -
+ { this.webview = webview; }} + autosize + src={service.url} + preload="./webview/recipe.js" + partition={`persist:service-${service.id}`} + onDidAttach={() => { + setWebviewReference({ + serviceId: service.id, + webview: this.webview.view, + }); + }} + onUpdateTargetUrl={this.updateTargetUrl} + useragent={service.userAgent} + allowpopups + /> ); } } + +export default ServiceWebview; diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js index 54f16ba12..8f8c38a11 100644 --- a/src/components/services/content/Services.js +++ b/src/components/services/content/Services.js @@ -4,7 +4,7 @@ import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; import { Link } from 'react-router'; import { defineMessages, intlShape } from 'react-intl'; -import Webview from './ServiceWebview'; +import ServiceView from './ServiceView'; import Appear from '../../ui/effects/Appear'; const messages = defineMessages({ @@ -22,6 +22,7 @@ export default @observer class Services extends Component { static propTypes = { services: MobxPropTypes.arrayOrObservableArray, setWebviewReference: PropTypes.func.isRequired, + detachService: PropTypes.func.isRequired, handleIPCMessage: PropTypes.func.isRequired, openWindow: PropTypes.func.isRequired, reload: PropTypes.func.isRequired, @@ -42,6 +43,7 @@ export default @observer class Services extends Component { services, handleIPCMessage, setWebviewReference, + detachService, openWindow, reload, openSettings, @@ -71,11 +73,12 @@ export default @observer class Services extends Component { )} {services.map(service => ( - reload({ serviceId: service.id })} edit={() => openSettings({ path: `services/edit/${service.id}` })} diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index 749912c59..5a05ce431 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js @@ -42,6 +42,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e setActive, handleIPCMessage, setWebviewReference, + detachService, openWindow, reorder, reload, @@ -105,6 +106,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e services={services.allDisplayedUnordered} handleIPCMessage={handleIPCMessage} setWebviewReference={setWebviewReference} + detachService={detachService} openWindow={openWindow} reload={reload} openSettings={openSettings} @@ -160,6 +162,7 @@ AppLayoutContainer.wrappedComponent.propTypes = { toggleAudio: PropTypes.func.isRequired, handleIPCMessage: PropTypes.func.isRequired, setWebviewReference: PropTypes.func.isRequired, + detachService: PropTypes.func.isRequired, openWindow: PropTypes.func.isRequired, reloadUpdatedServices: PropTypes.func.isRequired, updateService: PropTypes.func.isRequired, diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index c63bef196..69e616f0c 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -44,6 +44,7 @@ export default class ServicesStore extends Store { this.actions.service.deleteService.listen(this._deleteService.bind(this)); this.actions.service.clearCache.listen(this._clearCache.bind(this)); this.actions.service.setWebviewReference.listen(this._setWebviewReference.bind(this)); + this.actions.service.detachService.listen(this._detachService.bind(this)); this.actions.service.focusService.listen(this._focusService.bind(this)); this.actions.service.focusActiveService.listen(this._focusActiveService.bind(this)); this.actions.service.toggleService.listen(this._toggleService.bind(this)); @@ -341,6 +342,11 @@ export default class ServicesStore extends Store { service.isAttached = true; } + @action _detachService({ service }) { + service.webview = null; + service.isAttached = false; + } + @action _focusService({ serviceId }) { const service = this.one(serviceId); -- cgit v1.2.3-54-g00ecf From 87acf96d42cc18bfe3b2ab8c86842d565eaec712 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 14 Mar 2019 15:18:50 +0100 Subject: fixes unnecessary scrollbars issue on signup form --- src/styles/auth.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/styles/auth.scss b/src/styles/auth.scss index 817801982..0a075036a 100644 --- a/src/styles/auth.scss +++ b/src/styles/auth.scss @@ -107,7 +107,7 @@ &__scroll-container { max-height: 100vh; padding: 80px 0; - overflow: scroll; + overflow: auto; width: 100%; } -- cgit v1.2.3-54-g00ecf From f8ecdadfbaf656a827ea5406ce44e01b80fabd4b Mon Sep 17 00:00:00 2001 From: FranzBot Date: Sun, 17 Mar 2019 21:28:03 +0000 Subject: Automatic i18n update (i18n.meetfranz.com) --- src/i18n/locales/ca.json | 15 ++++++--------- src/i18n/locales/cs.json | 15 ++++++--------- src/i18n/locales/de.json | 33 +++++++++++++++------------------ src/i18n/locales/el.json | 15 ++++++--------- src/i18n/locales/es.json | 19 ++++++++----------- src/i18n/locales/fr.json | 33 +++++++++++++++------------------ src/i18n/locales/ga.json | 15 ++++++--------- src/i18n/locales/hr.json | 15 ++++++--------- src/i18n/locales/hu.json | 15 ++++++--------- src/i18n/locales/id.json | 15 ++++++--------- src/i18n/locales/it.json | 15 ++++++--------- src/i18n/locales/ja.json | 15 ++++++--------- src/i18n/locales/ka.json | 15 ++++++--------- src/i18n/locales/nl-BE.json | 15 ++++++--------- src/i18n/locales/nl.json | 15 ++++++--------- src/i18n/locales/pl.json | 15 ++++++--------- src/i18n/locales/pt-BR.json | 33 +++++++++++++++------------------ src/i18n/locales/pt.json | 15 ++++++--------- src/i18n/locales/ru.json | 17 +++++++---------- src/i18n/locales/sk.json | 15 ++++++--------- src/i18n/locales/sr.json | 15 ++++++--------- src/i18n/locales/tr.json | 39 ++++++++++++++++++--------------------- src/i18n/locales/uk.json | 15 ++++++--------- src/i18n/locales/zh-TW.json | 15 ++++++--------- 24 files changed, 186 insertions(+), 258 deletions(-) (limited to 'src') diff --git a/src/i18n/locales/ca.json b/src/i18n/locales/ca.json index f374fddd9..dabe4ba16 100644 --- a/src/i18n/locales/ca.json +++ b/src/i18n/locales/ca.json @@ -70,7 +70,9 @@ "menu.help.support" : "Suport", "menu.help.tos" : "Condicions del Servei", "menu.services" : "Serveis", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Afegeix un servei...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Visualitza", "menu.view.enterFullScreen" : "Inicia la pantalla completa", "menu.view.exitFullScreen" : "Surt de pantalla completa", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Descarregar", "settings.account.manageSubscription.label" : "Gestioneu la vostra subscripció", "settings.account.successInfo" : "S'han desat els canvis", + "settings.account.tryReloadServices" : "Torna a provar-ho", "settings.account.tryReloadUserInfoRequest" : "Torna a provar-ho", "settings.account.userInfoRequestFailed" : "No s'ha pogut carregar la informació de l'usuari", "settings.app.buttonClearAllCache" : "Buida la memòria cau", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Inclou versions beta", "settings.app.form.darkMode" : "Uneix-te al Cantó Fosc", "settings.app.form.enableGPUAcceleration" : "Activar acceleració GPU", - "settings.app.form.enableMenuBar" : "Mostra Franz a la barra de menú", "settings.app.form.enableSpellchecking" : "Habilita la comprobació ortogràfica", "settings.app.form.enableSystemTray" : "Mostra Franz a la safata del sistema", - "settings.app.form.hideDockIcon" : "Oculta la icona de Franz al Dock", "settings.app.form.language" : "Idioma", "settings.app.form.minimizeToSystemTray" : "Minimitza Franz a la safata del sistema", "settings.app.form.runInBackground" : "Mantén a Franz en segon pla en tancar la finestra", "settings.app.form.showDisabledServices" : "Mostra les pestanyes dels serveis desactivats", "settings.app.form.showMessagesBadgesWhenMuted" : "Mostra la insígnia de missatges no llegits quan les notificacions estiguin desactivades", - "settings.app.form.spellcheckerLanguage" : "Corrector ortogràfic", "settings.app.headline" : "Configuració", "settings.app.headlineAdvanced" : "Avançat", "settings.app.headlineAppearance" : "Aparença", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Siusplau, reinicieu el Franz després de canviar els ajustaments de proxy", "settings.service.form.proxy.user" : "Usuari (opcional)", "settings.service.form.saveButton" : "Desa el servei", - "settings.service.form.spellcheckerLanguage" : "Idioma del corrector", - "settings.service.form.spellcheckerLanguage.default" : "Utilitzar el predeterminat del sistema ({default})", "settings.service.form.tabHosted" : "Allotjat", "settings.service.form.tabOnPremise" : "Allotjat per si mateix ⭐️", "settings.service.form.team" : "Equip", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Descobrir serveis", "settings.services.headline" : "Els vostres serveis", "settings.services.noServicesAdded" : "Encara no heu afegit cap servei.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "El servei està desactivat", "settings.services.tooltip.isMuted" : "Tots els sons estan desactivats", "settings.services.tooltip.notificationsDisabled" : "Les notificacions estan desactivades", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Residents d'EU: es poden aplicar impostos locals", "subscription.features.ads" : "Sense anuncis, mai!", "subscription.features.comingSoon" : "properament", - "subscription.features.encryptedSync" : "Sincronització de sessió xifrada", "subscription.features.noInterruptions" : "Sense retards ni molestes actualitzacions de llicències ", - "subscription.features.onpremise" : "Afegiu serveis en premissa\/allotjats com HipChat", "subscription.features.onpremise.mattermost" : "Afegir serveis allotjats com Mattermost", "subscription.features.proxy" : "Suport de Proxy per a serveis", "subscription.features.spellchecker" : "Suport per corrector ortogràfic", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Recarrega", "validation.email" : "{field} no es vàlid", "validation.minLength" : "{field} ha de ser al menys {length} caràcters de llargada", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} es requerit", "validation.url" : "{field} es una URL no vàlida", "welcome.loginButton" : "Inicia sessió al teu compte", - "welcome.signupButton" : "Crea un compte gratuït", - "welcome.slogan" : "Crea un compte gratuït" + "welcome.signupButton" : "Crea un compte gratuït" } diff --git a/src/i18n/locales/cs.json b/src/i18n/locales/cs.json index 3fc6318a2..f0b0b7c81 100644 --- a/src/i18n/locales/cs.json +++ b/src/i18n/locales/cs.json @@ -70,7 +70,9 @@ "menu.help.support" : "Podpora", "menu.help.tos" : "Podmínky použití", "menu.services" : "Služby", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Přidat novou službu...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Zobrazení", "menu.view.enterFullScreen" : "Spustit režim celé obrazovky", "menu.view.exitFullScreen" : "Ukončit celoobrazovkový režim", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Stáhnout", "settings.account.manageSubscription.label" : "Spravovat vaše předplatné", "settings.account.successInfo" : "Vaše změny byly uloženy", + "settings.account.tryReloadServices" : "Zkusit opět", "settings.account.tryReloadUserInfoRequest" : "Zkusit opět", "settings.account.userInfoRequestFailed" : "Nelze načíst informace o uživateli.", "settings.app.buttonClearAllCache" : "Vyprázdnit mezipaměti", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Zahrnout beta verze", "settings.app.form.darkMode" : "Připoj se k Temné straně", "settings.app.form.enableGPUAcceleration" : "Aktivovat GPU zrychlení", - "settings.app.form.enableMenuBar" : "Zobraz Franz v Menu nabídce", "settings.app.form.enableSpellchecking" : "Zapnout kontrolu pravopisu", "settings.app.form.enableSystemTray" : "Zobrazit Franz v systémové liště", - "settings.app.form.hideDockIcon" : "Schovej ikonu Franz v Docku", "settings.app.form.language" : "Jazyk", "settings.app.form.minimizeToSystemTray" : "Minimalizovat Franz do systémové lišty", "settings.app.form.runInBackground" : "Ponechat Franze v pozadí při zavírání okna", "settings.app.form.showDisabledServices" : "Zobrazit záložky vypnutých služeb", "settings.app.form.showMessagesBadgesWhenMuted" : "Zobrazit odznak pro nepřečtené zprávy když jsou upozornění vypnutá", - "settings.app.form.spellcheckerLanguage" : "Oprava překlepů jazyka", "settings.app.headline" : "Nastavení", "settings.app.headlineAdvanced" : "Pokročilé", "settings.app.headlineAppearance" : "Vzhled", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Please restart Franz after changing proxy Settings.", "settings.service.form.proxy.user" : "User (optional)", "settings.service.form.saveButton" : "Uložit službu", - "settings.service.form.spellcheckerLanguage" : "Spell checking Language", - "settings.service.form.spellcheckerLanguage.default" : "Use System Default ({default})", "settings.service.form.tabHosted" : "Hostováno", "settings.service.form.tabOnPremise" : "Samostatně hostované ⭐️", "settings.service.form.team" : "Tým", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Objevte služby", "settings.services.headline" : "Vaše služby", "settings.services.noServicesAdded" : "Doposud jste nepřidali žádné služby.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Služba je zakázána", "settings.services.tooltip.isMuted" : "Všechny zvuky jsou ztišeny", "settings.services.tooltip.notificationsDisabled" : "Oznámení jsou zakázána", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Pro obyvatelé EU: mohou být aplikovány lokální daně", "subscription.features.ads" : "Žádné reklamy, nikdy!", "subscription.features.comingSoon" : "již brzy", - "subscription.features.encryptedSync" : "Šifrovaná synchronizace relací", "subscription.features.noInterruptions" : "No app delays & nagging to upgrade license", - "subscription.features.onpremise" : "Přidat hostované služby jako HipChat", "subscription.features.onpremise.mattermost" : "Add on-premise\/hosted services like Mattermost", "subscription.features.proxy" : "Proxy support for services", "subscription.features.spellchecker" : "Support for spellchecker", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Obnovit", "validation.email" : "{field} není validní", "validation.minLength" : "{field} musí být alespoň {length} znaků dlouhé", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} je povinné", "validation.url" : "{field} není validní URL", "welcome.loginButton" : "Přihlášení do vašeho účtu", - "welcome.signupButton" : "Vytvořit účet zdarma", - "welcome.slogan" : "Zprávy, které pracují pro vás" + "welcome.signupButton" : "Vytvořit účet zdarma" } diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 13b8d12fc..adb466e18 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -4,18 +4,18 @@ "feature.delayApp.action" : "Upgrade deinen Account", "feature.delayApp.headline" : "Erspare dir das Warten mit einer Franz Supporter Lizenz", "feature.delayApp.text" : "Es geht in {seconds} Sekunden weiter.", - "feature.shareFranz.action.email" : "Send as email", - "feature.shareFranz.action.facebook" : "Share on Facebook", - "feature.shareFranz.action.twitter" : "Share on Twitter", - "feature.shareFranz.headline" : "Franz is better together!", - "feature.shareFranz.shareText.email" : "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com", - "feature.shareFranz.shareText.twitter" : "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com \/cc @MeetFranz", - "feature.shareFranz.text" : "Tell your friends and colleagues how awesome Franz is and help us to spread the word.", + "feature.shareFranz.action.email" : "Als E-Mail senden", + "feature.shareFranz.action.facebook" : "Auf Facebook teilen", + "feature.shareFranz.action.twitter" : "Auf Twitter teilen", + "feature.shareFranz.headline" : "Gemeinsam ist Franz noch besser!", + "feature.shareFranz.shareText.email" : "Ich verwende Franz! Hol dir jetzt die kostenlose App für WhatsApp, Messenger, Slack, Skype und viele mehr auf www.meetfranz.com", + "feature.shareFranz.shareText.twitter" : "Ich verwende Franz mit {count} Diensten! Hol dir jetzt die kostenlose App für WhatsApp, Messenger, Slack, Skype und mehr auf www.meetfranz.com \/cc @MeetFranz", + "feature.shareFranz.text" : "Bitte erzähle deinen Freunden und Kollegen wie toll du Franz findest.", "global.api.unhealthy" : "Verbindung mit dem Franz Online Service fehlgeschlagen", "global.notConnectedToTheInternet" : "Du bist nicht mit dem Internet verbunden.", "global.spellchecker.useDefault" : "Standard benutzen ({default})", - "global.spellchecking.autodetect" : "Detect language automatically", - "global.spellchecking.autodetect.short" : "Automatic", + "global.spellchecking.autodetect" : "Sprache automatisch erkennen", + "global.spellchecking.autodetect.short" : "Automatisch", "global.spellchecking.language" : "Sprache für Rechtschreibprüfung", "import.headline" : "Deine Franz 4 Dienste importieren", "import.notSupportedHeadline" : "Dienste, die noch nicht von Franz 5 unterstützt werden", @@ -70,7 +70,9 @@ "menu.help.support" : "Hilfe", "menu.help.tos" : "Nutzungsbedingungen", "menu.services" : "Dienste", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Dienst hinzufügen", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Darstellung", "menu.view.enterFullScreen" : "Vollbildmodus", "menu.view.exitFullScreen" : "Vollbildmodus aus", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Herunterladen", "settings.account.manageSubscription.label" : "Dein Abonnement verwalten", "settings.account.successInfo" : "Deine Änderungen wurden gespeichert", + "settings.account.tryReloadServices" : "Erneut versuchen", "settings.account.tryReloadUserInfoRequest" : "Erneut versuchen", "settings.account.userInfoRequestFailed" : "Benutzerinformationen konnten nicht geladen werden", "settings.app.buttonClearAllCache" : "Cache leeren", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Beta-Versionen einbeziehen", "settings.app.form.darkMode" : "Die dunkle Seite erwartet dich (Dark Mode)", "settings.app.form.enableGPUAcceleration" : "Hardwarebeschleunigung aktivieren", - "settings.app.form.enableMenuBar" : "Franz in Menüleiste anzeigen", "settings.app.form.enableSpellchecking" : "Rechtschreibprüfung aktivieren", "settings.app.form.enableSystemTray" : "Franz im Infobereich anzeigen", - "settings.app.form.hideDockIcon" : "Franz Icon im Dock ausblenden", "settings.app.form.language" : "Sprache", "settings.app.form.minimizeToSystemTray" : "Franz in den Infobereich minimieren", "settings.app.form.runInBackground" : "Franz im Hintergrund behalten, wenn das Fenster geschlossen wird", "settings.app.form.showDisabledServices" : "Deaktivierte Services-Tabs anzeigen", "settings.app.form.showMessagesBadgesWhenMuted" : "Ungelesene Nachrichten zeigen, wenn die Benachrichtigungen deaktiviert sind", - "settings.app.form.spellcheckerLanguage" : "Sprache für Rechtschreibprüfung", "settings.app.headline" : "Einstellungen", "settings.app.headlineAdvanced" : "Erweitert", "settings.app.headlineAppearance" : "Darstellung", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Bitte starte Franz nach dem Ändern der Proxy Einstellungen neu.", "settings.service.form.proxy.user" : "Benutzer (optional)", "settings.service.form.saveButton" : "Dienst speichern", - "settings.service.form.spellcheckerLanguage" : "Sprache für Rechtschreibprüfung", - "settings.service.form.spellcheckerLanguage.default" : "Standard benutzen ({default})", "settings.service.form.tabHosted" : "Gehostet", "settings.service.form.tabOnPremise" : "Selbst gehostet ⭐️", "settings.service.form.team" : "Team", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Dienste entdecken", "settings.services.headline" : "Deine Dienste", "settings.services.noServicesAdded" : "Du hast noch keine Dienste hinzugefügt.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Dienst ist deaktiviert", "settings.services.tooltip.isMuted" : "Alle Töne sind deaktiviert", "settings.services.tooltip.notificationsDisabled" : "Benachrichtigungen deaktiviert", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Preise sind exklusive Steuern.", "subscription.features.ads" : "Werbefrei auf Lebenszeit!", "subscription.features.comingSoon" : "folgt bald", - "subscription.features.encryptedSync" : "Verschlüsselte Sitzungs-Synchronisation", "subscription.features.noInterruptions" : "Keine Wartezeiten um Franz zu verwenden", - "subscription.features.onpremise" : "Integration von gehosteten Diensten, wie HipChat", "subscription.features.onpremise.mattermost" : "Integration von gehosteten Diensten, wie Mattermost", "subscription.features.proxy" : "Proxy Support für Dienste", "subscription.features.spellchecker" : "Unterstützung für Rechtschreibprüfung", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Neuladen", "validation.email" : "{field} ist ungültig", "validation.minLength" : "{field} muss mindestens {length} Zeichen enthalten", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} wird benötigt", "validation.url" : "{field} ist keine gültige URL", "welcome.loginButton" : "Bei Franz einloggen", - "welcome.signupButton" : "Kostenloses Konto erstellen", - "welcome.slogan" : "Kommunikation, die für Dich funktioniert" + "welcome.signupButton" : "Kostenloses Konto erstellen" } diff --git a/src/i18n/locales/el.json b/src/i18n/locales/el.json index 9639ec5f7..626abfddd 100644 --- a/src/i18n/locales/el.json +++ b/src/i18n/locales/el.json @@ -70,7 +70,9 @@ "menu.help.support" : "Υποστήριξη", "menu.help.tos" : "Όροι Χρήσης", "menu.services" : "Υπηρεσίες", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Νέα Υπηρεσία", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Προβολή", "menu.view.enterFullScreen" : "Πλήρης Οθόνη", "menu.view.exitFullScreen" : "Έξοδος από πλήρη οθόνη", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Λήψη", "settings.account.manageSubscription.label" : "Διαχείριση της συνδρομής σας", "settings.account.successInfo" : "Οι αλλαγές σας έχουν αποθηκευτεί", + "settings.account.tryReloadServices" : "Δοκιμάστε ξανά", "settings.account.tryReloadUserInfoRequest" : "Δοκιμάστε ξανά", "settings.account.userInfoRequestFailed" : "Δεν ήταν δυνατή η φόρτωση πληροφοριών χρήστη", "settings.app.buttonClearAllCache" : "Καθαρισμός λανθάνουσας μνήμης", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Συμπεριλάβετε εκδόσεις beta", "settings.app.form.darkMode" : "Join the Dark Side", "settings.app.form.enableGPUAcceleration" : "Ενεργοποιήση Ενίσχυσης GPU ", - "settings.app.form.enableMenuBar" : "Εμφάνιση Γραμμής Μενού Franz", "settings.app.form.enableSpellchecking" : "Ενεργοποίηση ορθογραφικού ελέγχου", "settings.app.form.enableSystemTray" : "Εμφάνιση του Franz στη γραμμή ειδοποιήσεων", - "settings.app.form.hideDockIcon" : "Απόκρυψη εικονιδίου Franz", "settings.app.form.language" : "Γλώσσα", "settings.app.form.minimizeToSystemTray" : "Ελαχιστοποίηση του Franz στη γραμμή ειδοποιήσεων", "settings.app.form.runInBackground" : "Κρατήστε το Franz στο παρασκήνιο κατά το κλείσιμο του παραθύρου", "settings.app.form.showDisabledServices" : "Προβολή καρτελών των απενεργοποιημένων υπηρεσιών", "settings.app.form.showMessagesBadgesWhenMuted" : "Προβολή του εικονιδίου μη αναγνωσμένου μηνύματος όταν οι ειδοποιήσεις είναι απενεργοποιημένες", - "settings.app.form.spellcheckerLanguage" : "Spell checking language", "settings.app.headline" : "Ρυθμίσεις", "settings.app.headlineAdvanced" : "Για προχωρημένους", "settings.app.headlineAppearance" : "Εμφάνιση", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Please restart Franz after changing proxy Settings.", "settings.service.form.proxy.user" : "User (optional)", "settings.service.form.saveButton" : "Αποθήκευση υπηρεσίας", - "settings.service.form.spellcheckerLanguage" : "Spell checking Language", - "settings.service.form.spellcheckerLanguage.default" : "Use System Default ({default})", "settings.service.form.tabHosted" : "Φιλοξενείται", "settings.service.form.tabOnPremise" : "Αυτο-φιλοξενείται ⭐️", "settings.service.form.team" : "Ομάδα", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Ανακαλύψτε υπηρεσίες", "settings.services.headline" : "Οι υπηρεσίες σας", "settings.services.noServicesAdded" : "Δεν έχετε προσθέσει ακόμα υπηρεσίες.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Η υπηρεσία είναι απενεργοποιημένη", "settings.services.tooltip.isMuted" : "Όλοι οι ήχοι είναι απενεργοποιημένοι", "settings.services.tooltip.notificationsDisabled" : "Οι ειδοποιήσεις είναι απενεργοποιημένες", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Πολίτες Ε.Ε.: Στις τιμές δεν περιλαμβάνονται τυχόν φόροι και άλλες τοπικές επιβαρύνσεις", "subscription.features.ads" : "Τέλος στις διαφημίσεις", "subscription.features.comingSoon" : "σύντομα", - "subscription.features.encryptedSync" : "Κρυπτογραφημένος συγχρονισμός περιόδου σύνδεσης", "subscription.features.noInterruptions" : "No app delays & nagging to upgrade license", - "subscription.features.onpremise" : "Add on-premise \/ hosted services όπως το HipChat", "subscription.features.onpremise.mattermost" : "Add on-premise\/hosted services like Mattermost", "subscription.features.proxy" : "Proxy support for services", "subscription.features.spellchecker" : "Support for spellchecker", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Επαναφόρτωση", "validation.email" : "{field} δεν είναι έγκυρο", "validation.minLength" : "{field} πρέπει να είναι τουλάχιστον {length} χαρακτήρες", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} είναι υποχρεωτικό", "validation.url" : "{field} δεν είναι έγκυρος σύνδεσμος URL", "welcome.loginButton" : "Σύνδεση στο λογαριασμό σας", - "welcome.signupButton" : "Δημιουργία δωρεάν λογαριασμού", - "welcome.slogan" : "Επικοινωνία που λειτουργεί για εσάς" + "welcome.signupButton" : "Δημιουργία δωρεάν λογαριασμού" } diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 3ac23d9a5..5c26b456c 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -5,8 +5,8 @@ "feature.delayApp.headline" : "Por favor, compra una Licencia de Soporte de Franz para saltar la espera", "feature.delayApp.text" : "Franz continuará en {seconds} segundos.", "feature.shareFranz.action.email" : "Send as email", - "feature.shareFranz.action.facebook" : "Share on Facebook", - "feature.shareFranz.action.twitter" : "Share on Twitter", + "feature.shareFranz.action.facebook" : "Compartir en Facebook", + "feature.shareFranz.action.twitter" : "Compartir en Twitter", "feature.shareFranz.headline" : "Franz is better together!", "feature.shareFranz.shareText.email" : "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com", "feature.shareFranz.shareText.twitter" : "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com \/cc @MeetFranz", @@ -70,7 +70,9 @@ "menu.help.support" : "Ayuda técnica", "menu.help.tos" : "Términos del Servicio", "menu.services" : "Servicios", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Añadir Nuevo Servicio...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Mostrar", "menu.view.enterFullScreen" : "Pasar a pantalla completa", "menu.view.exitFullScreen" : "Salir de Pantalla Completa", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Descargar", "settings.account.manageSubscription.label" : "Administra tu suscripción", "settings.account.successInfo" : "Tus cambios han sido guardados", + "settings.account.tryReloadServices" : "Intentar de nuevo", "settings.account.tryReloadUserInfoRequest" : "Intentar de nuevo", "settings.account.userInfoRequestFailed" : "No se pudo cargar la información de usuario", "settings.app.buttonClearAllCache" : "Limpiar caché", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Incluir versiones beta", "settings.app.form.darkMode" : "Únete al Lado Oscuro", "settings.app.form.enableGPUAcceleration" : "Habilitar aceleración de GPU", - "settings.app.form.enableMenuBar" : "Mostrar a Franz en la barra de menús", "settings.app.form.enableSpellchecking" : "Activar corrección ortográfica", "settings.app.form.enableSystemTray" : "Mostrar Franz en la bandeja del sistema", - "settings.app.form.hideDockIcon" : "Ocultar Icono de Franz en barra de herramientas", "settings.app.form.language" : "Idioma", "settings.app.form.minimizeToSystemTray" : "Minimizar Franz a la bandeja del sistema", "settings.app.form.runInBackground" : "Mantener Franz en segundo plano al cerrar la ventana", "settings.app.form.showDisabledServices" : "Mostrar pestañas de servicios desactivados", "settings.app.form.showMessagesBadgesWhenMuted" : "Mostrar la insignia de mensajes sin leer cuando las notificaciones están desactivadas", - "settings.app.form.spellcheckerLanguage" : "Corrector de ortografía", "settings.app.headline" : "Configuración", "settings.app.headlineAdvanced" : "Avanzado", "settings.app.headlineAppearance" : "Apariencia", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Por favor reinicie Franz despues de modificar los ajustes proxy.", "settings.service.form.proxy.user" : "Usuario (opcional)", "settings.service.form.saveButton" : "Guardar servicio", - "settings.service.form.spellcheckerLanguage" : "Marcar faltas de ortografía", - "settings.service.form.spellcheckerLanguage.default" : "Utilizar estándar del sistema ({default})", "settings.service.form.tabHosted" : "Alojado", "settings.service.form.tabOnPremise" : "Auto alojado ⭐️", "settings.service.form.team" : "Equipo", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Descubrir servicios", "settings.services.headline" : "Tus servicios", "settings.services.noServicesAdded" : "No has añadido ningún servicio aún.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "El servicio está desactivado", "settings.services.tooltip.isMuted" : "Todos los sonidos están silenciados", "settings.services.tooltip.notificationsDisabled" : "Las notificaciones están desactivadas", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Residentes de la UE: pueden aplicarse impuestos locales", "subscription.features.ads" : "¡Sin publicidad, para siempre!", "subscription.features.comingSoon" : "próximamente", - "subscription.features.encryptedSync" : "Sincronización de sesión encriptada", "subscription.features.noInterruptions" : "Sin retrasos en la app ni molestas actualizaciones de licencias", - "subscription.features.onpremise" : "Añade servicios locales\/autoalojados como HipChat", "subscription.features.onpremise.mattermost" : "Agregar servicios de almacenamiento como Mattermost", "subscription.features.proxy" : "Soporte Proxy para servicios", "subscription.features.spellchecker" : "Soporte para corrector de ortografía", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Recargar", "validation.email" : "{field} no es válido", "validation.minLength" : "{field} debería tener al menos {length} caracteres", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} es obligatorio", "validation.url" : "{field} no es una URL válida", "welcome.loginButton" : "Accede a tu cuenta", - "welcome.signupButton" : "Crear una cuenta gratuita", - "welcome.slogan" : "Mensajería que funciona para ti" + "welcome.signupButton" : "Crear una cuenta gratuita" } diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 8af875a3d..6f9d81713 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -4,18 +4,18 @@ "feature.delayApp.action" : "Obtenez une licence de Supporter Franz", "feature.delayApp.headline" : "Veuillez acheter une licence de Supporter Franz pour sauter le temps d'attente", "feature.delayApp.text" : "Franz reprendra dans {seconds} secondes.", - "feature.shareFranz.action.email" : "Send as email", - "feature.shareFranz.action.facebook" : "Share on Facebook", - "feature.shareFranz.action.twitter" : "Share on Twitter", - "feature.shareFranz.headline" : "Franz is better together!", - "feature.shareFranz.shareText.email" : "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com", - "feature.shareFranz.shareText.twitter" : "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com \/cc @MeetFranz", - "feature.shareFranz.text" : "Tell your friends and colleagues how awesome Franz is and help us to spread the word.", + "feature.shareFranz.action.email" : "Envoyer par mail", + "feature.shareFranz.action.facebook" : "Partager sur Facebook", + "feature.shareFranz.action.twitter" : "Partager sur Twitter", + "feature.shareFranz.headline" : "Franz est meilleur quand on est tous ensemble !", + "feature.shareFranz.shareText.email" : "J'ai ajouté {count} services à Franz ! Télécharger l'appli gratuite pour WhatsApp, Messenger, Skype et cie sur www.meetfranz.com", + "feature.shareFranz.shareText.twitter" : "J'ai ajouté {count} services à Franz ! Télécharger l'appli gratuite pour WhatsApp, Messenger, Skype et cie sur www.meetfranz.com \/cc @NeetFranz", + "feature.shareFranz.text" : "Dites à vos amis et collègues combien Franz est super et aidez nous à faire passer le mot.", "global.api.unhealthy" : "Impossible de se connecter aux services en ligne de Franz", "global.notConnectedToTheInternet" : "Vous n'êtes pas connecté à Internet.", "global.spellchecker.useDefault" : "Par défaut ({default})", - "global.spellchecking.autodetect" : "Detect language automatically", - "global.spellchecking.autodetect.short" : "Automatic", + "global.spellchecking.autodetect" : "Detecter automatiquement la langue", + "global.spellchecking.autodetect.short" : "Automatiquement", "global.spellchecking.language" : "Langue de la vérification orthographique", "import.headline" : "Importez vos services depuis la version 4 de Franz.", "import.notSupportedHeadline" : "Ces services ne sont pas encore supportés par Franz 5", @@ -70,7 +70,9 @@ "menu.help.support" : "Support", "menu.help.tos" : "Conditions d'utilisation", "menu.services" : "Services", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Ajouter un nouveau service...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Aperçu", "menu.view.enterFullScreen" : "Entrer en mode plein écran", "menu.view.exitFullScreen" : "Sortir du mode plein écran", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Télécharger", "settings.account.manageSubscription.label" : "Gérer votre abonnement", "settings.account.successInfo" : "Vos modifications ont été enregistrées", + "settings.account.tryReloadServices" : "Réessayer", "settings.account.tryReloadUserInfoRequest" : "Réessayer", "settings.account.userInfoRequestFailed" : "Impossible de charger les informations de l'utilisateur", "settings.app.buttonClearAllCache" : "Vider le cache", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Accepter les versions bêta", "settings.app.form.darkMode" : "Rejoins le côté obscur", "settings.app.form.enableGPUAcceleration" : "Activer l'accélération GPU", - "settings.app.form.enableMenuBar" : "Afficher Franz dans la barre des menus", "settings.app.form.enableSpellchecking" : "Activer la vérification orthographique", "settings.app.form.enableSystemTray" : "Afficher Franz dans la barre d'état système", - "settings.app.form.hideDockIcon" : "Masquer Franz dans le Dock", "settings.app.form.language" : "Langue", "settings.app.form.minimizeToSystemTray" : "Minimiser Franz dans la zone de notification", "settings.app.form.runInBackground" : "Garder Franz ouvert en arrière-plan à la fermeture de la fenêtre", "settings.app.form.showDisabledServices" : "Afficher les onglets des services désactivés", "settings.app.form.showMessagesBadgesWhenMuted" : "Afficher les badges de messages non lus quand les notifications sont désactivées.", - "settings.app.form.spellcheckerLanguage" : "Langue de la vérification orthographique", "settings.app.headline" : "Paramètres", "settings.app.headlineAdvanced" : "Paramètres avancés", "settings.app.headlineAppearance" : "Apparence", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Veuillez redémarrer Franz après avoir modifié les paramètres proxy.", "settings.service.form.proxy.user" : "Utilisateur (facultatif)", "settings.service.form.saveButton" : "Enregistrer le service", - "settings.service.form.spellcheckerLanguage" : "Langue de vérification d'orthographe", - "settings.service.form.spellcheckerLanguage.default" : "Par défaut ({default})", "settings.service.form.tabHosted" : "Hébergé", "settings.service.form.tabOnPremise" : "Auto-hébergé ⭐️", "settings.service.form.team" : "Équipe", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Découvrir les services", "settings.services.headline" : "Vos services", "settings.services.noServicesAdded" : "Vous n'avez pas encore ajouté de services.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Ce service est désactivé", "settings.services.tooltip.isMuted" : "Tous les sons sont coupés", "settings.services.tooltip.notificationsDisabled" : "Notifications désactivées.", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Résidents de l'UE : une taxe locale peut s'appliquer", "subscription.features.ads" : "Plus de pubs !", "subscription.features.comingSoon" : "Bientôt disponible", - "subscription.features.encryptedSync" : "Synchronisation de session cryptée", "subscription.features.noInterruptions" : "Aucun délai dans l'application ni de harcèlement pour mettre à niveau la licence", - "subscription.features.onpremise" : "Ajouter des services locaux\/hébergés comme HipChat", "subscription.features.onpremise.mattermost" : "Ajouter des services auto-hébergés comme Mattermost", "subscription.features.proxy" : "Support proxy pour les services", "subscription.features.spellchecker" : "Prise en charge du correcteur orthographique", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Recharger", "validation.email" : "{field} n'est pas valide", "validation.minLength" : "{field} doit contenir au moins {length} caractère(s)", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} est requis", "validation.url" : "{field} n'est pas une URL valide", "welcome.loginButton" : "Se connecter sur son compte", - "welcome.signupButton" : "Créer un compte gratuit", - "welcome.slogan" : "Une messagerie qui fonctionne pour vous" + "welcome.signupButton" : "Créer un compte gratuit" } diff --git a/src/i18n/locales/ga.json b/src/i18n/locales/ga.json index 2b3d39b73..eb7c04491 100644 --- a/src/i18n/locales/ga.json +++ b/src/i18n/locales/ga.json @@ -70,7 +70,9 @@ "menu.help.support" : "Tacaíocht", "menu.help.tos" : "Téarmaí tagartha", "menu.services" : "Seirbhísí", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Cuir seirbhís nua leis", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Amharc", "menu.view.enterFullScreen" : "Cuir isteach mód lánscáileáin", "menu.view.exitFullScreen" : "Scoir mód lánscáileáin", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Íoslódáil", "settings.account.manageSubscription.label" : "Bainistigh do shíntiús", "settings.account.successInfo" : "Sábháladh do chuid athruithe", + "settings.account.tryReloadServices" : "Atriail", "settings.account.tryReloadUserInfoRequest" : "Atriail", "settings.account.userInfoRequestFailed" : "Ní féidir eolas úsáideora a lódáil", "settings.app.buttonClearAllCache" : "Glan taisce", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Cuir leagain béite san áireamh", "settings.app.form.darkMode" : "Join the Dark Side", "settings.app.form.enableGPUAcceleration" : "Cumasaigh luasghéarú APG", - "settings.app.form.enableMenuBar" : "Taispeáin Franz sa bharra roghchláir", "settings.app.form.enableSpellchecking" : "Cumasaigh seiceáil litrithe", "settings.app.form.enableSystemTray" : "Taispeáin Franz i dtráidire an chórais", - "settings.app.form.hideDockIcon" : "Cuir íocóin Franz i bhfolach ón leaba nasctha", "settings.app.form.language" : "Teanga", "settings.app.form.minimizeToSystemTray" : "Íoslaghdaigh Franz chuig tráidire an chórais", "settings.app.form.runInBackground" : "Coimeád Franz sa chúlra nuair a dhúntar an fhuinneog", "settings.app.form.showDisabledServices" : "Taispeáin tabanna do sheirbhísí dhíchumasaithe", "settings.app.form.showMessagesBadgesWhenMuted" : "Taispeáin teachtaireachtaí neamhléite, nuair a dhíchumasaítear fógraí", - "settings.app.form.spellcheckerLanguage" : "Spell checking language", "settings.app.headline" : "Socruithe", "settings.app.headlineAdvanced" : "Casta", "settings.app.headlineAppearance" : "Dealramh", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Please restart Franz after changing proxy Settings.", "settings.service.form.proxy.user" : "User (optional)", "settings.service.form.saveButton" : "Sábháil seirbhís", - "settings.service.form.spellcheckerLanguage" : "Spell checking Language", - "settings.service.form.spellcheckerLanguage.default" : "Use System Default ({default})", "settings.service.form.tabHosted" : "Óstáilte", "settings.service.form.tabOnPremise" : "Féinóstáilte ⭐️", "settings.service.form.team" : "Foireann", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Aimsigh seirbhísí", "settings.services.headline" : "Do sheirbhísí", "settings.services.noServicesAdded" : "Níl aon seirbhís curtha agat go fóill.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Seirbhís díchumasaithe", "settings.services.tooltip.isMuted" : "Tachtar gach fuaim", "settings.services.tooltip.notificationsDisabled" : "Fógraí dhíchumasaithe", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Áithritheoirí an tAÉ: is féidir cáin díolacháin áitiúla a chur i bhfeidhm", "subscription.features.ads" : "Fógraí ar bith, choíche!", "subscription.features.comingSoon" : "ag teacht go luath", - "subscription.features.encryptedSync" : "Sionchronú seisiúin chriptithe", "subscription.features.noInterruptions" : "No app delays & nagging to upgrade license", - "subscription.features.onpremise" : "Cuir seirbhísí óstáilte ar nós HipChat leis", "subscription.features.onpremise.mattermost" : "Add on-premise\/hosted services like Mattermost", "subscription.features.proxy" : "Proxy support for services", "subscription.features.spellchecker" : "Support for spellchecker", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Athlódáil", "validation.email" : "Níl {field} neamhbhailí", "validation.minLength" : "Ba cheart go mbeadh {field} ar a laghad {length} charactar fada", + "validation.oneRequired" : "At least one is required", "validation.required" : "Tá {field} de dhíth", "validation.url" : "Ní AAA bhailí é {field}", "welcome.loginButton" : "Logáil isteach i do chuntas", - "welcome.signupButton" : "Cruthaigh cuntas nua", - "welcome.slogan" : "Teachtaireachtaí a oibríonn duitse" + "welcome.signupButton" : "Cruthaigh cuntas nua" } diff --git a/src/i18n/locales/hr.json b/src/i18n/locales/hr.json index dc1d579fa..95920c4ce 100644 --- a/src/i18n/locales/hr.json +++ b/src/i18n/locales/hr.json @@ -70,7 +70,9 @@ "menu.help.support" : "Support", "menu.help.tos" : "Terms of Service", "menu.services" : "Services", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Add New Service...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "View", "menu.view.enterFullScreen" : "Enter Full Screen", "menu.view.exitFullScreen" : "Exit Full Screen", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Preuzmite", "settings.account.manageSubscription.label" : "Upravljajte pretplatama", "settings.account.successInfo" : "Vaše promjene su spremljene", + "settings.account.tryReloadServices" : "Pokušajte ponovno", "settings.account.tryReloadUserInfoRequest" : "Pokušajte ponovno", "settings.account.userInfoRequestFailed" : "Nije moguće učitati informacije o korisniku", "settings.app.buttonClearAllCache" : "Očisti memoriju", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Obuhvati i beta verzije", "settings.app.form.darkMode" : "Join the Dark Side", "settings.app.form.enableGPUAcceleration" : "Enable GPU Acceleration", - "settings.app.form.enableMenuBar" : "Prikaži Franz u traci izbornika", "settings.app.form.enableSpellchecking" : "Omogući provjeru pravopisa", "settings.app.form.enableSystemTray" : "Prikaži aplikaciju u sustavskoj traci", - "settings.app.form.hideDockIcon" : "Sakrij ikonu Franz u prostoru za obavijesti", "settings.app.form.language" : "Jezik", "settings.app.form.minimizeToSystemTray" : "Smanji Franca u sustavsku traku", "settings.app.form.runInBackground" : "Neka se Franc održava u pozadini i ako je prozor zatvoren", "settings.app.form.showDisabledServices" : "Prikaži ploče s onemogućenim servisima", "settings.app.form.showMessagesBadgesWhenMuted" : "Pokaži nepročitane značke poruka kad se obavještenja onemoguće", - "settings.app.form.spellcheckerLanguage" : "Spell checking language", "settings.app.headline" : "Postavke", "settings.app.headlineAdvanced" : "Napredne alatke", "settings.app.headlineAppearance" : "Izgled", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Please restart Franz after changing proxy Settings.", "settings.service.form.proxy.user" : "User (optional)", "settings.service.form.saveButton" : "Sačuvaj uslugu\/e", - "settings.service.form.spellcheckerLanguage" : "Spell checking Language", - "settings.service.form.spellcheckerLanguage.default" : "Use System Default ({default})", "settings.service.form.tabHosted" : "Hostovano", "settings.service.form.tabOnPremise" : "Samo-hostovano ⭐️", "settings.service.form.team" : "Tim", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Pronađite usluge", "settings.services.headline" : "Vaše usluge", "settings.services.noServicesAdded" : "Još uvijek niste unijeli niti jednu uslugu.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Usluga je onemogućena. ", "settings.services.tooltip.isMuted" : "Svi zvukovi su onemogućeni. ", "settings.services.tooltip.notificationsDisabled" : "Obavijesti su onemogućene.", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "EU državljani, upozerenje: Moguće taksiranje ", "subscription.features.ads" : "Bez reklama, doživotno!", "subscription.features.comingSoon" : "Dolazi uskoro", - "subscription.features.encryptedSync" : "Kodirano usklađivanje sesija.", "subscription.features.noInterruptions" : "No app delays & nagging to upgrade license", - "subscription.features.onpremise" : "Dodajte pretpostavljeni\/hostirani servis kao što ima usluga HipChat ", "subscription.features.onpremise.mattermost" : "Add on-premise\/hosted services like Mattermost", "subscription.features.proxy" : "Proxy support for services", "subscription.features.spellchecker" : "Support for spellchecker", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Ponovno učitavanje", "validation.email" : "{field} is not valid", "validation.minLength" : "{field} should be at least {length} characters long", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} is required", "validation.url" : "{field} is not a valid URL", "welcome.loginButton" : "Prijavite se na račun", - "welcome.signupButton" : "Stvorite novi korisnički račun", - "welcome.slogan" : "Poruke koje su stvorene za tebe" + "welcome.signupButton" : "Stvorite novi korisnički račun" } diff --git a/src/i18n/locales/hu.json b/src/i18n/locales/hu.json index ddaffeebb..bce9a368e 100644 --- a/src/i18n/locales/hu.json +++ b/src/i18n/locales/hu.json @@ -70,7 +70,9 @@ "menu.help.support" : "Támogatás", "menu.help.tos" : "Felhasználói feltételek", "menu.services" : "Szolgáltatások", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Új szolgáltatás hozzáadása...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Nézet", "menu.view.enterFullScreen" : "Kilépés a teljes képernyős módból", "menu.view.exitFullScreen" : "Kilépés a teljes képernyős módból", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Letöltés", "settings.account.manageSubscription.label" : "Előfizetés kezelése", "settings.account.successInfo" : "A módosításokat elmentettük", + "settings.account.tryReloadServices" : "Próbáld újra", "settings.account.tryReloadUserInfoRequest" : "Próbáld újra", "settings.account.userInfoRequestFailed" : "A felhasználói adatok betöltése sikertelen", "settings.app.buttonClearAllCache" : "Gyorsítótár törlése", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Béta verziók keresése", "settings.app.form.darkMode" : "Csatlakozz a Sötét Oldalhoz", "settings.app.form.enableGPUAcceleration" : "Hardveres gyorsítás engedélyezése", - "settings.app.form.enableMenuBar" : "Franz megjelenítése a menüsorban", "settings.app.form.enableSpellchecking" : "Helyesírás-ellenőrzés engedélyezése", "settings.app.form.enableSystemTray" : "Franz mutatása a tálcán", - "settings.app.form.hideDockIcon" : "Franz ikon elrejtése a Dock mögött", "settings.app.form.language" : "Nyelv", "settings.app.form.minimizeToSystemTray" : "Franz kicsinyítése a tálcára", "settings.app.form.runInBackground" : "Franz fusson a háttérben az ablak bezárásakor", "settings.app.form.showDisabledServices" : "Letiltott szolgáltatások megjelenítése", "settings.app.form.showMessagesBadgesWhenMuted" : "Mutassa az 'olvasatlan üzenet' jelzést, amikor az értesítések le vannak tiltva", - "settings.app.form.spellcheckerLanguage" : "Helyesírás-ellenőrző nyelve", "settings.app.headline" : "Beállítások", "settings.app.headlineAdvanced" : "Haladó", "settings.app.headlineAppearance" : "Megjelenés", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Kérjük indítsd újra a Franz-ot a proxy beállítások megváltoztatása után.", "settings.service.form.proxy.user" : "Felhasználó (opcionális)", "settings.service.form.saveButton" : "Szolgáltatás mentése", - "settings.service.form.spellcheckerLanguage" : "Helyesírás-ellenőrző nyelve", - "settings.service.form.spellcheckerLanguage.default" : "Rendszer alapbeállítás használata ({default})", "settings.service.form.tabHosted" : "Üzemeltetett", "settings.service.form.tabOnPremise" : "Egyénileg üzemeltetett", "settings.service.form.team" : "Csapat", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Szolgáltatások felfedezése", "settings.services.headline" : "Szolgáltatásaid", "settings.services.noServicesAdded" : "Még nem adtál hozzá egyetlen szolgáltatást sem eddig.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "A szolgáltatás le van tiltva", "settings.services.tooltip.isMuted" : "Minden hang lenémítva", "settings.services.tooltip.notificationsDisabled" : "Értesítések letiltva", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "EU állampolgárok: helyi vásárlás esetén adók kerülhetnek felszámolásra", "subscription.features.ads" : "Hirdetésmentes, mindig!", "subscription.features.comingSoon" : "hamarosan", - "subscription.features.encryptedSync" : "Titkosított munkamenet szinkronizálás", "subscription.features.noInterruptions" : "Nincs több app késlekedés és liszencfrissítési piszkálás", - "subscription.features.onpremise" : "Helyi\/üzemeltetett szolgáltatások használata, pl. HipChat", "subscription.features.onpremise.mattermost" : "Saját kiszolgálós szolgáltatások hozzáadása, pl.: Mattermost", "subscription.features.proxy" : "Proxy támogatás a szolgáltatásokhoz", "subscription.features.spellchecker" : "Támogatás a Helyesírás-ellenőrzőhöz", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Újratöltés", "validation.email" : "{field} nem érvényes", "validation.minLength" : "{field} mezőnek legalább {length} karakter hosszúnak kell lennie", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} kitöltése kötelező", "validation.url" : "{field} nem érvényes URL", "welcome.loginButton" : "Jelentkezz be a fiókodba", - "welcome.signupButton" : "Új fiók létrehozása", - "welcome.slogan" : "Üzenetküldés okosan" + "welcome.signupButton" : "Új fiók létrehozása" } diff --git a/src/i18n/locales/id.json b/src/i18n/locales/id.json index 6abbf064b..73271dceb 100644 --- a/src/i18n/locales/id.json +++ b/src/i18n/locales/id.json @@ -70,7 +70,9 @@ "menu.help.support" : "Dukungan", "menu.help.tos" : "Ketentuan Layanan", "menu.services" : "Layanan", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Tambahkan Layanan Baru...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Tampilan", "menu.view.enterFullScreen" : "Masuk ke Mode Layar Penuh", "menu.view.exitFullScreen" : "Keluar dari Layar Penuh", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Unduh", "settings.account.manageSubscription.label" : "Kelola langganan Anda", "settings.account.successInfo" : "Perubahan Anda telah disimpan", + "settings.account.tryReloadServices" : "Coba lagi", "settings.account.tryReloadUserInfoRequest" : "Coba lagi", "settings.account.userInfoRequestFailed" : "Gagal memuat informasi pengguna", "settings.app.buttonClearAllCache" : "Bersihkan singgahan", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Sertakan versi beta", "settings.app.form.darkMode" : "Sisi Kelam menunggu Anda (Mode Gelap)", "settings.app.form.enableGPUAcceleration" : "Aktifkan Akselerasi GPU", - "settings.app.form.enableMenuBar" : "Tampilkan Franz di Bilah Menu", "settings.app.form.enableSpellchecking" : "Aktifkan pemeriksaan ejaan", "settings.app.form.enableSystemTray" : "Tampilkan Franz di baki sistem", - "settings.app.form.hideDockIcon" : "Sembunyikan ikon Franz di Dock", "settings.app.form.language" : "Bahasa", "settings.app.form.minimizeToSystemTray" : "Perkecil Franz ke baki sistem", "settings.app.form.runInBackground" : "Tetap jalankan Franz di latar belakang saat menutup jendela", "settings.app.form.showDisabledServices" : "Tampilkan tab layanan yang dinonaktifkan", "settings.app.form.showMessagesBadgesWhenMuted" : "Tampilkan lencana pesan belum dibaca saat pemberitahuan dinonaktifkan", - "settings.app.form.spellcheckerLanguage" : "Periksa ejaan", "settings.app.headline" : "Pengaturan", "settings.app.headlineAdvanced" : "Tingkat Lanjut", "settings.app.headlineAppearance" : "Tampilan", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Silahkan mulai ulang Franz setelah mengubah Setelan proxy", "settings.service.form.proxy.user" : "Pengguna (opsional)", "settings.service.form.saveButton" : "Simpan layanan", - "settings.service.form.spellcheckerLanguage" : "Periksa ejaan Bahasa", - "settings.service.form.spellcheckerLanguage.default" : "Gunakan Bawaan Sistem ({default})", "settings.service.form.tabHosted" : "Hosted", "settings.service.form.tabOnPremise" : "Hosted mandiri", "settings.service.form.team" : "Tim", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Temukan layanan", "settings.services.headline" : "Layanan Anda", "settings.services.noServicesAdded" : "Anda belum menambahkan layanan apa pun.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Layanan dinonaktifkan", "settings.services.tooltip.isMuted" : "Semua suara dibisukan", "settings.services.tooltip.notificationsDisabled" : "Pemberitahuan dinonaktifkan", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Warga UE: pajak penjualan lokal mungkin berlaku", "subscription.features.ads" : "Tanpa iklan, selamanya!", "subscription.features.comingSoon" : "segera hadir", - "subscription.features.encryptedSync" : "Sinkronisasi sesi terenkripsi", "subscription.features.noInterruptions" : "Tanpa menunggu dan ditanya untuk meningkatkan lisensi", - "subscription.features.onpremise" : "Integrasi layanan hosted, misalnya HipChat", "subscription.features.onpremise.mattermost" : "Integrasi layanan hosted, misalnya Mattermost", "subscription.features.proxy" : "Dukungan proksi untuk layanan", "subscription.features.spellchecker" : "Dukungan pengecek ejaan", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Muat Ulang", "validation.email" : "{field} tidak benar", "validation.minLength" : "{field} setidaknya harus {length} karakter", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} wajib diisi", "validation.url" : "{field} bukan URL yang benar", "welcome.loginButton" : "Masuk ke akun Anda", - "welcome.signupButton" : "Buat akun gratis", - "welcome.slogan" : "Perpesanan yang bekerja untuk Anda" + "welcome.signupButton" : "Buat akun gratis" } diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index b63b30a90..71150483c 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -70,7 +70,9 @@ "menu.help.support" : "Supporto", "menu.help.tos" : "Termini di Servizio", "menu.services" : "Servizi", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Aggiungi Nuovo Servizio...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Visualizza", "menu.view.enterFullScreen" : "Visualizza a Schermo Intero", "menu.view.exitFullScreen" : "Esci da Schermo Intero", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Scarica", "settings.account.manageSubscription.label" : "Gestisci il tuo abbonamento", "settings.account.successInfo" : "Le tue modifiche sono state salvate", + "settings.account.tryReloadServices" : "Prova di nuovo", "settings.account.tryReloadUserInfoRequest" : "Prova di nuovo", "settings.account.userInfoRequestFailed" : "Impossibile caricare le informazioni dell'utente.", "settings.app.buttonClearAllCache" : "Svuota la cache", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Includi versioni beta", "settings.app.form.darkMode" : "Unisciti al Lato Oscuro.", "settings.app.form.enableGPUAcceleration" : "Attiva Accelerazione GPU", - "settings.app.form.enableMenuBar" : "Mostra Franz nella Barra del Menu", "settings.app.form.enableSpellchecking" : "Attiva controllo ortografico", "settings.app.form.enableSystemTray" : "Mostra Franz nell'area di notifica", - "settings.app.form.hideDockIcon" : "Nascondi l'icona Franz nel Dock", "settings.app.form.language" : "Lingua", "settings.app.form.minimizeToSystemTray" : "Minimizza Franz nell'area di notifica", "settings.app.form.runInBackground" : "Mantieni Franz in esecuzione quando chiudi la finestra", "settings.app.form.showDisabledServices" : "Mostra schede servizi disattivati", "settings.app.form.showMessagesBadgesWhenMuted" : "Mostra l'etichetta dei messaggi non letti quando le notifiche sono disattivate", - "settings.app.form.spellcheckerLanguage" : "Lingua per controllo ortografico", "settings.app.headline" : "Impostazioni", "settings.app.headlineAdvanced" : "Avanzate", "settings.app.headlineAppearance" : "Aspetto", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Riavvia Franz dopo aver cambiato le impostazioni del proxy.", "settings.service.form.proxy.user" : "Utente (opzionale)", "settings.service.form.saveButton" : "Salva servizio", - "settings.service.form.spellcheckerLanguage" : "Lingua per controllo ortografico", - "settings.service.form.spellcheckerLanguage.default" : "Usa le impostazioni predefinite di sistema ({default})", "settings.service.form.tabHosted" : "Hosted", "settings.service.form.tabOnPremise" : "Self hosted ⭐️", "settings.service.form.team" : "Gruppo", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Scopri servizi", "settings.services.headline" : "I tuoi servizi", "settings.services.noServicesAdded" : "Non hai aggiunto ancora nessun servizio.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Il servizio è disattivato", "settings.services.tooltip.isMuted" : "Tutti i suoni sono disattivati", "settings.services.tooltip.notificationsDisabled" : "Le notifiche sono disattivate", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Per i residenti UE: possono essere applicate tasse locali", "subscription.features.ads" : "Nessuna pubblicità, mai!", "subscription.features.comingSoon" : "in arrivo", - "subscription.features.encryptedSync" : "Sincronizzazione sessione crittografata", "subscription.features.noInterruptions" : "L'upgrade della licenza avrà impatti sull'utilizzo dell'App", - "subscription.features.onpremise" : "Aggiungi servizi on-premise\/hosted come HipChat", "subscription.features.onpremise.mattermost" : "Aggiungi servizi on-premise\/hosted come \"Mattermost\"", "subscription.features.proxy" : "Supporto proxy per i servizi", "subscription.features.spellchecker" : "Supporto per il correttore ortografico", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Ricarica", "validation.email" : "{field} non valido", "validation.minLength" : "{field} dovrebbe contenere almeno {length} caratteri", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} è necessario", "validation.url" : "{field} non è un URL valido", "welcome.loginButton" : "Accedi al tuo account", - "welcome.signupButton" : "Crea un account gratuito", - "welcome.slogan" : "Un sistema di messaggistica che va bene per te" + "welcome.signupButton" : "Crea un account gratuito" } diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 838dc81ea..bd1024a34 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -70,7 +70,9 @@ "menu.help.support" : "サポート", "menu.help.tos" : "サービス利用規約", "menu.services" : "サービス", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "サービスを追加", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "表示", "menu.view.enterFullScreen" : "全画面表示", "menu.view.exitFullScreen" : "全画面表示を終了する", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "ダウンロード", "settings.account.manageSubscription.label" : "サブスクリプションの管理", "settings.account.successInfo" : "変更内容が保存されました", + "settings.account.tryReloadServices" : "もう一度試す", "settings.account.tryReloadUserInfoRequest" : "もう一度試す", "settings.account.userInfoRequestFailed" : "ユーザ情報を読み込めませんでした", "settings.app.buttonClearAllCache" : "キャッシュを消去する", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Betaバージョンを含める", "settings.app.form.darkMode" : "ダークモードを有効にする", "settings.app.form.enableGPUAcceleration" : "GPUアクセラレーションを有効にする", - "settings.app.form.enableMenuBar" : "メニューバーにFranzを表示する", "settings.app.form.enableSpellchecking" : "スペルチェックを有効にする", "settings.app.form.enableSystemTray" : "Franzをシステムトレイに表示する", - "settings.app.form.hideDockIcon" : "DockからFranzを隠す", "settings.app.form.language" : "言語", "settings.app.form.minimizeToSystemTray" : "Franzをシステムトレイに最小化する", "settings.app.form.runInBackground" : "ウインドウを閉じた際にFranzをバックグラウンドで実行させておく", "settings.app.form.showDisabledServices" : "無効化されたサービスのタブを表示する", "settings.app.form.showMessagesBadgesWhenMuted" : "通知の無効時に未読メッセージ件数を表示する", - "settings.app.form.spellcheckerLanguage" : "スペルチェックする言語", "settings.app.headline" : "設定", "settings.app.headlineAdvanced" : "詳細", "settings.app.headlineAppearance" : "表示スタイル", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "プロキシ設定を変更してから、Franzを再起動してください", "settings.service.form.proxy.user" : "ユーザー名(任意)", "settings.service.form.saveButton" : "サービスの保存", - "settings.service.form.spellcheckerLanguage" : "言語のスペルチェック", - "settings.service.form.spellcheckerLanguage.default" : " {default}を初期設定で使用してください", "settings.service.form.tabHosted" : "ホスト", "settings.service.form.tabOnPremise" : "セルフホスト ⭐️", "settings.service.form.team" : "チーム", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "サービスを探す", "settings.services.headline" : "利用中のサービス", "settings.services.noServicesAdded" : "まだ、どのサービスも追加されていません。", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "サービスが無効です", "settings.services.tooltip.isMuted" : "無音となっています", "settings.services.tooltip.notificationsDisabled" : "通知は無効です", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "EU在住者 : 地域の消費税が適用される可能性があります", "subscription.features.ads" : "広告は一切ありません!", "subscription.features.comingSoon" : "まもなく登場", - "subscription.features.encryptedSync" : "暗号化されたセッションの同期", "subscription.features.noInterruptions" : "待ち時間なしでFranz をお使いいただけます", - "subscription.features.onpremise" : "HipChatのようなオンプレミス\/ホスト型サービスの追加", "subscription.features.onpremise.mattermost" : "Mattermost のようなオンプレミス(自社運用)型のサービスを追加できるようになります", "subscription.features.proxy" : "プロキシ設定が利用可能", "subscription.features.spellchecker" : "スペルチェック機能をお使いいただけます", @@ -280,9 +277,9 @@ "tabs.item.reload" : "再読み込み", "validation.email" : "{field}は正しくありません", "validation.minLength" : "{field}は少なくとも{length}文字以上でなければなりません", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field}は必須です", "validation.url" : "{field}は正しいURLではありません", "welcome.loginButton" : "アカウントにログイン", - "welcome.signupButton" : "無料アカウントを作成", - "welcome.slogan" : "Messaging that works for you" + "welcome.signupButton" : "無料アカウントを作成" } diff --git a/src/i18n/locales/ka.json b/src/i18n/locales/ka.json index ec0cdd375..4796cbe9f 100644 --- a/src/i18n/locales/ka.json +++ b/src/i18n/locales/ka.json @@ -70,7 +70,9 @@ "menu.help.support" : "Support", "menu.help.tos" : "Terms of Service", "menu.services" : "Services", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Add New Service...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "View", "menu.view.enterFullScreen" : "Enter Full Screen", "menu.view.exitFullScreen" : "Exit Full Screen", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "გადმოწერა", "settings.account.manageSubscription.label" : "თქვენი გამოწერის მართვა", "settings.account.successInfo" : "თქვენი ცვლილებები შენახულია", + "settings.account.tryReloadServices" : "სცადეთ ხელახლა", "settings.account.tryReloadUserInfoRequest" : "სცადეთ ხელახლა", "settings.account.userInfoRequestFailed" : "მომხმარებლის ინფორმაციის ჩატვირთვა ვერ მოხერხდა", "settings.app.buttonClearAllCache" : "Clear cache", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "ჩართეთ ბეტა ვერსიები", "settings.app.form.darkMode" : "Join the Dark Side", "settings.app.form.enableGPUAcceleration" : "Enable GPU Acceleration", - "settings.app.form.enableMenuBar" : "Show Franz in Menu Bar", "settings.app.form.enableSpellchecking" : "Enable spell checking", "settings.app.form.enableSystemTray" : "აჩვენეთ Franz სისტემის უჯრაში", - "settings.app.form.hideDockIcon" : "Hide Franz icon in Dock", "settings.app.form.language" : "ენა", "settings.app.form.minimizeToSystemTray" : "ჩაკეცეთ Franz სისტემის უჯრაში", "settings.app.form.runInBackground" : "დატოვეთ Franz გაშვებული როდესაც ფანჯარა დაიხურება", "settings.app.form.showDisabledServices" : "Display disabled services tabs", "settings.app.form.showMessagesBadgesWhenMuted" : "Show unread message badge when notifications are disabled", - "settings.app.form.spellcheckerLanguage" : "Spell checking language", "settings.app.headline" : "პარამეტრები", "settings.app.headlineAdvanced" : "Advanced", "settings.app.headlineAppearance" : "Appearance", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Please restart Franz after changing proxy Settings.", "settings.service.form.proxy.user" : "User (optional)", "settings.service.form.saveButton" : "სერვისის შენახვა", - "settings.service.form.spellcheckerLanguage" : "Spell checking Language", - "settings.service.form.spellcheckerLanguage.default" : "Use System Default ({default})", "settings.service.form.tabHosted" : "დაჰოსტილი", "settings.service.form.tabOnPremise" : "თვით დაჰოსტილი ⭐️", "settings.service.form.team" : "გუნდი", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "აღმოაჩინეთ სერვისები", "settings.services.headline" : "თქვენი სერვისები", "settings.services.noServicesAdded" : "თქვენ ჯერ არ გაქვთ სერვისები დამატებული.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "სერვისი გათიშულია", "settings.services.tooltip.isMuted" : "All sounds are muted", "settings.services.tooltip.notificationsDisabled" : "შეტყობინებები გათიშულია", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "EU residents: local sales tax may apply", "subscription.features.ads" : "არანაირი რეკლამები, არასდროს!", "subscription.features.comingSoon" : "მალე", - "subscription.features.encryptedSync" : "დაშიფრული სესიის სინქრონიზაცია", "subscription.features.noInterruptions" : "No app delays & nagging to upgrade license", - "subscription.features.onpremise" : "on-premise\/hosted სერვისების დამატება, როგორიცაა HipChat", "subscription.features.onpremise.mattermost" : "Add on-premise\/hosted services like Mattermost", "subscription.features.proxy" : "Proxy support for services", "subscription.features.spellchecker" : "Support for spellchecker", @@ -280,9 +277,9 @@ "tabs.item.reload" : "ჩატვირთვა", "validation.email" : "{field} is not valid", "validation.minLength" : "{field} should be at least {length} characters long", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} is required", "validation.url" : "{field} is not a valid URL", "welcome.loginButton" : "შედით თქვენს ანგარიშში", - "welcome.signupButton" : "შექმენი ანგარიში, ეს უფასოა", - "welcome.slogan" : "შეტყობინების აპლიკაცია, რომელიც მუშაობს შენთვის" + "welcome.signupButton" : "შექმენი ანგარიში, ეს უფასოა" } diff --git a/src/i18n/locales/nl-BE.json b/src/i18n/locales/nl-BE.json index 2082edd6d..00d7ddd06 100644 --- a/src/i18n/locales/nl-BE.json +++ b/src/i18n/locales/nl-BE.json @@ -70,7 +70,9 @@ "menu.help.support" : "Ondersteuning", "menu.help.tos" : "Servicevoorwaarden", "menu.services" : "Services", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Nieuwe service toevoegen...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Weergave", "menu.view.enterFullScreen" : "Volledig scherm openen", "menu.view.exitFullScreen" : "Volledig scherm verlaten", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Download", "settings.account.manageSubscription.label" : "Beheer je abonnement", "settings.account.successInfo" : "Je wijzigingen zijn opgeslagen", + "settings.account.tryReloadServices" : "Probeer opnieuw", "settings.account.tryReloadUserInfoRequest" : "Probeer opnieuw", "settings.account.userInfoRequestFailed" : "Kon gebruikersinformatie niet laden", "settings.app.buttonClearAllCache" : "Cache wissen", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Inclusief beta versies", "settings.app.form.darkMode" : "Word lid van de Dark Side", "settings.app.form.enableGPUAcceleration" : "GPU Acceleratie Activeren", - "settings.app.form.enableMenuBar" : "Toon Franz in Menu Bar", "settings.app.form.enableSpellchecking" : "Spellingcontrole inschakelen", "settings.app.form.enableSystemTray" : "Toon Franz in de systeembalk", - "settings.app.form.hideDockIcon" : "Verberg Franz in Dock", "settings.app.form.language" : "Taal", "settings.app.form.minimizeToSystemTray" : "Minimaliseer Franz naar de systeembalk", "settings.app.form.runInBackground" : "Houd Franz op de achtergrond wanneer het venster gesloten wordt", "settings.app.form.showDisabledServices" : "Toon uitgeschakelde services", "settings.app.form.showMessagesBadgesWhenMuted" : "Toon badge met ongelezen berichten wanneer meldingen zijn uitgeschakeld", - "settings.app.form.spellcheckerLanguage" : "Taal spellingscontrole", "settings.app.headline" : "Instellingen", "settings.app.headlineAdvanced" : "Geavanceerd", "settings.app.headlineAppearance" : "Weergave", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Start Franz opnieuw op na het aanpassen van proxy Instellingen.", "settings.service.form.proxy.user" : "Gebruiker (optioneel)", "settings.service.form.saveButton" : "Service opslaan", - "settings.service.form.spellcheckerLanguage" : "Taal spellingscontrole", - "settings.service.form.spellcheckerLanguage.default" : "Gebruik Systeemstandaard ({default})", "settings.service.form.tabHosted" : "Gehost", "settings.service.form.tabOnPremise" : "Intern gehost ⭐️", "settings.service.form.team" : "Team", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Services ontdekken", "settings.services.headline" : "Jouw services", "settings.services.noServicesAdded" : "Je hebt nog geen services toegevoegd.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Service is uitgeschakeld", "settings.services.tooltip.isMuted" : "Alle geluiden zijn uitgeschakeld", "settings.services.tooltip.notificationsDisabled" : "Notificaties staan uit", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Bewoners binnen EU: lokale belasting kan van toepassing zijn", "subscription.features.ads" : "Geen reclame, nooit!", "subscription.features.comingSoon" : "komt binnenkort", - "subscription.features.encryptedSync" : "Synchronisatie van geëncrypteerde sessies", "subscription.features.noInterruptions" : "Geen haperingen & pop ups over upgrades", - "subscription.features.onpremise" : "Intern gehoste services zoals HipChat", "subscription.features.onpremise.mattermost" : "Voeg op-locatie\/gehoste diensten zoals Mattermost toe", "subscription.features.proxy" : "Proxy ondersteuning voor services", "subscription.features.spellchecker" : "Ondersteuning voor spellingscheck", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Herladen", "validation.email" : "{field} is niet geldig", "validation.minLength" : "{field} moet minimaal {length} karakters lang zijn", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} is vereist", "validation.url" : "{field} is niet een geldige URL", "welcome.loginButton" : "Inloggen op je account", - "welcome.signupButton" : "Maak een gratis account aan", - "welcome.slogan" : "Messaging die voor jou werkt" + "welcome.signupButton" : "Maak een gratis account aan" } diff --git a/src/i18n/locales/nl.json b/src/i18n/locales/nl.json index df0549a28..782c29a6c 100644 --- a/src/i18n/locales/nl.json +++ b/src/i18n/locales/nl.json @@ -70,7 +70,9 @@ "menu.help.support" : "Ondersteuning", "menu.help.tos" : "Servicevoorwaarden", "menu.services" : "Diensten", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Nieuwe dienst toevoegen", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Weergave", "menu.view.enterFullScreen" : "Gebruik volledig scherm", "menu.view.exitFullScreen" : "Volledig scherm verlaten", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Download", "settings.account.manageSubscription.label" : "Beheer je abonnement", "settings.account.successInfo" : "Je wijzigingen zijn opgeslagen", + "settings.account.tryReloadServices" : "Probeer opnieuw", "settings.account.tryReloadUserInfoRequest" : "Probeer opnieuw", "settings.account.userInfoRequestFailed" : "Kon gebruikersinformatie niet laden", "settings.app.buttonClearAllCache" : "Cache legen", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Inclusief bètaversies", "settings.app.form.darkMode" : "Stap over naar de donkere kant", "settings.app.form.enableGPUAcceleration" : "Schakel videokaart acceleratie in ", - "settings.app.form.enableMenuBar" : "Toon Franz in menubalk", "settings.app.form.enableSpellchecking" : "Zet spellingcontrole aan", "settings.app.form.enableSystemTray" : "Toon Franz in de systeembalk", - "settings.app.form.hideDockIcon" : "Verberg Franz in Dock", "settings.app.form.language" : "Taal", "settings.app.form.minimizeToSystemTray" : "Minimaliseer Franz naar de systeembalk", "settings.app.form.runInBackground" : "Houd Franz op de achtergrond wanneer het venster gesloten wordt", "settings.app.form.showDisabledServices" : "Toon uitgeschakelde services", "settings.app.form.showMessagesBadgesWhenMuted" : "Toon badge met ongelezen berichten wanneer meldingen zijn uitgeschakeld", - "settings.app.form.spellcheckerLanguage" : "Spelling checken", "settings.app.headline" : "Instellingen", "settings.app.headlineAdvanced" : "Geavanceerd", "settings.app.headlineAppearance" : "Weergave", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Start Franz opnieuw na het aanpassen van proxy instellingen.", "settings.service.form.proxy.user" : "Gebruiker (optioneel)", "settings.service.form.saveButton" : "Service opslaan", - "settings.service.form.spellcheckerLanguage" : "Spellingcontrole taal", - "settings.service.form.spellcheckerLanguage.default" : "Gebruik systeemstandaard ({default})", "settings.service.form.tabHosted" : "Gehost", "settings.service.form.tabOnPremise" : "Zelf-gehost ⭐️", "settings.service.form.team" : "Team", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Ontdek services", "settings.services.headline" : "Jouw services", "settings.services.noServicesAdded" : "Je hebt nog geen services toegevoegd.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Service is uitgeschakeld", "settings.services.tooltip.isMuted" : "Alle geluiden zijn uitgeschakeld", "settings.services.tooltip.notificationsDisabled" : "Meldingen zijn uitgeschakeld", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Bewoners binnen EU: lokale belasting kan van toepassing zijn", "subscription.features.ads" : "Geen advertenties, nooit!", "subscription.features.comingSoon" : "komt binnenkort", - "subscription.features.encryptedSync" : "Beveiligde sessie synchronisatie", "subscription.features.noInterruptions" : "Geen haperingen & pop ups over upgrades", - "subscription.features.onpremise" : "Add on-geschikt\/gehoste services zoals HipChat", "subscription.features.onpremise.mattermost" : "Voeg op-locatie\/gehoste diensten zoals Mattermost toe", "subscription.features.proxy" : "Proxy understeuning voor diensten", "subscription.features.spellchecker" : "Ondersteuning voor spellingscheck", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Herladen", "validation.email" : "{field} is niet geldig", "validation.minLength" : "{field} moet minimaal {length} karakters lang zijn", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} is vereist", "validation.url" : "{field} is niet een geldige URL", "welcome.loginButton" : "Log in op je account", - "welcome.signupButton" : "Maak een gratis account", - "welcome.slogan" : "Messaging die voor jou werkt" + "welcome.signupButton" : "Maak een gratis account" } diff --git a/src/i18n/locales/pl.json b/src/i18n/locales/pl.json index e1a1747b3..dd70f25f7 100644 --- a/src/i18n/locales/pl.json +++ b/src/i18n/locales/pl.json @@ -70,7 +70,9 @@ "menu.help.support" : "Wsparcie", "menu.help.tos" : "Warunki świadczenia usług", "menu.services" : "Usługi", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Dodaj nową usługę...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Widok", "menu.view.enterFullScreen" : "Włącz tryb pełnoekranowy", "menu.view.exitFullScreen" : "Zakończ tryb pełnoekranowy", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Pobierz", "settings.account.manageSubscription.label" : "Zarządzaj swoimi subskrypcjami", "settings.account.successInfo" : "Twoje zmiany zostały zapisane", + "settings.account.tryReloadServices" : "Spróbuj ponownie", "settings.account.tryReloadUserInfoRequest" : "Spróbuj ponownie", "settings.account.userInfoRequestFailed" : "Nie można wczytać informacji o użytkowniku", "settings.app.buttonClearAllCache" : "Wyczyść pamięć podręczną (cache)", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Uwzględnij wersje beta", "settings.app.form.darkMode" : "Przejdź na Ciemną Stronę", "settings.app.form.enableGPUAcceleration" : "Włącz akcelerację GPU", - "settings.app.form.enableMenuBar" : "Pokaż Franz na pasku menu", "settings.app.form.enableSpellchecking" : "Włącz sprawdzanie pisowni", "settings.app.form.enableSystemTray" : "Pokaż Franza w obszarze powiadomień", - "settings.app.form.hideDockIcon" : "Ukrywaj ikonę Franz w zasobniku systemowym", "settings.app.form.language" : "Język", "settings.app.form.minimizeToSystemTray" : "Zminimalizuj aplikację Franz", "settings.app.form.runInBackground" : "Zachowaj aplikację Franz w tle po zamknięciu okna", "settings.app.form.showDisabledServices" : "Wyłącz wyświetlanie zakładek z usługami", "settings.app.form.showMessagesBadgesWhenMuted" : "Pokaż licznik nieprzeczytanych wiadomości gdy powiadomienia są wyłączone", - "settings.app.form.spellcheckerLanguage" : "Język słownika", "settings.app.headline" : "Ustawienia", "settings.app.headlineAdvanced" : "Zaawansowane", "settings.app.headlineAppearance" : "Wygląd", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Uruchom ponownie Franz po zmianie ustawień proxy.", "settings.service.form.proxy.user" : "Użytkownik (opcjonalnie)", "settings.service.form.saveButton" : "Zapisz usługę", - "settings.service.form.spellcheckerLanguage" : "Język sprawdzania pisowni", - "settings.service.form.spellcheckerLanguage.default" : "Użyj domyślnego dla systemu ({default})", "settings.service.form.tabHosted" : "Hostowane", "settings.service.form.tabOnPremise" : "Hostowane lokalnie ⭐️", "settings.service.form.team" : "Zespół", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Przeglądaj usługi", "settings.services.headline" : "Twoje usługi", "settings.services.noServicesAdded" : "Nie dodałeś jeszcze żadnych usług.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Usługa jest nieaktywna", "settings.services.tooltip.isMuted" : "Wszystkie dźwięki są wyciszone", "settings.services.tooltip.notificationsDisabled" : "Powiadomienia są nieaktywne", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Rezydenci UE: lokalne stawki VAT mogą zostać zaaplikowane", "subscription.features.ads" : "Brak reklam, na zawsze!", "subscription.features.comingSoon" : "wkrótce dostępne", - "subscription.features.encryptedSync" : "Szyfrowana synchronizacja sesji", "subscription.features.noInterruptions" : "Bez opóźnień i przypominania o ulepszeniu licencji", - "subscription.features.onpremise" : "Dodawanie lokalnych\/hostowanych usług takich jak HipChat", "subscription.features.onpremise.mattermost" : "Dodaj prywatnie hostowane usługi takie jak Mattermost", "subscription.features.proxy" : "Obsługa proxy dla usług", "subscription.features.spellchecker" : "Wsparcie dla sprawdzania pisowni", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Przeładuj", "validation.email" : "Pole {field} nie jest poprawne", "validation.minLength" : "Pole {field} powinno składać się z co najmniej {length} znaków", + "validation.oneRequired" : "At least one is required", "validation.required" : "Pole {field} jest wymagane", "validation.url" : "Pole {field} nie jest poprawnym ciągiem URL.", "welcome.loginButton" : "Zaloguj się na swoje konto", - "welcome.signupButton" : "Stwórz darmowe konto", - "welcome.slogan" : "Komunikator który działa" + "welcome.signupButton" : "Stwórz darmowe konto" } diff --git a/src/i18n/locales/pt-BR.json b/src/i18n/locales/pt-BR.json index 0ab5bdd21..490771c39 100644 --- a/src/i18n/locales/pt-BR.json +++ b/src/i18n/locales/pt-BR.json @@ -4,18 +4,18 @@ "feature.delayApp.action" : "Adquira uma licença Franz Supporter", "feature.delayApp.headline" : "Por favor, adquira uma licença Franz Supporter para pular o tempo de espera", "feature.delayApp.text" : "Franz continuará em {seconds} segundos.", - "feature.shareFranz.action.email" : "Send as email", - "feature.shareFranz.action.facebook" : "Share on Facebook", - "feature.shareFranz.action.twitter" : "Share on Twitter", - "feature.shareFranz.headline" : "Franz is better together!", - "feature.shareFranz.shareText.email" : "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com", - "feature.shareFranz.shareText.twitter" : "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com \/cc @MeetFranz", - "feature.shareFranz.text" : "Tell your friends and colleagues how awesome Franz is and help us to spread the word.", + "feature.shareFranz.action.email" : "Enviar como e-mail", + "feature.shareFranz.action.facebook" : "Compartilhar no Facebook", + "feature.shareFranz.action.twitter" : "Compartilhar no Twitter", + "feature.shareFranz.headline" : "Franz é melhor em grupo!", + "feature.shareFranz.shareText.email" : "Eu adicionei {count} serviços ao Franz! Adquira o aplicativo gratuito para WhatsApp, Messenger, Slack, Skype e mais em www.meetfranz.com", + "feature.shareFranz.shareText.twitter" : "Adicionei o serviço de {count} ao Franz! Adquira o app grátis para usar WhatsApp, Messenger, Slack, Skype e mais em www.meetfranz.com \/cc @MeetFranz", + "feature.shareFranz.text" : "Conte aos seus amigos e colegas o quão incrível Franz é e nos ajude a espalhar a mensagem. ", "global.api.unhealthy" : "Não foi possível conectar-se aos serviços on-line do Franz.", "global.notConnectedToTheInternet" : "Você não está conectado à internet", "global.spellchecker.useDefault" : "Use o padrão do sistema ({default})", - "global.spellchecking.autodetect" : "Detect language automatically", - "global.spellchecking.autodetect.short" : "Automatic", + "global.spellchecking.autodetect" : "Detectar linguagem automaticamente.", + "global.spellchecking.autodetect.short" : "Automático", "global.spellchecking.language" : "Idioma de verificação ortográfica", "import.headline" : "Importe seus serviços do Franz 4 ", "import.notSupportedHeadline" : "Serviços ainda não suportados pelo Franz 5 ", @@ -70,7 +70,9 @@ "menu.help.support" : "Suporte", "menu.help.tos" : "Termos de Serviço", "menu.services" : "Serviços", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Adicionar Novo Serviço", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Visualizar ", "menu.view.enterFullScreen" : "Modo Tela Cheia", "menu.view.exitFullScreen" : "Sair da Tela Cheia", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Baixar", "settings.account.manageSubscription.label" : "Gerencie a sua assinatura", "settings.account.successInfo" : "Suas alterações foram gravadas", + "settings.account.tryReloadServices" : "Tente novamente", "settings.account.tryReloadUserInfoRequest" : "Tente novamente", "settings.account.userInfoRequestFailed" : "Não foi possível carregar as informações do usuário", "settings.app.buttonClearAllCache" : "Limpar cache", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Incluir versões beta", "settings.app.form.darkMode" : "Venha para o Lado Negro da força", "settings.app.form.enableGPUAcceleration" : "Ativar Aceleração de GPU", - "settings.app.form.enableMenuBar" : "Mostrar Franz na Barra de Menu", "settings.app.form.enableSpellchecking" : "Ativar correção ortográfica", "settings.app.form.enableSystemTray" : "Exibir o Franz na barra de sistema", - "settings.app.form.hideDockIcon" : "Ocultar ícone do Franz no Dock", "settings.app.form.language" : "Idioma", "settings.app.form.minimizeToSystemTray" : "Minimizar o Franz para a área de sistema", "settings.app.form.runInBackground" : "Manter o Franz no fundo quando fechar a janela", "settings.app.form.showDisabledServices" : "Mostrar abas de serviços desativados", "settings.app.form.showMessagesBadgesWhenMuted" : "Mostrar ícone de mensagem não lida quando as notificações estiverem desativadas", - "settings.app.form.spellcheckerLanguage" : "Idioma de verificação ortográfica", "settings.app.headline" : "Configurações", "settings.app.headlineAdvanced" : "Avançado", "settings.app.headlineAppearance" : "Aparência", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Por favor, reinicie o Franz após alterar as configurações de proxy.", "settings.service.form.proxy.user" : "Usuário (opcional)", "settings.service.form.saveButton" : "Salvar serviço", - "settings.service.form.spellcheckerLanguage" : "Língua do corretor ortográfico", - "settings.service.form.spellcheckerLanguage.default" : "Use o padrão do sistema ({default})", "settings.service.form.tabHosted" : "Hospedado", "settings.service.form.tabOnPremise" : "Auto-hospedado ⭐️", "settings.service.form.team" : "Equipe", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Descobrir serviços", "settings.services.headline" : "Seus serviços", "settings.services.noServicesAdded" : "Você ainda não adicionou nenhum serviço.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "O serviço está desativado", "settings.services.tooltip.isMuted" : "Sem som", "settings.services.tooltip.notificationsDisabled" : "Notificações desativadas", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Residentes na União Europeia: taxas locais serão aplicadas", "subscription.features.ads" : "Sem anúncios, pra sempre!", "subscription.features.comingSoon" : "em breve", - "subscription.features.encryptedSync" : "Sincronização encriptada das sessões", "subscription.features.noInterruptions" : "Sem demora e sem chateação para comprar uma licença. ", - "subscription.features.onpremise" : "Adicionar serviços locais\/hospedados como o HipChat", "subscription.features.onpremise.mattermost" : "Adicionar serviços locais\/hospedados como o Mattermost", "subscription.features.proxy" : "Suporte de proxy para serviços", "subscription.features.spellchecker" : "Suporte para corretor ortográfico", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Recarregar", "validation.email" : "inválido", "validation.minLength" : "{campo} deve ter pelo menos {comprimento} mais caracteres ", + "validation.oneRequired" : "At least one is required", "validation.required" : "{campo} obrigatório", "validation.url" : "{campo} essa URL não é válida", "welcome.loginButton" : "Entrar na sua conta", - "welcome.signupButton" : "Criar uma conta grátis", - "welcome.slogan" : "Mensagens que funcionam para você" + "welcome.signupButton" : "Criar uma conta grátis" } diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 9e7455bdf..7e23aa0ba 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -70,7 +70,9 @@ "menu.help.support" : "Suporte", "menu.help.tos" : "Termos do Serviço", "menu.services" : "Serviços", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Adicionar Novo Serviço...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Ver", "menu.view.enterFullScreen" : "Ativar Modo de Ecrã Completo", "menu.view.exitFullScreen" : "Sair do Modo de Ecrã Completo", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Transferir", "settings.account.manageSubscription.label" : "Gerir as minhas subscrições", "settings.account.successInfo" : "As suas alterações foram efetuadas com sucesso", + "settings.account.tryReloadServices" : "Tentar novamente", "settings.account.tryReloadUserInfoRequest" : "Tentar novamente", "settings.account.userInfoRequestFailed" : "Não é possível carregar a informação do utilizador", "settings.app.buttonClearAllCache" : "Limpar cache", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Incluir versões instáveis (beta)", "settings.app.form.darkMode" : "Junta-te ao Lado Negro", "settings.app.form.enableGPUAcceleration" : "Activar Aceleração de GPU", - "settings.app.form.enableMenuBar" : "Mostrar Franz na Barra de Menu", "settings.app.form.enableSpellchecking" : "Ativar verificação ortográfica", "settings.app.form.enableSystemTray" : "Mostrar o Franz na barra do sistema", - "settings.app.form.hideDockIcon" : "Esconder ícone na Dock", "settings.app.form.language" : "Idioma", "settings.app.form.minimizeToSystemTray" : "Minimizar o Franz para a barra do sistema", "settings.app.form.runInBackground" : "Manter o Franz em segundo plano ao fechar a janela", "settings.app.form.showDisabledServices" : "Apresentar separadores de serviços desativados", "settings.app.form.showMessagesBadgesWhenMuted" : "Apresentar emblema com o número de mensagens não lidas quando as notificações estão desativadas", - "settings.app.form.spellcheckerLanguage" : "Linguagem para correção ortográfica", "settings.app.headline" : "Definições", "settings.app.headlineAdvanced" : "Avançado", "settings.app.headlineAppearance" : "Aparência", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Reinicie, por favor, após atualizar as definições do Franz", "settings.service.form.proxy.user" : "Utilizador (opcional)", "settings.service.form.saveButton" : "Guardar serviço", - "settings.service.form.spellcheckerLanguage" : "Linguagem de correção ortográfica", - "settings.service.form.spellcheckerLanguage.default" : "Utilizar o Sistema por Omissão ({default})", "settings.service.form.tabHosted" : "Com domínio", "settings.service.form.tabOnPremise" : "Com domínio próprio ⭐️", "settings.service.form.team" : "Equipa", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Descobrir serviços", "settings.services.headline" : "Os seus serviços", "settings.services.noServicesAdded" : "Ainda não adicionou nenhum serviço.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "O serviço está desativado", "settings.services.tooltip.isMuted" : "Todos os sons estão silenciados", "settings.services.tooltip.notificationsDisabled" : "As notificações estão desativadas", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Residentes EU: Taxas locais podem ser aplicadas", "subscription.features.ads" : "Sem anúncios, para sempre!", "subscription.features.comingSoon" : "em breve", - "subscription.features.encryptedSync" : "Sincronização encriptada de sessão", "subscription.features.noInterruptions" : "Sem atrasos na aplicação nem mensagens para comprar uma licença", - "subscription.features.onpremise" : "Adicionar serviços 'on-premise'\/hosted como o HipChat", "subscription.features.onpremise.mattermost" : "Adicione serviços como Mattermost no local ou online", "subscription.features.proxy" : "Suporte Proxy para os serviços", "subscription.features.spellchecker" : "Suporte para correção ortográfica", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Recarregar", "validation.email" : "{field} não é válido", "validation.minLength" : "{field} deveria ter pelo menos {length} caracteres", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} é obrigatório", "validation.url" : "{field} não é uma hiperligação válida", "welcome.loginButton" : "Iniciar sessão", - "welcome.signupButton" : "Criar uma conta gratuita", - "welcome.slogan" : "Sistema de mensagens feito para si" + "welcome.signupButton" : "Criar uma conta gratuita" } diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 6098c8ad9..d8e02b7f3 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -69,8 +69,10 @@ "menu.help.privacy" : "Политика конфиденциальности", "menu.help.support" : "Поддержка", "menu.help.tos" : "Условия использования", - "menu.services" : "Сервисы", + "menu.services" : "Сервис", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Добавить новый сервис...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Вид", "menu.view.enterFullScreen" : "На весь экран", "menu.view.exitFullScreen" : "В окне", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Скачать", "settings.account.manageSubscription.label" : "Управление вашей подпиской", "settings.account.successInfo" : "Ваши изменения были сохранены", + "settings.account.tryReloadServices" : "Попробовать снова", "settings.account.tryReloadUserInfoRequest" : "Попробовать снова", "settings.account.userInfoRequestFailed" : "Невозможно загрузить информацию пользователя", "settings.app.buttonClearAllCache" : "Очистить кэш", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Включая бета версии", "settings.app.form.darkMode" : "Перейти на Тёмную сторону", "settings.app.form.enableGPUAcceleration" : "Включить ускорение GPU", - "settings.app.form.enableMenuBar" : "Показывать Franz на панели меню", "settings.app.form.enableSpellchecking" : "Включить проверку правописания", "settings.app.form.enableSystemTray" : "Показывать Franz в системном трее", - "settings.app.form.hideDockIcon" : "Спрятать иконку Franz на панели", "settings.app.form.language" : "Язык", "settings.app.form.minimizeToSystemTray" : "Сворачивать Franz в системный трей", "settings.app.form.runInBackground" : "Оставлять Franz в фоне при закрытии окна", "settings.app.form.showDisabledServices" : "Показывать вкладки отключённых служб", "settings.app.form.showMessagesBadgesWhenMuted" : "Показывать значок непрочитанного сообщения при отключённых уведомлениях", - "settings.app.form.spellcheckerLanguage" : "Проверка правописания", "settings.app.headline" : "Настройки", "settings.app.headlineAdvanced" : "Дополнительно", "settings.app.headlineAppearance" : "Внешний вид", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Пожалуйста перезапустите Franz после изменения настроек прокси.", "settings.service.form.proxy.user" : "Пользователь (опционально)", "settings.service.form.saveButton" : "Сохранить сервис", - "settings.service.form.spellcheckerLanguage" : "Проверка правописания", - "settings.service.form.spellcheckerLanguage.default" : "Использовать системные параметры по умолчанию ({default})", "settings.service.form.tabHosted" : "Размещено", "settings.service.form.tabOnPremise" : "Свой хостинг ⭐️", "settings.service.form.team" : "Команда", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Найти сервисы", "settings.services.headline" : "Ваши сервисы", "settings.services.noServicesAdded" : "Вы пока не добавили никаких сервисов.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Сервис отключен", "settings.services.tooltip.isMuted" : "Все звуки отключены", "settings.services.tooltip.notificationsDisabled" : "Уведомления отключены", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Резидентам ЕвроСоюза: могут применяться местные налоги", "subscription.features.ads" : "Без рекламы, навсегда!", "subscription.features.comingSoon" : "скоро", - "subscription.features.encryptedSync" : "Зашифрованные сессии синхронизации", "subscription.features.noInterruptions" : "Никаких задержек и предложений перейти на платную версию", - "subscription.features.onpremise" : "Добавление облачных служб или служб на своём хостинге типа HipChat", "subscription.features.onpremise.mattermost" : "Локальные\/размещенные на хостинге сервисы, такие как Mattermost", "subscription.features.proxy" : "Подержка прокси для сервисов", "subscription.features.spellchecker" : "Поддержка проверки правописания", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Перезагрузить", "validation.email" : "{field} недействительно", "validation.minLength" : "{field} должно быть не менее {length} символов", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} обязательно", "validation.url" : "{field} является недействительной ссылкой", "welcome.loginButton" : "Вход", - "welcome.signupButton" : "Создать бесплатный аккаунт", - "welcome.slogan" : "Общение, которое работает для вас" + "welcome.signupButton" : "Создать бесплатный аккаунт" } diff --git a/src/i18n/locales/sk.json b/src/i18n/locales/sk.json index 35c699322..688490b58 100644 --- a/src/i18n/locales/sk.json +++ b/src/i18n/locales/sk.json @@ -70,7 +70,9 @@ "menu.help.support" : "Podpora", "menu.help.tos" : "Podmienky použitia", "menu.services" : "Služby", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Pridať novú službu...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Zobraziť", "menu.view.enterFullScreen" : "Na celú obrazovku", "menu.view.exitFullScreen" : "Ukončiť režim na celú obrazovku", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Prevziať", "settings.account.manageSubscription.label" : "Spravovať vaše odoberanie", "settings.account.successInfo" : "Vaše zmeny boli uložené", + "settings.account.tryReloadServices" : "Skúsiť znova", "settings.account.tryReloadUserInfoRequest" : "Skúsiť znova", "settings.account.userInfoRequestFailed" : "Nebolo možné načítať informácie o používateľovi", "settings.app.buttonClearAllCache" : "Vyčistiť vyrovnávaciu pamäť", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Vrátane beta verzií", "settings.app.form.darkMode" : "Join the Dark Side", "settings.app.form.enableGPUAcceleration" : "Zapnúť GPU zrýchlenie", - "settings.app.form.enableMenuBar" : "Zobraziť Franz v ponuke menu", "settings.app.form.enableSpellchecking" : "Zapnúť kontrolu pravopisu", "settings.app.form.enableSystemTray" : "Zobrazovať Franz v systémovej lište", - "settings.app.form.hideDockIcon" : "Skryť ikonu Franz v doku", "settings.app.form.language" : "Jazyk", "settings.app.form.minimizeToSystemTray" : "Minimalizovať Franz do systémovej lišty", "settings.app.form.runInBackground" : "Po zatvorení okna ponechať Franz spustený na pozadí", "settings.app.form.showDisabledServices" : "Zobraziť záložky vypnutých služieb", "settings.app.form.showMessagesBadgesWhenMuted" : "Zobraziť symbol pre neprečítané správy, keď sú vypnuté upozornenia", - "settings.app.form.spellcheckerLanguage" : "Spell checking language", "settings.app.headline" : "Nastavenia", "settings.app.headlineAdvanced" : "Pokročilé", "settings.app.headlineAppearance" : "Vzhľad", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Please restart Franz after changing proxy Settings.", "settings.service.form.proxy.user" : "User (optional)", "settings.service.form.saveButton" : "Uložiť službu", - "settings.service.form.spellcheckerLanguage" : "Spell checking Language", - "settings.service.form.spellcheckerLanguage.default" : "Use System Default ({default})", "settings.service.form.tabHosted" : "Hostované", "settings.service.form.tabOnPremise" : "Vlastné hostovanie ⭐️", "settings.service.form.team" : "Tím", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Preskúmať služby", "settings.services.headline" : "Vaše služby", "settings.services.noServicesAdded" : "Doposiaľ ste nepridali žiadne služby.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Služba je vypnutá", "settings.services.tooltip.isMuted" : "Všetky zvuky sú stíšené", "settings.services.tooltip.notificationsDisabled" : "Oznámenia sú vypnuté", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Pre obyvateľov EÚ: môže byť aplikovaná miestna daň", "subscription.features.ads" : "Žiadne reklamy, nikdy!", "subscription.features.comingSoon" : "už čoskoro", - "subscription.features.encryptedSync" : "Šifrovaná synchronizácia relácie", "subscription.features.noInterruptions" : "No app delays & nagging to upgrade license", - "subscription.features.onpremise" : "Pridať lokálne hostované služby, ako napr. HipChat", "subscription.features.onpremise.mattermost" : "Add on-premise\/hosted services like Mattermost", "subscription.features.proxy" : "Proxy support for services", "subscription.features.spellchecker" : "Support for spellchecker", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Obnoviť", "validation.email" : "{field} je neplatný", "validation.minLength" : "{field} by malo byť dlhé aspoň {length} znakov", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} je povinné", "validation.url" : "{field} nie je platné URL", "welcome.loginButton" : "Prihlásiť sa do vášho účtu", - "welcome.signupButton" : "Vytvoriť účet zdarma", - "welcome.slogan" : "Správy, ktoré pracujú pre vás" + "welcome.signupButton" : "Vytvoriť účet zdarma" } diff --git a/src/i18n/locales/sr.json b/src/i18n/locales/sr.json index 8ffc0c007..a3a80925d 100644 --- a/src/i18n/locales/sr.json +++ b/src/i18n/locales/sr.json @@ -70,7 +70,9 @@ "menu.help.support" : "Подршка", "menu.help.tos" : "Услови коришћења услуге", "menu.services" : "Usluge", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Додај нову услугу", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Преглед", "menu.view.enterFullScreen" : "Отвори у целом екрану", "menu.view.exitFullScreen" : "Напусти цео екран", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Preuzmite", "settings.account.manageSubscription.label" : "Upravljajte pretplatama", "settings.account.successInfo" : "Vaše promjene su spremljene", + "settings.account.tryReloadServices" : "Pokušajte ponovno", "settings.account.tryReloadUserInfoRequest" : "Pokušajte ponovno", "settings.account.userInfoRequestFailed" : "Nije moguće učitati informacije o korisniku", "settings.app.buttonClearAllCache" : "Очисти кеш", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Obuhvati i beta verzije", "settings.app.form.darkMode" : "Join the Dark Side", "settings.app.form.enableGPUAcceleration" : "Омогући убрзање графичке јединице", - "settings.app.form.enableMenuBar" : "Покажи Франз у менију", "settings.app.form.enableSpellchecking" : "Omogući provjeru pravopisa", "settings.app.form.enableSystemTray" : "Prikaži aplikaciju u sustavskoj traci", - "settings.app.form.hideDockIcon" : "Сакриј Франз иконицу у доку", "settings.app.form.language" : "Jezik", "settings.app.form.minimizeToSystemTray" : "Smanji Franca u sustavsku traku", "settings.app.form.runInBackground" : "Neka se Franc održava u pozadini i ako je prozor zatvoren", "settings.app.form.showDisabledServices" : "Prikaži ploče s onemogućenim servisima", "settings.app.form.showMessagesBadgesWhenMuted" : "Покажи беџ за непрочитане поруке када су обавештења онемогућена", - "settings.app.form.spellcheckerLanguage" : "Spell checking language", "settings.app.headline" : "Подешавања", "settings.app.headlineAdvanced" : "Napredne alatke", "settings.app.headlineAppearance" : "Izgled", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Please restart Franz after changing proxy Settings.", "settings.service.form.proxy.user" : "User (optional)", "settings.service.form.saveButton" : "Sačuvaj uslugu\/e", - "settings.service.form.spellcheckerLanguage" : "Spell checking Language", - "settings.service.form.spellcheckerLanguage.default" : "Use System Default ({default})", "settings.service.form.tabHosted" : "Hostovano", "settings.service.form.tabOnPremise" : "Samo-hostovano ⭐️", "settings.service.form.team" : "Tim", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Pronađite usluge", "settings.services.headline" : "Vaše usluge", "settings.services.noServicesAdded" : "Još uvijek niste unijeli niti jednu uslugu.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Usluga je onemogućena.", "settings.services.tooltip.isMuted" : "Svi zvukovi su onemogućeni.", "settings.services.tooltip.notificationsDisabled" : "Obavijesti su onemogućene.", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "EU državljani, upozerenje: Moguće taksiranje", "subscription.features.ads" : "Bez reklama, doživotno!", "subscription.features.comingSoon" : "Dolazi uskoro", - "subscription.features.encryptedSync" : "Kodirano usklađivanje sesija.", "subscription.features.noInterruptions" : "No app delays & nagging to upgrade license", - "subscription.features.onpremise" : "Dodajte pretpostavljeni\/hostirani servis kao što ima usluga HipChat", "subscription.features.onpremise.mattermost" : "Add on-premise\/hosted services like Mattermost", "subscription.features.proxy" : "Proxy support for services", "subscription.features.spellchecker" : "Support for spellchecker", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Ponovno učitavanje", "validation.email" : "{поље} није валидно", "validation.minLength" : "{поље} треба да буде најмање {дужина} карактера дугачко", + "validation.oneRequired" : "At least one is required", "validation.required" : "{поље} је неопходно", "validation.url" : "{field} није валидан УРЛ", "welcome.loginButton" : "Prijavite se na račun", - "welcome.signupButton" : "Stvorite novi korisnički račun", - "welcome.slogan" : "Poruke koje su stvorene za tebe" + "welcome.signupButton" : "Stvorite novi korisnički račun" } diff --git a/src/i18n/locales/tr.json b/src/i18n/locales/tr.json index 70632b966..9f8313c2e 100644 --- a/src/i18n/locales/tr.json +++ b/src/i18n/locales/tr.json @@ -4,18 +4,18 @@ "feature.delayApp.action" : "Franz Destek Lisansı'nı alın", "feature.delayApp.headline" : "Beklememek için Franz Destek Lisansı'nı satın alın", "feature.delayApp.text" : "Franz {seconds} saniye sonra devam edecek.", - "feature.shareFranz.action.email" : "Send as email", - "feature.shareFranz.action.facebook" : "Share on Facebook", - "feature.shareFranz.action.twitter" : "Share on Twitter", - "feature.shareFranz.headline" : "Franz is better together!", - "feature.shareFranz.shareText.email" : "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com", - "feature.shareFranz.shareText.twitter" : "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com \/cc @MeetFranz", - "feature.shareFranz.text" : "Tell your friends and colleagues how awesome Franz is and help us to spread the word.", + "feature.shareFranz.action.email" : "Mail olarak gönder", + "feature.shareFranz.action.facebook" : "Facebook'ta Paylaş", + "feature.shareFranz.action.twitter" : "Twitter'da Paylaş", + "feature.shareFranz.headline" : "Franz birlikte daha iyi!", + "feature.shareFranz.shareText.email" : "Franz'a {count} tane servis ekledim! WhatsApp, Messenger, Slack ve fazlasını içeren ücretsiz uygulamayı www.meetfranz.com adresinden edinin.", + "feature.shareFranz.shareText.twitter" : "Franz'a {count} tane servis ekledim! WhatsApp, Messenger, Slack ve fazlasını içeren ücretsiz uygulamayı www.meetfranz.com adresinden edinin. \/cc @MeetFranz", + "feature.shareFranz.text" : "Arkadaşlarına ve meslektaşlarına Franz'ın ne kadar harika olduğunu söyle ve bize bu kelimeyi yaymamızda yardım et.", "global.api.unhealthy" : "Franz hizmetlerine şu anda erişilemiyor", "global.notConnectedToTheInternet" : "İnternete bağlı değilsiniz.", "global.spellchecker.useDefault" : "Sistem Dilini Kullan ({default})", - "global.spellchecking.autodetect" : "Detect language automatically", - "global.spellchecking.autodetect.short" : "Automatic", + "global.spellchecking.autodetect" : "Dili otomatik tespit et", + "global.spellchecking.autodetect.short" : "Otomatik", "global.spellchecking.language" : "İmla kontrol dili", "import.headline" : "Franz 4 servislerinizi içeri aktarın", "import.notSupportedHeadline" : "Henüz Franz 5'te desteklenmeyen servisler", @@ -70,7 +70,9 @@ "menu.help.support" : "Destek", "menu.help.tos" : "Kullanım Şartları", "menu.services" : "Hizmetler", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Yeni servis ekle...", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Görünüm", "menu.view.enterFullScreen" : "Tam Ekrana Geç", "menu.view.exitFullScreen" : "Tam Ekrandan Çık", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "İndir", "settings.account.manageSubscription.label" : "Aboneliğini yönet", "settings.account.successInfo" : "Değişikliklerin kaydedildi", + "settings.account.tryReloadServices" : "Tekrar deneyin", "settings.account.tryReloadUserInfoRequest" : "Tekrar deneyin", "settings.account.userInfoRequestFailed" : "Kullanıcı bilgisi yüklenemedi", "settings.app.buttonClearAllCache" : "Önbelleği temizle", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Beta versiyonları dahil et", "settings.app.form.darkMode" : "Karanlık tarafa katıl", "settings.app.form.enableGPUAcceleration" : "Grafik İşlemci Ünitesi (GPU) Hızlandırıcısını Aktif et", - "settings.app.form.enableMenuBar" : "Menü çubuğunda Franz'ı göster", "settings.app.form.enableSpellchecking" : "Yazım denetimini etkinleştir", "settings.app.form.enableSystemTray" : "Franz'ı sistem tepsisinde göster", - "settings.app.form.hideDockIcon" : "Franz Simgesini Gösterme", "settings.app.form.language" : "Dil", "settings.app.form.minimizeToSystemTray" : "Franz'ı sistem tepsisine küçült", "settings.app.form.runInBackground" : "Pencereyi kapatırken Franz'ı arka planda tut", "settings.app.form.showDisabledServices" : "Devre dışı bırakılan servis sekmelerini göster", "settings.app.form.showMessagesBadgesWhenMuted" : "Bildirimler kapalı iken okunmamış mesaj sayısını göster", - "settings.app.form.spellcheckerLanguage" : "İmla kontrol dili", "settings.app.headline" : "Ayarlar", "settings.app.headlineAdvanced" : "Gelişmiş", "settings.app.headlineAppearance" : "Görünüm", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Proxy ayarlarını değiştirdikten sonra Franz'ı yeniden başlatınız.", "settings.service.form.proxy.user" : "Kullanıcı (opsiyonel)", "settings.service.form.saveButton" : "Servisi kaydet", - "settings.service.form.spellcheckerLanguage" : "İmla kontrol dili", - "settings.service.form.spellcheckerLanguage.default" : "Sistem Dilini Kullan ({default})", "settings.service.form.tabHosted" : "Barındırılan", "settings.service.form.tabOnPremise" : "Kendi barındırılan", "settings.service.form.team" : "Takım", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Servisleri keşfet", "settings.services.headline" : "Servislerin", "settings.services.noServicesAdded" : "Henüz hiç servis eklemedin.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Servis devre dışı", "settings.services.tooltip.isMuted" : "Tüm sesler kapalı", "settings.services.tooltip.notificationsDisabled" : "Bildirimler devre dışı", @@ -255,11 +254,9 @@ "subscription.euTaxInfo" : "AB vatandaşları: yerel satış vergileri uygulanabilir", "subscription.features.ads" : "Reklam yok, asla!", "subscription.features.comingSoon" : "yakında geliyor", - "subscription.features.encryptedSync" : "Şifreli oturum senkronizasyonu", - "subscription.features.noInterruptions" : "No app delays & nagging to upgrade license", - "subscription.features.onpremise" : "HipChat gibi kurum içi\/barındırılan hizmetler ekle", - "subscription.features.onpremise.mattermost" : "Add on-premise\/hosted services like Mattermost", - "subscription.features.proxy" : "Proxy support for services", + "subscription.features.noInterruptions" : "Uygulama gecikmeleri & yükseltme lisanları için dırdır yok", + "subscription.features.onpremise.mattermost" : "Mattermost gibi şirket-içi\/barındırılan servisler ekleyin", + "subscription.features.proxy" : "Servisler için proxy desteği", "subscription.features.spellchecker" : "Yazım denetleyicisi desteği", "subscription.includedFeatures" : "Ücretli Franz Premium Destekçi Hesabına dahil", "subscription.paymentSessionError" : "Ödeme formu başlatılamadı", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Tekrar yükle", "validation.email" : "{alan} geçerli değil", "validation.minLength" : "{field} en az {length} karakter uzunluğunda olmalı", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} gereklidir", "validation.url" : "{field} geçerli bir URL değil", "welcome.loginButton" : "Hesabına giriş yap", - "welcome.signupButton" : "Ücretsiz hesap oluştur", - "welcome.slogan" : "Sizin için çalışan mesajlaşma" + "welcome.signupButton" : "Ücretsiz hesap oluştur" } diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index db3145b36..56dda09d5 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -70,7 +70,9 @@ "menu.help.support" : "Підтримка", "menu.help.tos" : "Умови використання", "menu.services" : "Служби", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "Додати сервіс", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "Вигляд", "menu.view.enterFullScreen" : "Вікно на повний екран", "menu.view.exitFullScreen" : "Вийти з повного екрану", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "Завантажити", "settings.account.manageSubscription.label" : "Керування вашою підпискою", "settings.account.successInfo" : "Ваші зміни були збережені", + "settings.account.tryReloadServices" : "Спробуйте ще раз", "settings.account.tryReloadUserInfoRequest" : "Спробуйте ще раз", "settings.account.userInfoRequestFailed" : "Не вдалося завантажити інформацію користувача", "settings.app.buttonClearAllCache" : "Очистити кеш", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "Включити бета-версії", "settings.app.form.darkMode" : "Переходь на Темну Сторону", "settings.app.form.enableGPUAcceleration" : "Ввімкнути прискорення GPU", - "settings.app.form.enableMenuBar" : "Відображати Franz в панелі головного меню", "settings.app.form.enableSpellchecking" : "Увімкнути перевірку орфографії", "settings.app.form.enableSystemTray" : "Показувати Franz у системному лотку", - "settings.app.form.hideDockIcon" : "Сховати значок Franz в Dock", "settings.app.form.language" : "Мова", "settings.app.form.minimizeToSystemTray" : "Мінімізувати Franz до системного лотка", "settings.app.form.runInBackground" : "Тримати Franz в фоні при закритті вікна", "settings.app.form.showDisabledServices" : "Показати вкладку вимкнених сервісів", "settings.app.form.showMessagesBadgesWhenMuted" : "Показувати значок непрочитаних повідомлень коли сповіщення вимкнені", - "settings.app.form.spellcheckerLanguage" : "Мова перевірки правопису", "settings.app.headline" : "Налаштування", "settings.app.headlineAdvanced" : "Додаткові налаштування", "settings.app.headlineAppearance" : "Вигляд", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "Будь ласка, перезапустіть Franz після зміни налуштувань проксі", "settings.service.form.proxy.user" : "Користувач (опційно)", "settings.service.form.saveButton" : "Зберегти сервіс", - "settings.service.form.spellcheckerLanguage" : "Мова перевірки правопису", - "settings.service.form.spellcheckerLanguage.default" : "Використовувати системні параметри за змовчуванням ({default})", "settings.service.form.tabHosted" : "Розміщений", "settings.service.form.tabOnPremise" : "Самостійно розміщений ⭐️", "settings.service.form.team" : "Команда", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "Відкрийте для себе сервіси", "settings.services.headline" : "Ваші сервіси", "settings.services.noServicesAdded" : "Ви ще не додавали жодних сервісів.", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "Сервіс відключений", "settings.services.tooltip.isMuted" : "Всі звуки вимкнено", "settings.services.tooltip.notificationsDisabled" : "Сповіщення відключені", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "Для жителів ЄС: можуть застосовуватися податки", "subscription.features.ads" : "Жодної реклами!", "subscription.features.comingSoon" : "очікуйте незабаром", - "subscription.features.encryptedSync" : "Шифрована синхронізація сеансу", "subscription.features.noInterruptions" : "Ніяких затримок та набридливих пропозицій з платних підписок", - "subscription.features.onpremise" : "Додайте on-premise \/ hosted сервіси, такі як Hipchat", "subscription.features.onpremise.mattermost" : "Сервіси, що виконуються локально\/вимагають хостингу, приміром Mattermost", "subscription.features.proxy" : "Підтримка проксі ", "subscription.features.spellchecker" : "Підтримка перевірки правопису", @@ -280,9 +277,9 @@ "tabs.item.reload" : "Перезавантажити", "validation.email" : "{field} не валідне", "validation.minLength" : "Кількість символів в {field} повина бути не меньше {length} ", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field} обов'язвоке", "validation.url" : "{field} не валідний URL", "welcome.loginButton" : "Увійдіть до свого акаунту", - "welcome.signupButton" : "Створити безплатний акаунт", - "welcome.slogan" : "Обмін повідомленнями, який працює для вас" + "welcome.signupButton" : "Створити безплатний акаунт" } diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json index 3ae08c9ef..54245ba57 100644 --- a/src/i18n/locales/zh-TW.json +++ b/src/i18n/locales/zh-TW.json @@ -70,7 +70,9 @@ "menu.help.support" : "支援", "menu.help.tos" : "服務條款", "menu.services" : "服務", + "menu.services.activatePreviousService" : "Activate previous service", "menu.services.addNewService" : "新增服務", + "menu.services.setNextServiceActive" : "Activate next service", "menu.view" : "檢視", "menu.view.enterFullScreen" : "進入全螢幕模式", "menu.view.exitFullScreen" : "離開全螢幕模式", @@ -128,6 +130,7 @@ "settings.account.invoiceDownload" : "下載", "settings.account.manageSubscription.label" : "管理您的訂閱", "settings.account.successInfo" : "您的更變已經被儲存", + "settings.account.tryReloadServices" : "再試一次", "settings.account.tryReloadUserInfoRequest" : "再試一次", "settings.account.userInfoRequestFailed" : "無法載入使用者資訊。", "settings.app.buttonClearAllCache" : "清除快取", @@ -140,16 +143,13 @@ "settings.app.form.beta" : "包含測試版", "settings.app.form.darkMode" : "加入黑暗面", "settings.app.form.enableGPUAcceleration" : "啟用 GPU 加速", - "settings.app.form.enableMenuBar" : "在選單列顯示 Franz", "settings.app.form.enableSpellchecking" : "啟用拼字檢查", "settings.app.form.enableSystemTray" : "在系統列顯示 Franz", - "settings.app.form.hideDockIcon" : "隱藏 Dock 中的 Franz 圖示", "settings.app.form.language" : "語言", "settings.app.form.minimizeToSystemTray" : "最小化 Franz 到系統列", "settings.app.form.runInBackground" : "當關閉視窗時,保持 Franz 在背景運作", "settings.app.form.showDisabledServices" : "顯示停用的服務標籤", "settings.app.form.showMessagesBadgesWhenMuted" : "當通知關閉時,標記未讀的訊息", - "settings.app.form.spellcheckerLanguage" : "拼字檢查語言", "settings.app.headline" : "設定", "settings.app.headlineAdvanced" : "進階", "settings.app.headlineAppearance" : "外觀", @@ -212,8 +212,6 @@ "settings.service.form.proxy.restartInfo" : "在變更 Proxy 設定後,請重新啟動 Franz", "settings.service.form.proxy.user" : "使用者 (選填)", "settings.service.form.saveButton" : "保存服務", - "settings.service.form.spellcheckerLanguage" : "拼字檢查語言", - "settings.service.form.spellcheckerLanguage.default" : "使用系統預設 ({default})", "settings.service.form.tabHosted" : "託管", "settings.service.form.tabOnPremise" : "自我託管⭐️", "settings.service.form.team" : "團隊", @@ -223,6 +221,7 @@ "settings.services.discoverServices" : "發現服務", "settings.services.headline" : "您的服務", "settings.services.noServicesAdded" : "你尚未新增任何服務", + "settings.services.servicesRequestFailed" : "Could not load your services", "settings.services.tooltip.isDisabled" : "服務已停用", "settings.services.tooltip.isMuted" : "所有的聲音都是靜音", "settings.services.tooltip.notificationsDisabled" : "通知已停用", @@ -255,9 +254,7 @@ "subscription.euTaxInfo" : "歐盟居民:可能採用當地銷售稅", "subscription.features.ads" : "無廣告,永遠!", "subscription.features.comingSoon" : "即將推出", - "subscription.features.encryptedSync" : "加密的會話同步", "subscription.features.noInterruptions" : "升級授權沒有延遲與打盹", - "subscription.features.onpremise" : "添加本地\/託管服務如HipChat", "subscription.features.onpremise.mattermost" : "加入如 Mattermost 等已預定 \/ 託管的服務", "subscription.features.proxy" : "服務的代理伺服器支援", "subscription.features.spellchecker" : "支援拼字檢查", @@ -280,9 +277,9 @@ "tabs.item.reload" : "重新載入", "validation.email" : "{field}無效", "validation.minLength" : "{field}長度至少應為{length}個字", + "validation.oneRequired" : "At least one is required", "validation.required" : "{field}為必填", "validation.url" : "{field}不是個有效的網址", "welcome.loginButton" : "登入您的帳戶", - "welcome.signupButton" : "建立免費帳號", - "welcome.slogan" : "為你通信" + "welcome.signupButton" : "建立免費帳號" } -- cgit v1.2.3-54-g00ecf From 15ebfef32251790a62f50bc63029f36a26e4d4c3 Mon Sep 17 00:00:00 2001 From: FranzBot Date: Sun, 17 Mar 2019 21:30:41 +0000 Subject: Automatic i18n update (i18n.meetfranz.com) --- src/i18n/locales/de.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index adb466e18..2560a5add 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -70,9 +70,9 @@ "menu.help.support" : "Hilfe", "menu.help.tos" : "Nutzungsbedingungen", "menu.services" : "Dienste", - "menu.services.activatePreviousService" : "Activate previous service", + "menu.services.activatePreviousService" : "Vorheriger Dienst", "menu.services.addNewService" : "Dienst hinzufügen", - "menu.services.setNextServiceActive" : "Activate next service", + "menu.services.setNextServiceActive" : "Nächster Dienst", "menu.view" : "Darstellung", "menu.view.enterFullScreen" : "Vollbildmodus", "menu.view.exitFullScreen" : "Vollbildmodus aus", @@ -221,7 +221,7 @@ "settings.services.discoverServices" : "Dienste entdecken", "settings.services.headline" : "Deine Dienste", "settings.services.noServicesAdded" : "Du hast noch keine Dienste hinzugefügt.", - "settings.services.servicesRequestFailed" : "Could not load your services", + "settings.services.servicesRequestFailed" : "Dienste konnten nicht geladen werden", "settings.services.tooltip.isDisabled" : "Dienst ist deaktiviert", "settings.services.tooltip.isMuted" : "Alle Töne sind deaktiviert", "settings.services.tooltip.notificationsDisabled" : "Benachrichtigungen deaktiviert", @@ -277,7 +277,7 @@ "tabs.item.reload" : "Neuladen", "validation.email" : "{field} ist ungültig", "validation.minLength" : "{field} muss mindestens {length} Zeichen enthalten", - "validation.oneRequired" : "At least one is required", + "validation.oneRequired" : "Mindestens ein Wert wird benötigt", "validation.required" : "{field} wird benötigt", "validation.url" : "{field} ist keine gültige URL", "welcome.loginButton" : "Bei Franz einloggen", -- cgit v1.2.3-54-g00ecf From e4f1862644d5921e2ee77078c10e16efa3e58c7b Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Tue, 19 Mar 2019 19:38:56 +0100 Subject: add workspace drawer --- packages/theme/src/themes/dark/index.ts | 9 +++ packages/theme/src/themes/default/index.ts | 10 +++ src/components/layout/AppLayout.js | 24 +++++- src/components/layout/Sidebar.js | 42 +++++++++- src/components/services/content/ServiceView.js | 1 + src/containers/layout/AppLayoutContainer.js | 14 ++++ src/features/workspaces/actions.js | 6 +- .../workspaces/components/WorkspaceDrawer.js | 94 ++++++++++++++++++++++ .../workspaces/components/WorkspaceDrawerItem.js | 88 ++++++++++++++++++++ src/features/workspaces/state.js | 1 + src/features/workspaces/store.js | 12 ++- src/i18n/locales/defaultMessages.json | 57 +++++++++++++ src/i18n/locales/en-US.json | 8 +- .../messages/src/components/layout/AppLayout.json | 24 +++--- .../messages/src/components/layout/Sidebar.json | 26 ++++++ .../workspaces/components/WorkspaceDrawer.json | 28 +++++++ src/lib/Menu.js | 4 +- src/styles/layout.scss | 12 ++- 18 files changed, 435 insertions(+), 25 deletions(-) create mode 100644 src/features/workspaces/components/WorkspaceDrawer.js create mode 100644 src/features/workspaces/components/WorkspaceDrawerItem.js create mode 100644 src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json (limited to 'src') diff --git a/packages/theme/src/themes/dark/index.ts b/packages/theme/src/themes/dark/index.ts index 3a56719b2..eaa552961 100644 --- a/packages/theme/src/themes/dark/index.ts +++ b/packages/theme/src/themes/dark/index.ts @@ -63,3 +63,12 @@ export const selectSearchColor = inputBackground; // Modal export const colorModalOverlayBackground = color(legacyStyles.darkThemeBlack).alpha(0.8).rgb().string(); + +// Workspace Drawer +export const workspaceDrawerBackground = color(colorBackground).lighten(0.3).hex(); +export const workspaceDrawerItemBorder = color(workspaceDrawerBackground).lighten(0.2).hex(); +export const workspaceDrawerItemActiveBackground = defaultStyles.brandPrimary; +export const workspaceDrawerNameColor = colorText; +export const workspaceDrawerNameActiveColor = 'white'; +export const workspaceDrawerServicesColor = color(colorText).darken(0.5).hex(); +export const workspaceDrawerServicesActiveColor = color(defaultStyles.brandPrimary).lighten(0.5).hex(); diff --git a/packages/theme/src/themes/default/index.ts b/packages/theme/src/themes/default/index.ts index 8a71e61cf..fc03b67de 100644 --- a/packages/theme/src/themes/default/index.ts +++ b/packages/theme/src/themes/default/index.ts @@ -140,3 +140,13 @@ export const badgeBorderRadius = 50; // Modal export const colorModalOverlayBackground = color('#000').alpha(0.5).rgb().string(); + +// Workspace Drawer +export const workspaceDrawerWidth = '220px'; +export const workspaceDrawerBackground = color(colorBackground).lighten(0.1).hex(); +export const workspaceDrawerItemActiveBackground = legacyStyles.themeGrayLightest; +export const workspaceDrawerItemBorder = color(workspaceDrawerBackground).darken(0.05).hex(); +export const workspaceDrawerNameColor = colorText; +export const workspaceDrawerNameActiveColor = colorText; +export const workspaceDrawerServicesColor = color(colorText).lighten(1.5).hex(); +export const workspaceDrawerServicesActiveColor = workspaceDrawerServicesColor; diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index 593149e72..e06192f87 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; import { defineMessages, intlShape } from 'react-intl'; import { TitleBar } from 'electron-react-titlebar'; +import injectSheet from 'react-jss'; import InfoBar from '../ui/InfoBar'; import { Component as DelayApp } from '../../features/delayApp'; @@ -13,6 +14,7 @@ import ErrorBoundary from '../util/ErrorBoundary'; // import globalMessages from '../../i18n/globalMessages'; import { isWindows } from '../../environment'; +import { workspacesState } from '../../features/workspaces/state'; function createMarkup(HTMLString) { return { __html: HTMLString }; @@ -45,10 +47,23 @@ const messages = defineMessages({ }, }); -export default @observer class AppLayout extends Component { +const styles = theme => ({ + appContent: { + width: `calc(100% + ${theme.workspaceDrawerWidth})`, + transition: 'transform 0.5s ease', + transform() { + return workspacesState.isWorkspaceDrawerOpen ? 'translateX(0)' : 'translateX(-220px)'; + }, + }, +}); + +@injectSheet(styles) @observer +class AppLayout extends Component { static propTypes = { + classes: PropTypes.object.isRequired, isFullScreen: PropTypes.bool.isRequired, sidebar: PropTypes.element.isRequired, + workspacesDrawer: PropTypes.element.isRequired, services: PropTypes.element.isRequired, children: PropTypes.element, news: MobxPropTypes.arrayOrObservableArray.isRequired, @@ -76,7 +91,9 @@ export default @observer class AppLayout extends Component { render() { const { + classes, isFullScreen, + workspacesDrawer, sidebar, services, children, @@ -102,7 +119,8 @@ export default @observer class AppLayout extends Component {
{isWindows && !isFullScreen && } -
+
+ {workspacesDrawer} {sidebar}
{news.length > 0 && news.map(item => ( @@ -176,3 +194,5 @@ export default @observer class AppLayout extends Component { ); } } + +export default AppLayout; diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index fcc5b0001..de379875e 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js @@ -24,6 +24,14 @@ const messages = defineMessages({ id: 'sidebar.unmuteApp', defaultMessage: '!!!Enable notifications & audio', }, + openWorkspaceDrawer: { + id: 'sidebar.openWorkspaceDrawer', + defaultMessage: '!!!Open workspace drawer', + }, + closeWorkspaceDrawer: { + id: 'sidebar.closeWorkspaceDrawer', + defaultMessage: '!!!Close workspace drawer', + }, }); export default @observer class Sidebar extends Component { @@ -31,6 +39,8 @@ export default @observer class Sidebar extends Component { openSettings: PropTypes.func.isRequired, toggleMuteApp: PropTypes.func.isRequired, isAppMuted: PropTypes.bool.isRequired, + isWorkspaceDrawerOpen: PropTypes.bool.isRequired, + toggleWorkspaceDrawer: PropTypes.func.isRequired, }; static contextTypes = { @@ -53,9 +63,23 @@ export default @observer class Sidebar extends Component { this.setState({ tooltipEnabled: false }); } + updateToolTip() { + this.disableToolTip(); + setTimeout(this.enableToolTip.bind(this)); + } + render() { - const { openSettings, toggleMuteApp, isAppMuted } = this.props; + const { + openSettings, + toggleMuteApp, + isAppMuted, + isWorkspaceDrawerOpen, + toggleWorkspaceDrawer, + } = this.props; const { intl } = this.context; + const workspaceToggleMessage = ( + isWorkspaceDrawerOpen ? messages.closeWorkspaceDrawer : messages.openWorkspaceDrawer + ); return (
@@ -66,7 +90,21 @@ export default @observer class Sidebar extends Component { /> +
diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js index 5fdea217e..89bd2a2ef 100644 --- a/src/features/workspaces/containers/WorkspacesScreen.js +++ b/src/features/workspaces/containers/WorkspacesScreen.js @@ -22,7 +22,7 @@ class WorkspacesScreen extends Component { actions.workspaces.create(data)} onWorkspaceClick={w => actions.workspaces.edit({ workspace: w })} /> diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 86a8a2c76..3cec5f360 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -30,7 +30,7 @@ export default class WorkspacesStore { @computed get workspaces() { if (!this.isFeatureActive) return []; - return getUserWorkspacesRequest.execute().result || []; + return getUserWorkspacesRequest.result || []; } constructor() { @@ -57,6 +57,7 @@ export default class WorkspacesStore { this.actions = actions; this._reactions.forEach(r => r.start()); this.isFeatureActive = true; + getUserWorkspacesRequest.execute(); } stop() { diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 03e96fc40..afbacf28a 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -3388,26 +3388,52 @@ "defaultMessage": "!!!Your workspaces", "end": { "column": 3, - "line": 15 + "line": 17 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.headline", "start": { "column": 12, - "line": 12 + "line": 14 } }, { "defaultMessage": "!!!You haven't added any workspaces yet.", "end": { "column": 3, - "line": 19 + "line": 21 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.noWorkspacesAdded", "start": { "column": 19, - "line": 16 + "line": 18 + } + }, + { + "defaultMessage": "!!!Could not load your workspaces", + "end": { + "column": 3, + "line": 25 + }, + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "id": "settings.workspaces.workspacesRequestFailed", + "start": { + "column": 27, + "line": 22 + } + }, + { + "defaultMessage": "!!!Try again", + "end": { + "column": 3, + "line": 29 + }, + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "id": "settings.workspaces.tryReloadWorkspaces", + "start": { + "column": 23, + "line": 26 } } ], diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 4206d4358..2b4e79621 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -251,6 +251,8 @@ "settings.workspace.form.yourWorkspaces": "Your workspaces", "settings.workspaces.headline": "Your workspaces", "settings.workspaces.noWorkspacesAdded": "You haven't added any workspaces yet.", + "settings.workspaces.tryReloadWorkspaces": "Try again", + "settings.workspaces.workspacesRequestFailed": "Could not load your workspaces", "sidebar.addNewService": "Add new service", "sidebar.closeWorkspaceDrawer": "Close workspace drawer", "sidebar.muteApp": "Disable notifications & audio", @@ -305,4 +307,4 @@ "workspaceDrawer.headline": "Workspaces", "workspaceDrawer.item.noServicesAddedYet": "No services added yet", "workspaces.switchingIndicator.switchingTo": "Switching to" -} \ No newline at end of file +} diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json index 0e053a124..f875ace8a 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Your workspaces", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 12, + "line": 14, "column": 12 }, "end": { - "line": 15, + "line": 17, "column": 3 } }, @@ -17,11 +17,37 @@ "defaultMessage": "!!!You haven't added any workspaces yet.", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 16, + "line": 18, "column": 19 }, "end": { - "line": 19, + "line": 21, + "column": 3 + } + }, + { + "id": "settings.workspaces.workspacesRequestFailed", + "defaultMessage": "!!!Could not load your workspaces", + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "start": { + "line": 22, + "column": 27 + }, + "end": { + "line": 25, + "column": 3 + } + }, + { + "id": "settings.workspaces.tryReloadWorkspaces", + "defaultMessage": "!!!Try again", + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "start": { + "line": 26, + "column": 23 + }, + "end": { + "line": 29, "column": 3 } } diff --git a/src/stores/lib/Request.js b/src/stores/lib/Request.js index 04f528156..1fb67cc15 100644 --- a/src/stores/lib/Request.js +++ b/src/stores/lib/Request.js @@ -85,6 +85,8 @@ export default class Request { return this.execute(...this._currentApiCall.args); } + retry = () => this.reload(); + isExecutingWithArgs(...args) { return this.isExecuting && this._currentApiCall && isEqual(this._currentApiCall.args, args); } -- cgit v1.2.3-54-g00ecf From a2e4316879908c5bc2c38cef81eef9152476b6f6 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Tue, 26 Mar 2019 15:26:20 +0100 Subject: show infobox when updating workspaces --- packages/ui/src/infobox/index.tsx | 7 ++ src/components/ui/Infobox.js | 17 ++++- .../workspaces/components/WorkspacesDashboard.js | 89 +++++++++++++--------- .../workspaces/containers/WorkspacesScreen.js | 3 +- src/features/workspaces/store.js | 15 ++-- src/i18n/locales/defaultMessages.json | 29 +++++-- src/i18n/locales/en-US.json | 3 +- .../workspaces/components/WorkspacesDashboard.json | 29 +++++-- src/stores/lib/Request.js | 4 +- 9 files changed, 129 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/packages/ui/src/infobox/index.tsx b/packages/ui/src/infobox/index.tsx index 1a442a733..9066a623e 100644 --- a/packages/ui/src/infobox/index.tsx +++ b/packages/ui/src/infobox/index.tsx @@ -11,6 +11,7 @@ interface IProps extends IWithStyle { type?: string; dismissable?: boolean; onDismiss?: () => void; + onUnmount?: () => void; ctaOnClick?: () => void; ctaLabel?: string; ctaLoading?: boolean; @@ -46,6 +47,7 @@ const styles = (theme: Theme) => ({ wrapper: { position: 'relative', overflow: 'hidden', + height: 'auto', }, infobox: { alignItems: 'center', @@ -129,6 +131,11 @@ class InfoboxComponent extends Component { }, 3000); } + componentWillUnmount(): void { + const { onUnmount } = this.props; + if (onUnmount) onUnmount(); + } + render() { const { classes, diff --git a/src/components/ui/Infobox.js b/src/components/ui/Infobox.js index a33c6474a..0917ee9f0 100644 --- a/src/components/ui/Infobox.js +++ b/src/components/ui/Infobox.js @@ -13,6 +13,8 @@ export default @observer class Infobox extends Component { ctaLabel: PropTypes.string, ctaLoading: PropTypes.bool, dismissable: PropTypes.bool, + onDismiss: PropTypes.func, + onSeen: PropTypes.func, }; static defaultProps = { @@ -22,12 +24,19 @@ export default @observer class Infobox extends Component { ctaOnClick: () => null, ctaLabel: '', ctaLoading: false, + onDismiss: () => null, + onSeen: () => null, }; state = { dismissed: false, }; + componentDidMount() { + const { onSeen } = this.props; + if (onSeen) onSeen(); + } + render() { const { children, @@ -37,6 +46,7 @@ export default @observer class Infobox extends Component { ctaLoading, ctaOnClick, dismissable, + onDismiss, } = this.props; if (this.state.dismissed) { @@ -76,9 +86,10 @@ export default @observer class Infobox extends Component { {dismissable && (
-
-
- -
- {getUserWorkspacesRequest.isExecuting ? ( - - ) : ( - - {getUserWorkspacesRequest.error ? ( - - {intl.formatMessage(messages.workspacesRequestFailed)} - - ) : ( - - - {workspaces.map(workspace => ( - onWorkspaceClick(w)} - /> - ))} - -
- )} -
- )} + {updateWorkspaceRequest.wasExecuted && updateWorkspaceRequest.result && ( + + + {intl.formatMessage(messages.updatedInfo)} + + + )} +
+
+ {getUserWorkspacesRequest.isExecuting ? ( + + ) : ( + + {getUserWorkspacesRequest.error ? ( + + {intl.formatMessage(messages.workspacesRequestFailed)} + + ) : ( + + + {workspaces.map(workspace => ( + onWorkspaceClick(w)} + /> + ))} + +
+ )} +
+ )}
); diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js index 89bd2a2ef..3f41de0c2 100644 --- a/src/features/workspaces/containers/WorkspacesScreen.js +++ b/src/features/workspaces/containers/WorkspacesScreen.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import WorkspacesDashboard from '../components/WorkspacesDashboard'; import ErrorBoundary from '../../../components/util/ErrorBoundary'; import { workspaceStore } from '../index'; -import { getUserWorkspacesRequest } from '../api'; +import { getUserWorkspacesRequest, updateWorkspaceRequest } from '../api'; @inject('actions') @observer class WorkspacesScreen extends Component { @@ -23,6 +23,7 @@ class WorkspacesScreen extends Component { actions.workspaces.create(data)} onWorkspaceClick={w => actions.workspaces.edit({ workspace: w })} /> diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 3cec5f360..f7df7b29c 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -102,9 +102,7 @@ export default class WorkspacesStore { @action _create = async ({ name }) => { try { const workspace = await createWorkspaceRequest.execute(name); - await getUserWorkspacesRequest.patch((result) => { - result.push(workspace); - }); + await getUserWorkspacesRequest.result.push(workspace); this._edit({ workspace }); } catch (error) { throw error; @@ -114,9 +112,7 @@ export default class WorkspacesStore { @action _delete = async ({ workspace }) => { try { await deleteWorkspaceRequest.execute(workspace); - await getUserWorkspacesRequest.patch((result) => { - result.remove(workspace); - }); + await getUserWorkspacesRequest.result.remove(workspace); this.stores.router.push('/settings/workspaces'); } catch (error) { throw error; @@ -126,10 +122,9 @@ export default class WorkspacesStore { @action _update = async ({ workspace }) => { try { await updateWorkspaceRequest.execute(workspace); - await getUserWorkspacesRequest.patch((result) => { - const localWorkspace = result.find(ws => ws.id === workspace.id); - Object.assign(localWorkspace, workspace); - }); + // Path local result optimistically + const localWorkspace = this._getWorkspaceById(workspace.id); + Object.assign(localWorkspace, workspace); this.stores.router.push('/settings/workspaces'); } catch (error) { throw error; diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index afbacf28a..891ad38d4 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -3388,52 +3388,65 @@ "defaultMessage": "!!!Your workspaces", "end": { "column": 3, - "line": 17 + "line": 18 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.headline", "start": { "column": 12, - "line": 14 + "line": 15 } }, { "defaultMessage": "!!!You haven't added any workspaces yet.", "end": { "column": 3, - "line": 21 + "line": 22 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.noWorkspacesAdded", "start": { "column": 19, - "line": 18 + "line": 19 } }, { "defaultMessage": "!!!Could not load your workspaces", "end": { "column": 3, - "line": 25 + "line": 26 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.workspacesRequestFailed", "start": { "column": 27, - "line": 22 + "line": 23 } }, { "defaultMessage": "!!!Try again", "end": { "column": 3, - "line": 29 + "line": 30 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.tryReloadWorkspaces", "start": { "column": 23, - "line": 26 + "line": 27 + } + }, + { + "defaultMessage": "!!!Your changes have been saved", + "end": { + "column": 3, + "line": 34 + }, + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "id": "settings.workspaces.updatedInfo", + "start": { + "column": 15, + "line": 31 } } ], diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 2b4e79621..ad179bc1d 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -252,6 +252,7 @@ "settings.workspaces.headline": "Your workspaces", "settings.workspaces.noWorkspacesAdded": "You haven't added any workspaces yet.", "settings.workspaces.tryReloadWorkspaces": "Try again", + "settings.workspaces.updatedInfo": "!!!Your changes have been saved", "settings.workspaces.workspacesRequestFailed": "Could not load your workspaces", "sidebar.addNewService": "Add new service", "sidebar.closeWorkspaceDrawer": "Close workspace drawer", @@ -307,4 +308,4 @@ "workspaceDrawer.headline": "Workspaces", "workspaceDrawer.item.noServicesAddedYet": "No services added yet", "workspaces.switchingIndicator.switchingTo": "Switching to" -} +} \ No newline at end of file diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json index f875ace8a..d68899d9b 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Your workspaces", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 14, + "line": 15, "column": 12 }, "end": { - "line": 17, + "line": 18, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!You haven't added any workspaces yet.", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 18, + "line": 19, "column": 19 }, "end": { - "line": 21, + "line": 22, "column": 3 } }, @@ -30,11 +30,11 @@ "defaultMessage": "!!!Could not load your workspaces", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 22, + "line": 23, "column": 27 }, "end": { - "line": 25, + "line": 26, "column": 3 } }, @@ -43,11 +43,24 @@ "defaultMessage": "!!!Try again", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 26, + "line": 27, "column": 23 }, "end": { - "line": 29, + "line": 30, + "column": 3 + } + }, + { + "id": "settings.workspaces.updatedInfo", + "defaultMessage": "!!!Your changes have been saved", + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "start": { + "line": 31, + "column": 15 + }, + "end": { + "line": 34, "column": 3 } } diff --git a/src/stores/lib/Request.js b/src/stores/lib/Request.js index 1fb67cc15..486de8a49 100644 --- a/src/stores/lib/Request.js +++ b/src/stores/lib/Request.js @@ -109,7 +109,7 @@ export default class Request { Request._hooks.forEach(hook => hook(this)); } - reset() { + reset = () => { this.result = null; this.isExecuting = false; this.isError = false; @@ -118,5 +118,5 @@ export default class Request { this._promise = Promise; return this; - } + }; } -- cgit v1.2.3-54-g00ecf From 03c76d7a6e5c5529e39f245dd350c0bc8abbd128 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Tue, 26 Mar 2019 16:25:49 +0100 Subject: indicate any server interaction with spinners and infoboxes --- src/features/workspaces/api.js | 2 +- .../workspaces/components/CreateWorkspaceForm.js | 7 ++- .../workspaces/components/EditWorkspaceForm.js | 59 +++++++++------------- .../workspaces/components/WorkspacesDashboard.js | 38 ++++++++++++-- .../workspaces/containers/EditWorkspaceScreen.js | 5 +- .../workspaces/containers/WorkspacesScreen.js | 9 +++- src/i18n/locales/defaultMessages.json | 35 +++++++++---- src/i18n/locales/en-US.json | 5 +- .../workspaces/components/CreateWorkspaceForm.json | 2 +- .../workspaces/components/EditWorkspaceForm.json | 20 ++++---- .../workspaces/components/WorkspacesDashboard.json | 13 +++++ 11 files changed, 127 insertions(+), 68 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js index 3da265e5e..0ec20c9ea 100644 --- a/src/features/workspaces/api.js +++ b/src/features/workspaces/api.js @@ -36,7 +36,7 @@ export const workspaceApi = { const result = await sendAuthRequest(url, { method: 'DELETE' }); debug('deleteWorkspace RESULT', result); if (!result.ok) throw result; - return (await result.json()).deleted; + return true; }, updateWorkspace: async (workspace) => { diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js index 83f6e07f7..8b5039246 100644 --- a/src/features/workspaces/components/CreateWorkspaceForm.js +++ b/src/features/workspaces/components/CreateWorkspaceForm.js @@ -10,7 +10,7 @@ import { required } from '../../../helpers/validation-helpers'; const messages = defineMessages({ submitButton: { id: 'settings.workspace.add.form.submitButton', - defaultMessage: '!!!Save workspace', + defaultMessage: '!!!Create workspace', }, name: { id: 'settings.workspace.add.form.name', @@ -40,6 +40,7 @@ class CreateWorkspaceForm extends Component { static propTypes = { classes: PropTypes.object.isRequired, + isSubmitting: PropTypes.bool.isRequired, onSubmit: PropTypes.func.isRequired, }; @@ -69,7 +70,7 @@ class CreateWorkspaceForm extends Component { render() { const { intl } = this.context; - const { classes } = this.props; + const { classes, isSubmitting } = this.props; const { form } = this; return (
@@ -84,6 +85,8 @@ class CreateWorkspaceForm extends Component { type="submit" label={intl.formatMessage(messages.submitButton)} onClick={this.submitForm.bind(this, form)} + busy={isSubmitting} + buttonType={isSubmitting ? 'secondary' : 'primary'} />
); diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js index 48090f608..a9fd4d21c 100644 --- a/src/features/workspaces/components/EditWorkspaceForm.js +++ b/src/features/workspaces/components/EditWorkspaceForm.js @@ -11,6 +11,7 @@ import Service from '../../../models/Service'; import Form from '../../../lib/Form'; import { required } from '../../../helpers/validation-helpers'; import ServiceListItem from './ServiceListItem'; +import Request from '../../../stores/lib/Request'; const messages = defineMessages({ buttonDelete: { @@ -52,12 +53,12 @@ class EditWorkspaceForm extends Component { static propTypes = { classes: PropTypes.object.isRequired, - isDeleting: PropTypes.bool.isRequired, - isSaving: PropTypes.bool.isRequired, onDelete: PropTypes.func.isRequired, onSave: PropTypes.func.isRequired, services: PropTypes.arrayOf(PropTypes.instanceOf(Service)).isRequired, workspace: PropTypes.instanceOf(Workspace).isRequired, + updateWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, + deleteWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, }; form = this.prepareWorkspaceForm(this.props.workspace); @@ -112,14 +113,16 @@ class EditWorkspaceForm extends Component { const { intl } = this.context; const { classes, - isDeleting, - isSaving, onDelete, workspace, services, + deleteWorkspaceRequest, + updateWorkspaceRequest, } = this.props; const { form } = this; const workspaceServices = form.$('services').value; + const isDeleting = deleteWorkspaceRequest.isExecuting; + const isSaving = updateWorkspaceRequest.isExecuting; return (
@@ -151,38 +154,24 @@ class EditWorkspaceForm extends Component {
{/* ===== Delete Button ===== */} - {isDeleting ? ( -
); diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js index 3db38aff4..b31581a5b 100644 --- a/src/features/workspaces/components/WorkspacesDashboard.js +++ b/src/features/workspaces/components/WorkspacesDashboard.js @@ -32,6 +32,10 @@ const messages = defineMessages({ id: 'settings.workspaces.updatedInfo', defaultMessage: '!!!Your changes have been saved', }, + deletedInfo: { + id: 'settings.workspaces.deletedInfo', + defaultMessage: '!!!Workspace has been deleted', + }, }); const styles = () => ({ @@ -49,6 +53,8 @@ class WorkspacesDashboard extends Component { static propTypes = { classes: PropTypes.object.isRequired, getUserWorkspacesRequest: PropTypes.instanceOf(Request).isRequired, + createWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, + deleteWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, updateWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, onCreateWorkspaceSubmit: PropTypes.func.isRequired, onWorkspaceClick: PropTypes.func.isRequired, @@ -63,38 +69,63 @@ class WorkspacesDashboard extends Component { const { classes, getUserWorkspacesRequest, + createWorkspaceRequest, + deleteWorkspaceRequest, updateWorkspaceRequest, onCreateWorkspaceSubmit, onWorkspaceClick, workspaces, } = this.props; const { intl } = this.context; + console.log(deleteWorkspaceRequest.result); return (

{intl.formatMessage(messages.headline)}

+ + {/* ===== Workspace updated info ===== */} {updateWorkspaceRequest.wasExecuted && updateWorkspaceRequest.result && ( {intl.formatMessage(messages.updatedInfo)} )} + + {/* ===== Workspace deleted info ===== */} + {deleteWorkspaceRequest.wasExecuted && deleteWorkspaceRequest.result && ( + + + {intl.formatMessage(messages.deletedInfo)} + + + )} + + {/* ===== Create workspace form ===== */}
- +
+ {getUserWorkspacesRequest.isExecuting ? ( ) : ( + {/* ===== Workspace could not be loaded error ===== */} {getUserWorkspacesRequest.error ? ( ) : ( + {/* ===== Workspaces list ===== */} {workspaces.map(workspace => ( ); diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js index 3f41de0c2..2ab565fa1 100644 --- a/src/features/workspaces/containers/WorkspacesScreen.js +++ b/src/features/workspaces/containers/WorkspacesScreen.js @@ -4,7 +4,12 @@ import PropTypes from 'prop-types'; import WorkspacesDashboard from '../components/WorkspacesDashboard'; import ErrorBoundary from '../../../components/util/ErrorBoundary'; import { workspaceStore } from '../index'; -import { getUserWorkspacesRequest, updateWorkspaceRequest } from '../api'; +import { + createWorkspaceRequest, + deleteWorkspaceRequest, + getUserWorkspacesRequest, + updateWorkspaceRequest, +} from '../api'; @inject('actions') @observer class WorkspacesScreen extends Component { @@ -23,6 +28,8 @@ class WorkspacesScreen extends Component { actions.workspaces.create(data)} onWorkspaceClick={w => actions.workspaces.edit({ workspace: w })} diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 891ad38d4..4b6a8eca9 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -3222,7 +3222,7 @@ { "descriptors": [ { - "defaultMessage": "!!!Save workspace", + "defaultMessage": "!!!Create workspace", "end": { "column": 3, "line": 14 @@ -3256,65 +3256,65 @@ "defaultMessage": "!!!Delete workspace", "end": { "column": 3, - "line": 19 + "line": 20 }, "file": "src/features/workspaces/components/EditWorkspaceForm.js", "id": "settings.workspace.form.buttonDelete", "start": { "column": 16, - "line": 16 + "line": 17 } }, { "defaultMessage": "!!!Save workspace", "end": { "column": 3, - "line": 23 + "line": 24 }, "file": "src/features/workspaces/components/EditWorkspaceForm.js", "id": "settings.workspace.form.buttonSave", "start": { "column": 14, - "line": 20 + "line": 21 } }, { "defaultMessage": "!!!Name", "end": { "column": 3, - "line": 27 + "line": 28 }, "file": "src/features/workspaces/components/EditWorkspaceForm.js", "id": "settings.workspace.form.name", "start": { "column": 8, - "line": 24 + "line": 25 } }, { "defaultMessage": "!!!Your workspaces", "end": { "column": 3, - "line": 31 + "line": 32 }, "file": "src/features/workspaces/components/EditWorkspaceForm.js", "id": "settings.workspace.form.yourWorkspaces", "start": { "column": 18, - "line": 28 + "line": 29 } }, { "defaultMessage": "!!!Services in this Workspace", "end": { "column": 3, - "line": 35 + "line": 36 }, "file": "src/features/workspaces/components/EditWorkspaceForm.js", "id": "settings.workspace.form.servicesInWorkspaceHeadline", "start": { "column": 31, - "line": 32 + "line": 33 } } ], @@ -3448,6 +3448,19 @@ "column": 15, "line": 31 } + }, + { + "defaultMessage": "!!!Workspace has been deleted", + "end": { + "column": 3, + "line": 38 + }, + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "id": "settings.workspaces.deletedInfo", + "start": { + "column": 15, + "line": 35 + } } ], "path": "src/features/workspaces/components/WorkspacesDashboard.json" diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index ad179bc1d..5f7254317 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -243,16 +243,17 @@ "settings.user.form.lastname": "Last Name", "settings.user.form.newPassword": "New password", "settings.workspace.add.form.name": "Name", - "settings.workspace.add.form.submitButton": "Save workspace", + "settings.workspace.add.form.submitButton": "Create workspace", "settings.workspace.form.buttonDelete": "Delete workspace", "settings.workspace.form.buttonSave": "Save workspace", "settings.workspace.form.name": "Name", "settings.workspace.form.servicesInWorkspaceHeadline": "Services in this Workspace", "settings.workspace.form.yourWorkspaces": "Your workspaces", + "settings.workspaces.deletedInfo": "Workspace has been deleted", "settings.workspaces.headline": "Your workspaces", "settings.workspaces.noWorkspacesAdded": "You haven't added any workspaces yet.", "settings.workspaces.tryReloadWorkspaces": "Try again", - "settings.workspaces.updatedInfo": "!!!Your changes have been saved", + "settings.workspaces.updatedInfo": "Your changes have been saved", "settings.workspaces.workspacesRequestFailed": "Could not load your workspaces", "sidebar.addNewService": "Add new service", "sidebar.closeWorkspaceDrawer": "Close workspace drawer", diff --git a/src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json b/src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json index 1d5063a97..7cc1a374f 100644 --- a/src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json +++ b/src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json @@ -1,7 +1,7 @@ [ { "id": "settings.workspace.add.form.submitButton", - "defaultMessage": "!!!Save workspace", + "defaultMessage": "!!!Create workspace", "file": "src/features/workspaces/components/CreateWorkspaceForm.js", "start": { "line": 11, diff --git a/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json b/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json index 467f49cda..8a26bf45a 100644 --- a/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json +++ b/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Delete workspace", "file": "src/features/workspaces/components/EditWorkspaceForm.js", "start": { - "line": 16, + "line": 17, "column": 16 }, "end": { - "line": 19, + "line": 20, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!Save workspace", "file": "src/features/workspaces/components/EditWorkspaceForm.js", "start": { - "line": 20, + "line": 21, "column": 14 }, "end": { - "line": 23, + "line": 24, "column": 3 } }, @@ -30,11 +30,11 @@ "defaultMessage": "!!!Name", "file": "src/features/workspaces/components/EditWorkspaceForm.js", "start": { - "line": 24, + "line": 25, "column": 8 }, "end": { - "line": 27, + "line": 28, "column": 3 } }, @@ -43,11 +43,11 @@ "defaultMessage": "!!!Your workspaces", "file": "src/features/workspaces/components/EditWorkspaceForm.js", "start": { - "line": 28, + "line": 29, "column": 18 }, "end": { - "line": 31, + "line": 32, "column": 3 } }, @@ -56,11 +56,11 @@ "defaultMessage": "!!!Services in this Workspace", "file": "src/features/workspaces/components/EditWorkspaceForm.js", "start": { - "line": 32, + "line": 33, "column": 31 }, "end": { - "line": 35, + "line": 36, "column": 3 } } diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json index d68899d9b..a957358c8 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json @@ -63,5 +63,18 @@ "line": 34, "column": 3 } + }, + { + "id": "settings.workspaces.deletedInfo", + "defaultMessage": "!!!Workspace has been deleted", + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "start": { + "line": 35, + "column": 15 + }, + "end": { + "line": 38, + "column": 3 + } } ] \ No newline at end of file -- cgit v1.2.3-54-g00ecf From eb57e4f787d06648dab2c473830dcfbfa168e00c Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 28 Mar 2019 12:13:27 +0100 Subject: add analytic events for workspace actions --- src/components/layout/Sidebar.js | 4 +- .../workspaces/components/CreateWorkspaceForm.js | 6 +- .../workspaces/components/EditWorkspaceForm.js | 16 +- .../workspaces/components/WorkspaceDrawer.js | 13 +- .../workspaces/components/WorkspacesDashboard.js | 1 - src/features/workspaces/index.js | 2 + src/i18n/locales/defaultMessages.json | 272 ++++++++++----------- .../messages/src/components/layout/Sidebar.json | 24 +- .../workspaces/components/CreateWorkspaceForm.json | 8 +- .../workspaces/components/EditWorkspaceForm.json | 20 +- .../workspaces/components/WorkspaceDrawer.json | 12 +- src/i18n/messages/src/lib/Menu.json | 208 ++++++++-------- src/lib/Menu.js | 6 +- src/lib/analytics.js | 4 +- 14 files changed, 310 insertions(+), 286 deletions(-) (limited to 'src') diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index f7bacfe0f..4fa5e79de 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js @@ -6,7 +6,8 @@ import { observer } from 'mobx-react'; import Tabbar from '../services/tabs/Tabbar'; import { ctrlKey } from '../../environment'; -import { workspaceStore } from '../../features/workspaces'; +import { GA_CATEGORY_WORKSPACES, workspaceStore } from '../../features/workspaces'; +import { gaEvent } from '../../lib/analytics'; const messages = defineMessages({ settings: { @@ -95,6 +96,7 @@ export default @observer class Sidebar extends Component { onClick={() => { toggleWorkspaceDrawer(); this.updateToolTip(); + gaEvent(GA_CATEGORY_WORKSPACES, 'toggleDrawer', 'sidebar'); }} className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`} data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${ctrlKey}+Shift+D)`} diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js index 8b5039246..a8f07d0d5 100644 --- a/src/features/workspaces/components/CreateWorkspaceForm.js +++ b/src/features/workspaces/components/CreateWorkspaceForm.js @@ -6,6 +6,8 @@ import { Input, Button } from '@meetfranz/forms'; import injectSheet from 'react-jss'; import Form from '../../../lib/Form'; import { required } from '../../../helpers/validation-helpers'; +import { gaEvent } from '../../../lib/analytics'; +import { GA_CATEGORY_WORKSPACES } from '../index'; const messages = defineMessages({ submitButton: { @@ -63,7 +65,9 @@ class CreateWorkspaceForm extends Component { form.submit({ onSuccess: async (f) => { const { onSubmit } = this.props; - onSubmit(f.values()); + const values = f.values(); + onSubmit(values); + gaEvent(GA_CATEGORY_WORKSPACES, 'create', values.name); }, }); } diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js index a9fd4d21c..e4bf44248 100644 --- a/src/features/workspaces/components/EditWorkspaceForm.js +++ b/src/features/workspaces/components/EditWorkspaceForm.js @@ -12,6 +12,8 @@ import Form from '../../../lib/Form'; import { required } from '../../../helpers/validation-helpers'; import ServiceListItem from './ServiceListItem'; import Request from '../../../stores/lib/Request'; +import { gaEvent } from '../../../lib/analytics'; +import { GA_CATEGORY_WORKSPACES } from '../index'; const messages = defineMessages({ buttonDelete: { @@ -87,17 +89,24 @@ class EditWorkspaceForm extends Component { }); } - submitForm(form) { + save(form) { form.submit({ onSuccess: async (f) => { const { onSave } = this.props; const values = f.values(); onSave(values); + gaEvent(GA_CATEGORY_WORKSPACES, 'save'); }, onError: async () => {}, }); } + delete() { + const { onDelete } = this.props; + onDelete(); + gaEvent(GA_CATEGORY_WORKSPACES, 'delete'); + } + toggleService(service) { const servicesField = this.form.$('services'); const serviceIds = servicesField.value; @@ -113,7 +122,6 @@ class EditWorkspaceForm extends Component { const { intl } = this.context; const { classes, - onDelete, workspace, services, deleteWorkspaceRequest, @@ -161,7 +169,7 @@ class EditWorkspaceForm extends Component { buttonType={isDeleting ? 'secondary' : 'danger'} className="settings__delete-button" disabled={isDeleting} - onClick={onDelete} + onClick={this.delete.bind(this)} /> {/* ===== Save Button ===== */} @@ -73,3 +88,5 @@ PremiumFeatureContainer.wrappedComponent.propTypes = { }).isRequired, }).isRequired, }; + +export default PremiumFeatureContainer; diff --git a/src/components/ui/PremiumFeatureContainer/styles.js b/src/components/ui/PremiumFeatureContainer/styles.js index 81d6666c6..615ed0a79 100644 --- a/src/components/ui/PremiumFeatureContainer/styles.js +++ b/src/components/ui/PremiumFeatureContainer/styles.js @@ -6,6 +6,7 @@ export default theme => ({ padding: 20, 'border-radius': theme.borderRadius, pointerEvents: 'none', + height: 'auto', }, titleContainer: { display: 'flex', @@ -26,7 +27,7 @@ export default theme => ({ content: { opacity: 0.5, 'margin-top': 20, - '& :last-child': { + '& > :last-child': { 'margin-bottom': 0, }, }, diff --git a/src/features/delayApp/index.js b/src/features/delayApp/index.js index abc8274cf..67f0fc5e6 100644 --- a/src/features/delayApp/index.js +++ b/src/features/delayApp/index.js @@ -55,7 +55,7 @@ export default function init(stores) { setVisibility(true); gaPage('/delayApp'); - gaEvent('delayApp', 'show', 'Delay App Feature'); + gaEvent('DelayApp', 'show', 'Delay App Feature'); timeLastDelay = moment(); shownAfterLaunch = true; diff --git a/src/features/utils/FeatureStore.js b/src/features/utils/FeatureStore.js new file mode 100644 index 000000000..66b66a104 --- /dev/null +++ b/src/features/utils/FeatureStore.js @@ -0,0 +1,21 @@ +import Reaction from '../../stores/lib/Reaction'; + +export class FeatureStore { + _actions = null; + + _reactions = null; + + _listenToActions(actions) { + if (this._actions) this._actions.forEach(a => a[0].off(a[1])); + this._actions = []; + actions.forEach(a => this._actions.push(a)); + this._actions.forEach(a => a[0].listen(a[1])); + } + + _startReactions(reactions) { + if (this._reactions) this._reactions.forEach(r => r.stop()); + this._reactions = []; + reactions.forEach(r => this._reactions.push(new Reaction(r))); + this._reactions.forEach(r => r.start()); + } +} diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js index a8f07d0d5..0be2d528f 100644 --- a/src/features/workspaces/components/CreateWorkspaceForm.js +++ b/src/features/workspaces/components/CreateWorkspaceForm.js @@ -30,7 +30,6 @@ const styles = () => ({ }, submitButton: { height: 'inherit', - marginTop: '3px', }, }); diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js index 52c3afdcf..1fad1f71d 100644 --- a/src/features/workspaces/components/WorkspacesDashboard.js +++ b/src/features/workspaces/components/WorkspacesDashboard.js @@ -10,6 +10,8 @@ import WorkspaceItem from './WorkspaceItem'; import CreateWorkspaceForm from './CreateWorkspaceForm'; import Request from '../../../stores/lib/Request'; import Appear from '../../../components/ui/effects/Appear'; +import { workspaceStore } from '../index'; +import PremiumFeatureContainer from '../../../components/ui/PremiumFeatureContainer'; const messages = defineMessages({ headline: { @@ -36,6 +38,14 @@ const messages = defineMessages({ id: 'settings.workspaces.deletedInfo', defaultMessage: '!!!Workspace has been deleted', }, + workspaceFeatureInfo: { + id: 'settings.workspaces.workspaceFeatureInfo', + defaultMessage: '!!!Info about workspace feature', + }, + workspaceFeatureHeadline: { + id: 'settings.workspaces.workspaceFeatureHeadline', + defaultMessage: '!!!Less is More: Introducing Franz Workspaces', + }, }); const styles = () => ({ @@ -46,6 +56,12 @@ const styles = () => ({ appear: { height: 'auto', }, + premiumAnnouncement: { + padding: '20px', + backgroundColor: '#3498db', + marginLeft: '-20px', + height: 'auto', + }, }); @injectSheet(styles) @observer @@ -112,14 +128,24 @@ class WorkspacesDashboard extends Component { )} - {/* ===== Create workspace form ===== */} -
- -
- + + {/* ===== Create workspace form ===== */} +
+ +
+
+ {workspaceStore.isUpgradeToPremiumRequired && ( +
+

{intl.formatMessage(messages.workspaceFeatureHeadline)}

+

{intl.formatMessage(messages.workspaceFeatureInfo)}

+
+ )} {getUserWorkspacesRequest.isExecuting ? ( ) : ( diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js index 89999ab0f..524a83e3c 100644 --- a/src/features/workspaces/index.js +++ b/src/features/workspaces/index.js @@ -4,11 +4,12 @@ import { resetApiRequests } from './api'; const debug = require('debug')('Franz:feature:workspaces'); -export const GA_CATEGORY_WORKSPACES = 'workspaces'; +export const GA_CATEGORY_WORKSPACES = 'Workspaces'; export const workspaceStore = new WorkspacesStore(); export default function initWorkspaces(stores, actions) { + stores.workspaces = workspaceStore; const { features, user } = stores; // Toggle workspace feature diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index f7df7b29c..62bf3efb4 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -3,9 +3,9 @@ import { observable, action, } from 'mobx'; -import Reaction from '../../stores/lib/Reaction'; import { matchRoute } from '../../helpers/routing-helpers'; import { workspaceActions } from './actions'; +import { FeatureStore } from '../utils/FeatureStore'; import { createWorkspaceRequest, deleteWorkspaceRequest, @@ -15,7 +15,11 @@ import { const debug = require('debug')('Franz:feature:workspaces:store'); -export default class WorkspacesStore { +export default class WorkspacesStore extends FeatureStore { + @observable isFeatureEnabled = false; + + @observable isPremiumFeature = true; + @observable isFeatureActive = false; @observable activeWorkspace = null; @@ -33,36 +37,39 @@ export default class WorkspacesStore { return getUserWorkspacesRequest.result || []; } - constructor() { - // Wire-up action handlers - workspaceActions.edit.listen(this._edit); - workspaceActions.create.listen(this._create); - workspaceActions.delete.listen(this._delete); - workspaceActions.update.listen(this._update); - workspaceActions.activate.listen(this._setActiveWorkspace); - workspaceActions.deactivate.listen(this._deactivateActiveWorkspace); - workspaceActions.toggleWorkspaceDrawer.listen(this._toggleWorkspaceDrawer); - workspaceActions.openWorkspaceSettings.listen(this._openWorkspaceSettings); - - // Register and start reactions - this._registerReactions([ - this._updateWorkspaceBeingEdited, - this._updateActiveServiceOnWorkspaceSwitch, - ]); + @computed get isUpgradeToPremiumRequired() { + return this.isFeatureEnabled && !this.isFeatureActive; } start(stores, actions) { debug('WorkspacesStore::start'); this.stores = stores; this.actions = actions; - this._reactions.forEach(r => r.start()); - this.isFeatureActive = true; + + this._listenToActions([ + [workspaceActions.edit, this._edit], + [workspaceActions.create, this._create], + [workspaceActions.delete, this._delete], + [workspaceActions.update, this._update], + [workspaceActions.activate, this._setActiveWorkspace], + [workspaceActions.deactivate, this._deactivateActiveWorkspace], + [workspaceActions.toggleWorkspaceDrawer, this._toggleWorkspaceDrawer], + [workspaceActions.openWorkspaceSettings, this._openWorkspaceSettings], + ]); + + this._startReactions([ + this._setWorkspaceBeingEditedReaction, + this._setActiveServiceOnWorkspaceSwitchReaction, + this._setFeatureEnabledReaction, + this._setIsPremiumFeatureReaction, + ]); + getUserWorkspacesRequest.execute(); + this.isFeatureActive = true; } stop() { debug('WorkspacesStore::stop'); - this._reactions.forEach(r => r.stop()); this.isFeatureActive = false; this.activeWorkspace = null; this.nextWorkspace = null; @@ -85,12 +92,6 @@ export default class WorkspacesStore { // ========== PRIVATE ========= // - _reactions = []; - - _registerReactions(reactions) { - reactions.forEach(r => this._reactions.push(new Reaction(r))); - } - _getWorkspaceById = id => this.workspaces.find(w => w.id === id); // Actions @@ -164,7 +165,17 @@ export default class WorkspacesStore { // Reactions - _updateWorkspaceBeingEdited = () => { + _setFeatureEnabledReaction = () => { + const { isWorkspaceEnabled } = this.stores.features.features; + this.isFeatureEnabled = isWorkspaceEnabled; + }; + + _setIsPremiumFeatureReaction = () => { + const { isWorkspacePremiumFeature } = this.stores.features.features; + this.isPremiumFeature = isWorkspacePremiumFeature; + }; + + _setWorkspaceBeingEditedReaction = () => { const { pathname } = this.stores.router.location; const match = matchRoute('/settings/workspaces/edit/:id', pathname); if (match) { @@ -172,7 +183,7 @@ export default class WorkspacesStore { } }; - _updateActiveServiceOnWorkspaceSwitch = () => { + _setActiveServiceOnWorkspaceSwitchReaction = () => { if (!this.isFeatureActive) return; if (this.activeWorkspace) { const services = this.stores.services.allDisplayed; diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 659b1b361..1747e1976 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -2535,13 +2535,13 @@ "defaultMessage": "!!!Upgrade account", "end": { "column": 3, - "line": 17 + "line": 18 }, "file": "src/components/ui/PremiumFeatureContainer/index.js", "id": "premiumFeature.button.upgradeAccount", "start": { "column": 10, - "line": 14 + "line": 15 } } ], @@ -3388,78 +3388,104 @@ "defaultMessage": "!!!Your workspaces", "end": { "column": 3, - "line": 18 + "line": 20 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.headline", "start": { "column": 12, - "line": 15 + "line": 17 } }, { "defaultMessage": "!!!You haven't added any workspaces yet.", "end": { "column": 3, - "line": 22 + "line": 24 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.noWorkspacesAdded", "start": { "column": 19, - "line": 19 + "line": 21 } }, { "defaultMessage": "!!!Could not load your workspaces", "end": { "column": 3, - "line": 26 + "line": 28 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.workspacesRequestFailed", "start": { "column": 27, - "line": 23 + "line": 25 } }, { "defaultMessage": "!!!Try again", "end": { "column": 3, - "line": 30 + "line": 32 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.tryReloadWorkspaces", "start": { "column": 23, - "line": 27 + "line": 29 } }, { "defaultMessage": "!!!Your changes have been saved", "end": { "column": 3, - "line": 34 + "line": 36 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.updatedInfo", "start": { "column": 15, - "line": 31 + "line": 33 } }, { "defaultMessage": "!!!Workspace has been deleted", "end": { "column": 3, - "line": 38 + "line": 40 }, "file": "src/features/workspaces/components/WorkspacesDashboard.js", "id": "settings.workspaces.deletedInfo", "start": { "column": 15, - "line": 35 + "line": 37 + } + }, + { + "defaultMessage": "!!!Info about workspace feature", + "end": { + "column": 3, + "line": 44 + }, + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "id": "settings.workspaces.workspaceFeatureInfo", + "start": { + "column": 24, + "line": 41 + } + }, + { + "defaultMessage": "!!!Less is More: Introducing Franz Workspaces", + "end": { + "column": 3, + "line": 48 + }, + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "id": "settings.workspaces.workspaceFeatureHeadline", + "start": { + "column": 28, + "line": 45 } } ], diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 5f7254317..987262c35 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -254,6 +254,8 @@ "settings.workspaces.noWorkspacesAdded": "You haven't added any workspaces yet.", "settings.workspaces.tryReloadWorkspaces": "Try again", "settings.workspaces.updatedInfo": "Your changes have been saved", + "settings.workspaces.workspaceFeatureHeadline": "Less is More: Introducing Franz Workspaces", + "settings.workspaces.workspaceFeatureInfo": "Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.", "settings.workspaces.workspacesRequestFailed": "Could not load your workspaces", "sidebar.addNewService": "Add new service", "sidebar.closeWorkspaceDrawer": "Close workspace drawer", diff --git a/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json b/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json index 582d546fa..320d3ca3e 100644 --- a/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json +++ b/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Upgrade account", "file": "src/components/ui/PremiumFeatureContainer/index.js", "start": { - "line": 14, + "line": 15, "column": 10 }, "end": { - "line": 17, + "line": 18, "column": 3 } } diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json index a957358c8..ef8f1bebc 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Your workspaces", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 15, + "line": 17, "column": 12 }, "end": { - "line": 18, + "line": 20, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!You haven't added any workspaces yet.", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 19, + "line": 21, "column": 19 }, "end": { - "line": 22, + "line": 24, "column": 3 } }, @@ -30,11 +30,11 @@ "defaultMessage": "!!!Could not load your workspaces", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 23, + "line": 25, "column": 27 }, "end": { - "line": 26, + "line": 28, "column": 3 } }, @@ -43,11 +43,11 @@ "defaultMessage": "!!!Try again", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 27, + "line": 29, "column": 23 }, "end": { - "line": 30, + "line": 32, "column": 3 } }, @@ -56,11 +56,11 @@ "defaultMessage": "!!!Your changes have been saved", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 31, + "line": 33, "column": 15 }, "end": { - "line": 34, + "line": 36, "column": 3 } }, @@ -69,11 +69,37 @@ "defaultMessage": "!!!Workspace has been deleted", "file": "src/features/workspaces/components/WorkspacesDashboard.js", "start": { - "line": 35, + "line": 37, "column": 15 }, "end": { - "line": 38, + "line": 40, + "column": 3 + } + }, + { + "id": "settings.workspaces.workspaceFeatureInfo", + "defaultMessage": "!!!Info about workspace feature", + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "start": { + "line": 41, + "column": 24 + }, + "end": { + "line": 44, + "column": 3 + } + }, + { + "id": "settings.workspaces.workspaceFeatureHeadline", + "defaultMessage": "!!!Less is More: Introducing Franz Workspaces", + "file": "src/features/workspaces/components/WorkspacesDashboard.js", + "start": { + "line": 45, + "column": 28 + }, + "end": { + "line": 48, "column": 3 } } diff --git a/src/lib/Menu.js b/src/lib/Menu.js index d19aa9d6e..a4e41c17c 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js @@ -323,7 +323,7 @@ const _templateFactory = intl => [ { label: intl.formatMessage(menuItems.workspaces), submenu: [], - visible: workspaceStore.isFeatureActive, + visible: workspaceStore.isFeatureEnabled, }, { label: intl.formatMessage(menuItems.window), @@ -732,7 +732,7 @@ export default class FranzMenu { tpl[3].submenu = serviceTpl; } - if (workspaceStore.isFeatureActive) { + if (workspaceStore.isFeatureEnabled) { tpl[4].submenu = this.workspacesMenu(); } diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index 2bda82e17..52e38ad96 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js @@ -1,4 +1,4 @@ -import { computed, observable, reaction } from 'mobx'; +import { computed, observable, reaction, runInAction } from 'mobx'; import Store from './lib/Store'; import CachedRequest from './lib/CachedRequest'; @@ -17,8 +17,11 @@ export default class FeaturesStore extends Store { @observable featuresRequest = new CachedRequest(this.api.features, 'features'); + @observable features = Object.assign({}, DEFAULT_FEATURES_CONFIG); + async setup() { this.registerReactions([ + this._updateFeatures, this._monitorLoginStatus.bind(this), ]); @@ -37,13 +40,16 @@ export default class FeaturesStore extends Store { return this.defaultFeaturesRequest.execute().result || DEFAULT_FEATURES_CONFIG; } - @computed get features() { + _updateFeatures = () => { + const features = Object.assign({}, DEFAULT_FEATURES_CONFIG); if (this.stores.user.isLoggedIn) { - return Object.assign({}, DEFAULT_FEATURES_CONFIG, this.featuresRequest.execute().result); + const requestResult = this.featuresRequest.execute().result; + Object.assign(features, requestResult); } - - return DEFAULT_FEATURES_CONFIG; - } + runInAction('FeaturesStore::_updateFeatures', () => { + this.features = features; + }); + }; _monitorLoginStatus() { if (this.stores.user.isLoggedIn) { -- cgit v1.2.3-54-g00ecf From b75206e9a0a2c0c7ffb6052ec0f18c6b9ef5a825 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 3 Apr 2019 15:14:45 +0200 Subject: add workspace feature info in drawer for free users --- src/features/spellchecker/index.js | 2 - .../workspaces/components/WorkspaceDrawer.js | 81 ++++++++++++++++------ .../workspaces/components/WorkspacesDashboard.js | 15 ++-- src/features/workspaces/store.js | 2 +- src/i18n/locales/defaultMessages.json | 38 ++++++++-- src/i18n/locales/en-US.json | 4 +- .../workspaces/components/WorkspaceDrawer.json | 38 ++++++++-- 7 files changed, 137 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/features/spellchecker/index.js b/src/features/spellchecker/index.js index 94883ad17..79a2172b4 100644 --- a/src/features/spellchecker/index.js +++ b/src/features/spellchecker/index.js @@ -14,8 +14,6 @@ export default function init(stores) { autorun(() => { const { isSpellcheckerPremiumFeature } = stores.features.features; - console.log('isSpellcheckerPremiumFeature', isSpellcheckerPremiumFeature); - config.isPremium = isSpellcheckerPremiumFeature !== undefined ? isSpellcheckerPremiumFeature : DEFAULT_FEATURES_CONFIG.isSpellcheckerPremiumFeature; if (!stores.user.data.isPremium && config.isPremium && stores.settings.app.enableSpellchecking) { diff --git a/src/features/workspaces/components/WorkspaceDrawer.js b/src/features/workspaces/components/WorkspaceDrawer.js index 4d48c45ef..6eacafa68 100644 --- a/src/features/workspaces/components/WorkspaceDrawer.js +++ b/src/features/workspaces/components/WorkspaceDrawer.js @@ -2,8 +2,9 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { observer } from 'mobx-react'; import injectSheet from 'react-jss'; -import { defineMessages, intlShape } from 'react-intl'; +import { defineMessages, FormattedHTMLMessage, intlShape } from 'react-intl'; import { H1, Icon } from '@meetfranz/ui'; +import { Button } from '@meetfranz/forms/lib'; import ReactTooltip from 'react-tooltip'; import WorkspaceDrawerItem from './WorkspaceDrawerItem'; @@ -24,6 +25,14 @@ const messages = defineMessages({ id: 'workspaceDrawer.addWorkspaceTooltip', defaultMessage: '!!!Add workspace', }, + workspaceFeatureInfo: { + id: 'workspaceDrawer.workspaceFeatureInfo', + defaultMessage: '!!!Info about workspace feature', + }, + premiumCtaButtonLabel: { + id: 'workspaceDrawer.premiumCtaButtonLabel', + defaultMessage: '!!!Create your first workspace', + }, }); const styles = theme => ({ @@ -48,6 +57,19 @@ const styles = theme => ({ fill: theme.workspaceDrawerAddButtonHoverColor, }, }, + workspaces: { + height: 'auto', + }, + premiumAnnouncement: { + padding: '20px', + paddingTop: '0', + height: 'auto', + }, + premiumCtaButton: { + marginTop: '20px', + width: '100%', + color: 'white !important', + }, }); @injectSheet(styles) @observer @@ -84,7 +106,10 @@ class WorkspaceDrawer extends Component { {intl.formatMessage(messages.headline)} { + workspaceActions.openWorkspaceSettings(); + gaEvent(GA_CATEGORY_WORKSPACES, 'add', 'drawerHeadline'); + }} data-tip={`${intl.formatMessage(messages.addWorkspaceTooltip)}`} > -
- { - workspaceActions.deactivate(); - gaEvent(GA_CATEGORY_WORKSPACES, 'switch', 'drawer'); - }} - services={getServicesForWorkspace(null)} - isActive={actualWorkspace == null} - /> - {workspaces.map(workspace => ( + {workspaceStore.isPremiumUpgradeRequired ? ( +
+ +
+ ) : ( +
{ - workspaceActions.activate({ workspace }); + workspaceActions.deactivate(); gaEvent(GA_CATEGORY_WORKSPACES, 'switch', 'drawer'); }} - services={getServicesForWorkspace(workspace)} + services={getServicesForWorkspace(null)} + isActive={actualWorkspace == null} /> - ))} -
+ {workspaces.map(workspace => ( + { + workspaceActions.activate({ workspace }); + gaEvent(GA_CATEGORY_WORKSPACES, 'switch', 'drawer'); + }} + services={getServicesForWorkspace(workspace)} + /> + ))} +
+ )} ); diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js index 1fad1f71d..b141dc960 100644 --- a/src/features/workspaces/components/WorkspacesDashboard.js +++ b/src/features/workspaces/components/WorkspacesDashboard.js @@ -51,7 +51,6 @@ const messages = defineMessages({ const styles = () => ({ createForm: { height: 'auto', - marginBottom: '20px', }, appear: { height: 'auto', @@ -60,6 +59,7 @@ const styles = () => ({ padding: '20px', backgroundColor: '#3498db', marginLeft: '-20px', + marginBottom: '20px', height: 'auto', }, }); @@ -128,6 +128,13 @@ class WorkspacesDashboard extends Component { )} + {workspaceStore.isPremiumUpgradeRequired && ( +
+

{intl.formatMessage(messages.workspaceFeatureHeadline)}

+

{intl.formatMessage(messages.workspaceFeatureInfo)}

+
+ )} + - {workspaceStore.isUpgradeToPremiumRequired && ( -
-

{intl.formatMessage(messages.workspaceFeatureHeadline)}

-

{intl.formatMessage(messages.workspaceFeatureInfo)}

-
- )} {getUserWorkspacesRequest.isExecuting ? ( ) : ( diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 62bf3efb4..712945bdc 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -37,7 +37,7 @@ export default class WorkspacesStore extends FeatureStore { return getUserWorkspacesRequest.result || []; } - @computed get isUpgradeToPremiumRequired() { + @computed get isPremiumUpgradeRequired() { return this.isFeatureEnabled && !this.isFeatureActive; } diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 1747e1976..a8f4a2cbf 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -3326,39 +3326,65 @@ "defaultMessage": "!!!Workspaces", "end": { "column": 3, - "line": 18 + "line": 19 }, "file": "src/features/workspaces/components/WorkspaceDrawer.js", "id": "workspaceDrawer.headline", "start": { "column": 12, - "line": 15 + "line": 16 } }, { "defaultMessage": "!!!All services", "end": { "column": 3, - "line": 22 + "line": 23 }, "file": "src/features/workspaces/components/WorkspaceDrawer.js", "id": "workspaceDrawer.allServices", "start": { "column": 15, - "line": 19 + "line": 20 } }, { "defaultMessage": "!!!Add workspace", "end": { "column": 3, - "line": 26 + "line": 27 }, "file": "src/features/workspaces/components/WorkspaceDrawer.js", "id": "workspaceDrawer.addWorkspaceTooltip", "start": { "column": 23, - "line": 23 + "line": 24 + } + }, + { + "defaultMessage": "!!!Info about workspace feature", + "end": { + "column": 3, + "line": 31 + }, + "file": "src/features/workspaces/components/WorkspaceDrawer.js", + "id": "workspaceDrawer.workspaceFeatureInfo", + "start": { + "column": 24, + "line": 28 + } + }, + { + "defaultMessage": "!!!Create your first workspace", + "end": { + "column": 3, + "line": 35 + }, + "file": "src/features/workspaces/components/WorkspaceDrawer.js", + "id": "workspaceDrawer.premiumCtaButton", + "start": { + "column": 20, + "line": 32 } } ], diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 987262c35..981946d00 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -310,5 +310,7 @@ "workspaceDrawer.allServices": "All services", "workspaceDrawer.headline": "Workspaces", "workspaceDrawer.item.noServicesAddedYet": "No services added yet", + "workspaceDrawer.premiumCtaButtonLabel": "Create your first workspace", + "workspaceDrawer.workspaceFeatureInfo": "

Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaces.switchingIndicator.switchingTo": "Switching to" -} \ No newline at end of file +} diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json index 7026708e2..acd304253 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Workspaces", "file": "src/features/workspaces/components/WorkspaceDrawer.js", "start": { - "line": 15, + "line": 16, "column": 12 }, "end": { - "line": 18, + "line": 19, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!All services", "file": "src/features/workspaces/components/WorkspaceDrawer.js", "start": { - "line": 19, + "line": 20, "column": 15 }, "end": { - "line": 22, + "line": 23, "column": 3 } }, @@ -30,11 +30,37 @@ "defaultMessage": "!!!Add workspace", "file": "src/features/workspaces/components/WorkspaceDrawer.js", "start": { - "line": 23, + "line": 24, "column": 23 }, "end": { - "line": 26, + "line": 27, + "column": 3 + } + }, + { + "id": "workspaceDrawer.workspaceFeatureInfo", + "defaultMessage": "!!!Info about workspace feature", + "file": "src/features/workspaces/components/WorkspaceDrawer.js", + "start": { + "line": 28, + "column": 24 + }, + "end": { + "line": 31, + "column": 3 + } + }, + { + "id": "workspaceDrawer.premiumCtaButtonLabel", + "defaultMessage": "!!!Create your first workspace", + "file": "src/features/workspaces/components/WorkspaceDrawer.js", + "start": { + "line": 32, + "column": 25 + }, + "end": { + "line": 35, "column": 3 } } -- cgit v1.2.3-54-g00ecf From 6b38abc9011648a1f54b1ef3e3fb29d13750750c Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 3 Apr 2019 16:59:24 +0200 Subject: add workspace premium badge in settings nav --- .../settings/navigation/SettingsNavigation.js | 9 +++++- src/i18n/locales/defaultMessages.json | 32 +++++++++++----------- src/i18n/locales/en-US.json | 2 +- .../settings/navigation/SettingsNavigation.json | 28 +++++++++---------- src/stores/FeaturesStore.js | 7 ++++- src/styles/settings.scss | 10 +++++++ 6 files changed, 55 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index dc3c1d6f1..945285f5a 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { defineMessages, intlShape } from 'react-intl'; import { inject, observer } from 'mobx-react'; +import { Icon } from '@meetfranz/ui'; import Link from '../../ui/Link'; import { workspaceStore } from '../../../features/workspaces'; @@ -77,7 +78,13 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp > {intl.formatMessage(messages.yourWorkspaces)} {' '} - {workspaceCount} + {workspaceStore.isPremiumUpgradeRequired ? ( + + + + ) : ( + {workspaceCount} + )} ) : null} Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaces.switchingIndicator.switchingTo": "Switching to" -} +} \ No newline at end of file diff --git a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json index 96a42aa80..de78a71cf 100644 --- a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json +++ b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Available services", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 10, + "line": 11, "column": 21 }, "end": { - "line": 13, + "line": 14, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!Your services", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 14, + "line": 15, "column": 16 }, "end": { - "line": 17, + "line": 18, "column": 3 } }, @@ -30,11 +30,11 @@ "defaultMessage": "!!!Your workspaces", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 18, + "line": 19, "column": 18 }, "end": { - "line": 21, + "line": 22, "column": 3 } }, @@ -43,11 +43,11 @@ "defaultMessage": "!!!Account", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 22, + "line": 23, "column": 11 }, "end": { - "line": 25, + "line": 26, "column": 3 } }, @@ -56,11 +56,11 @@ "defaultMessage": "!!!Settings", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 26, + "line": 27, "column": 12 }, "end": { - "line": 29, + "line": 30, "column": 3 } }, @@ -69,11 +69,11 @@ "defaultMessage": "!!!Invite Friends", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 30, + "line": 31, "column": 17 }, "end": { - "line": 33, + "line": 34, "column": 3 } }, @@ -82,11 +82,11 @@ "defaultMessage": "!!!Logout", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 34, + "line": 35, "column": 10 }, "end": { - "line": 37, + "line": 38, "column": 3 } } diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index 52e38ad96..8fe576813 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js @@ -1,4 +1,9 @@ -import { computed, observable, reaction, runInAction } from 'mobx'; +import { + computed, + observable, + reaction, + runInAction, +} from 'mobx'; import Store from './lib/Store'; import CachedRequest from './lib/CachedRequest'; diff --git a/src/styles/settings.scss b/src/styles/settings.scss index 9fde9a7bf..d97d4ac2c 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss @@ -85,6 +85,11 @@ .badge { background: $dark-theme-gray-lighter; color: $dark-theme-gray-smoke; + + &.badge--pro { + background: $theme-brand-primary; + padding: 4px 6px 3px 7px; + } } &:hover { @@ -93,6 +98,11 @@ .badge { background: $dark-theme-gray-lighter; color: $dark-theme-gray-smoke; + + &.badge--pro { + background: $theme-brand-primary; + padding: 4px 6px 3px 7px; + } } } -- cgit v1.2.3-54-g00ecf From 22a9ac15fe4a1c0a23e566033acf29bb4fb9b407 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Wed, 3 Apr 2019 17:01:19 +0200 Subject: fix shitty twitter account typo --- src/features/shareFranz/Component.js | 2 +- src/i18n/locales/en-US.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/features/shareFranz/Component.js b/src/features/shareFranz/Component.js index ef43a54fa..8d1d595c5 100644 --- a/src/features/shareFranz/Component.js +++ b/src/features/shareFranz/Component.js @@ -38,7 +38,7 @@ const messages = defineMessages({ }, shareTextTwitter: { id: 'feature.shareFranz.shareText.twitter', - defaultMessage: '!!! I\'ve added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @MeetFranz', + defaultMessage: '!!! I\'ve added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @FranzMessenger', }, }); diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 7543d38bd..06cda4aca 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -9,7 +9,7 @@ "feature.shareFranz.action.twitter": "Share on Twitter", "feature.shareFranz.headline": "Franz is better together!", "feature.shareFranz.shareText.email": "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com", - "feature.shareFranz.shareText.twitter": "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @MeetFranz", + "feature.shareFranz.shareText.twitter": "I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @FranzMessenger", "feature.shareFranz.text": "Tell your friends and colleagues how awesome Franz is and help us to spread the word.", "global.api.unhealthy": "Can't connect to Franz online services", "global.notConnectedToTheInternet": "You are not connected to the internet.", @@ -282,4 +282,4 @@ "validation.url": "{field} is not a valid URL", "welcome.loginButton": "Login to your account", "welcome.signupButton": "Create a free account" -} \ No newline at end of file +} -- cgit v1.2.3-54-g00ecf From 4e5726914a0c32fc445b2aae364baf0d006024a8 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 3 Apr 2019 17:17:54 +0200 Subject: fix premium workspace badge in settings menu for light theme --- src/components/settings/navigation/SettingsNavigation.js | 2 +- src/i18n/locales/defaultMessages.json | 2 +- src/i18n/locales/en-US.json | 2 +- src/i18n/messages/src/features/shareFranz/Component.json | 2 +- src/styles/settings.scss | 13 ++++++++++++- 5 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 945285f5a..1c51d50d6 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js @@ -80,7 +80,7 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp {' '} {workspaceStore.isPremiumUpgradeRequired ? ( - + ) : ( {workspaceCount} diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 5e3988781..500053377 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -3204,7 +3204,7 @@ } }, { - "defaultMessage": "!!! I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @MeetFranz", + "defaultMessage": "!!! I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @FranzMessenger", "end": { "column": 3, "line": 42 diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index c36801d4a..9770ff0d5 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -313,4 +313,4 @@ "workspaceDrawer.premiumCtaButtonLabel": "Create your first workspace", "workspaceDrawer.workspaceFeatureInfo": "

Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaces.switchingIndicator.switchingTo": "Switching to" -} +} \ No newline at end of file diff --git a/src/i18n/messages/src/features/shareFranz/Component.json b/src/i18n/messages/src/features/shareFranz/Component.json index 0fec9db64..34a43d5a0 100644 --- a/src/i18n/messages/src/features/shareFranz/Component.json +++ b/src/i18n/messages/src/features/shareFranz/Component.json @@ -79,7 +79,7 @@ }, { "id": "feature.shareFranz.shareText.twitter", - "defaultMessage": "!!! I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @MeetFranz", + "defaultMessage": "!!! I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @FranzMessenger", "file": "src/features/shareFranz/Component.js", "start": { "line": 39, diff --git a/src/styles/settings.scss b/src/styles/settings.scss index d97d4ac2c..b4f013cad 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss @@ -433,10 +433,21 @@ text-decoration: none; transition: background $theme-transition-time, color $theme-transition-time; + .badge--pro { + background: $theme-brand-primary !important; + padding: 4px 6px 3px 7px; + + .badge-icon-pro { + fill: white; + } + } + &:hover { background: darken($theme-gray-lightest, 5%); - .badge { background: #FFF; } + .badge { + background: #FFF; + } } &.is-active { -- cgit v1.2.3-54-g00ecf From 8cc877e8ee3f0c6587a5aebdca6b4d07114e2e86 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 3 Apr 2019 17:26:45 +0200 Subject: fix active workspaces settings premium badge in light theme --- src/features/workspaces/components/WorkspacesDashboard.js | 1 + src/styles/settings.scss | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'src') diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js index b141dc960..a0a34c778 100644 --- a/src/features/workspaces/components/WorkspacesDashboard.js +++ b/src/features/workspaces/components/WorkspacesDashboard.js @@ -61,6 +61,7 @@ const styles = () => ({ marginLeft: '-20px', marginBottom: '20px', height: 'auto', + color: 'white', }, }); diff --git a/src/styles/settings.scss b/src/styles/settings.scss index b4f013cad..6340f2951 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss @@ -454,6 +454,13 @@ background: $theme-brand-primary; color: #FFF; + .badge--pro { + background: white !important; + .badge-icon-pro { + fill: $theme-brand-primary; + } + } + .badge { background: #FFF; color: $theme-brand-primary; -- cgit v1.2.3-54-g00ecf From 3abf170d41726e73580716c11956892280665d4c Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 3 Apr 2019 17:27:10 +0200 Subject: give upgrade account button a bit more padding --- src/components/ui/PremiumFeatureContainer/styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/ui/PremiumFeatureContainer/styles.js b/src/components/ui/PremiumFeatureContainer/styles.js index 615ed0a79..41881e044 100644 --- a/src/components/ui/PremiumFeatureContainer/styles.js +++ b/src/components/ui/PremiumFeatureContainer/styles.js @@ -20,7 +20,7 @@ export default theme => ({ color: theme.colorSubscriptionContainerActionButtonColor, 'margin-left': 'auto', 'border-radius': theme.borderRadiusSmall, - padding: [2, 4], + padding: [4, 8], 'font-size': 12, pointerEvents: 'initial', }, -- cgit v1.2.3-54-g00ecf From 07d10ad573d36d460acabe282d6020487e95c090 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 3 Apr 2019 17:53:50 +0200 Subject: add open last used workspace logic --- src/features/workspaces/api.js | 11 +++++++++++ src/features/workspaces/store.js | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js index 0ec20c9ea..0a3e2bfa4 100644 --- a/src/features/workspaces/api.js +++ b/src/features/workspaces/api.js @@ -1,4 +1,5 @@ import { pick } from 'lodash'; +import localStorage from 'mobx-localstorage'; import { sendAuthRequest } from '../../api/utils/auth'; import { API, API_VERSION } from '../../environment'; import Request from '../../stores/lib/Request'; @@ -51,12 +52,22 @@ export const workspaceApi = { if (!result.ok) throw result; return new Workspace(await result.json()); }, + + getWorkspaceSettings: async () => ( + localStorage.getItem('workspaces') || {} + ), + + setWorkspaceSettings: async settings => ( + localStorage.setItem('workspaces', settings) + ), }; export const getUserWorkspacesRequest = new Request(workspaceApi, 'getUserWorkspaces'); export const createWorkspaceRequest = new Request(workspaceApi, 'createWorkspace'); export const deleteWorkspaceRequest = new Request(workspaceApi, 'deleteWorkspace'); export const updateWorkspaceRequest = new Request(workspaceApi, 'updateWorkspace'); +export const getWorkspaceSettingsRequest = new Request(workspaceApi, 'getWorkspaceSettings'); +export const setWorkspaceSettingsRequest = new Request(workspaceApi, 'setWorkspaceSettings'); export const resetApiRequests = () => { getUserWorkspacesRequest.reset(); diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 712945bdc..2abb91c22 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -9,7 +9,7 @@ import { FeatureStore } from '../utils/FeatureStore'; import { createWorkspaceRequest, deleteWorkspaceRequest, - getUserWorkspacesRequest, + getUserWorkspacesRequest, getWorkspaceSettingsRequest, setWorkspaceSettingsRequest, updateWorkspaceRequest, } from './api'; @@ -37,6 +37,14 @@ export default class WorkspacesStore extends FeatureStore { return getUserWorkspacesRequest.result || []; } + @computed get settings() { + return getWorkspaceSettingsRequest.result; + } + + @computed get userHasWorkspaces() { + return getUserWorkspacesRequest.wasExecuted && this.workspaces.length > 0; + } + @computed get isPremiumUpgradeRequired() { return this.isFeatureEnabled && !this.isFeatureActive; } @@ -62,9 +70,11 @@ export default class WorkspacesStore extends FeatureStore { this._setActiveServiceOnWorkspaceSwitchReaction, this._setFeatureEnabledReaction, this._setIsPremiumFeatureReaction, + this._activateLastUsedWorkspaceReaction, ]); getUserWorkspacesRequest.execute(); + getWorkspaceSettingsRequest.execute(); this.isFeatureActive = true; } @@ -94,6 +104,13 @@ export default class WorkspacesStore extends FeatureStore { _getWorkspaceById = id => this.workspaces.find(w => w.id === id); + _updateSettings = (changes) => { + setWorkspaceSettingsRequest.execute({ + ...this.settings, + ...changes, + }); + }; + // Actions @action _edit = ({ workspace }) => { @@ -137,7 +154,10 @@ export default class WorkspacesStore extends FeatureStore { this.isSwitchingWorkspace = true; this.nextWorkspace = workspace; // Delay switching to next workspace so that the services loading does not drag down UI - setTimeout(() => { this.activeWorkspace = workspace; }, 100); + setTimeout(() => { + this.activeWorkspace = workspace; + this._updateSettings({ lastActiveWorkspace: workspace.id }); + }, 100); // Indicate that we are done switching to the next workspace setTimeout(() => { this.isSwitchingWorkspace = false; @@ -149,8 +169,12 @@ export default class WorkspacesStore extends FeatureStore { // Indicate that we are switching to default workspace this.isSwitchingWorkspace = true; this.nextWorkspace = null; + this._updateSettings({ lastActiveWorkspace: null }); + getWorkspaceSettingsRequest.execute(); // Delay switching to next workspace so that the services loading does not drag down UI - setTimeout(() => { this.activeWorkspace = null; }, 100); + setTimeout(() => { + this.activeWorkspace = null; + }, 100); // Indicate that we are done switching to the default workspace setTimeout(() => { this.isSwitchingWorkspace = false; }, 1000); }; @@ -195,4 +219,14 @@ export default class WorkspacesStore extends FeatureStore { } } }; + + _activateLastUsedWorkspaceReaction = () => { + if (!this.activeWorkspace && this.userHasWorkspaces) { + const { lastActiveWorkspace } = this.settings; + if (lastActiveWorkspace) { + const workspace = this._getWorkspaceById(lastActiveWorkspace); + if (workspace) this._setActiveWorkspace({ workspace }); + } + } + }; } -- cgit v1.2.3-54-g00ecf From 913b9e8614be3ae1e904423311d3adf55a210e5d Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 4 Apr 2019 14:02:34 +0200 Subject: use mobx-localstorage directly in the store --- src/features/workspaces/api.js | 10 ---------- src/features/workspaces/store.js | 9 ++++----- 2 files changed, 4 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js index 0a3e2bfa4..356e48cdb 100644 --- a/src/features/workspaces/api.js +++ b/src/features/workspaces/api.js @@ -52,22 +52,12 @@ export const workspaceApi = { if (!result.ok) throw result; return new Workspace(await result.json()); }, - - getWorkspaceSettings: async () => ( - localStorage.getItem('workspaces') || {} - ), - - setWorkspaceSettings: async settings => ( - localStorage.setItem('workspaces', settings) - ), }; export const getUserWorkspacesRequest = new Request(workspaceApi, 'getUserWorkspaces'); export const createWorkspaceRequest = new Request(workspaceApi, 'createWorkspace'); export const deleteWorkspaceRequest = new Request(workspaceApi, 'deleteWorkspace'); export const updateWorkspaceRequest = new Request(workspaceApi, 'updateWorkspace'); -export const getWorkspaceSettingsRequest = new Request(workspaceApi, 'getWorkspaceSettings'); -export const setWorkspaceSettingsRequest = new Request(workspaceApi, 'setWorkspaceSettings'); export const resetApiRequests = () => { getUserWorkspacesRequest.reset(); diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 2abb91c22..4d65712a7 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -3,13 +3,14 @@ import { observable, action, } from 'mobx'; +import localStorage from 'mobx-localstorage'; import { matchRoute } from '../../helpers/routing-helpers'; import { workspaceActions } from './actions'; import { FeatureStore } from '../utils/FeatureStore'; import { createWorkspaceRequest, deleteWorkspaceRequest, - getUserWorkspacesRequest, getWorkspaceSettingsRequest, setWorkspaceSettingsRequest, + getUserWorkspacesRequest, updateWorkspaceRequest, } from './api'; @@ -38,7 +39,7 @@ export default class WorkspacesStore extends FeatureStore { } @computed get settings() { - return getWorkspaceSettingsRequest.result; + return localStorage.getItem('workspaces') || {}; } @computed get userHasWorkspaces() { @@ -74,7 +75,6 @@ export default class WorkspacesStore extends FeatureStore { ]); getUserWorkspacesRequest.execute(); - getWorkspaceSettingsRequest.execute(); this.isFeatureActive = true; } @@ -105,7 +105,7 @@ export default class WorkspacesStore extends FeatureStore { _getWorkspaceById = id => this.workspaces.find(w => w.id === id); _updateSettings = (changes) => { - setWorkspaceSettingsRequest.execute({ + localStorage.setItem('workspaces', { ...this.settings, ...changes, }); @@ -170,7 +170,6 @@ export default class WorkspacesStore extends FeatureStore { this.isSwitchingWorkspace = true; this.nextWorkspace = null; this._updateSettings({ lastActiveWorkspace: null }); - getWorkspaceSettingsRequest.execute(); // Delay switching to next workspace so that the services loading does not drag down UI setTimeout(() => { this.activeWorkspace = null; -- cgit v1.2.3-54-g00ecf From 20d96420efc87560678aa233876f23970df4efdb Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 4 Apr 2019 15:58:20 +0200 Subject: fix wrong workspace tooltip shortcut in sidebar --- src/components/layout/Sidebar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index 327f76392..36c1f2e39 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js @@ -99,7 +99,7 @@ export default @observer class Sidebar extends Component { gaEvent(GA_CATEGORY_WORKSPACES, 'toggleDrawer', 'sidebar'); }} className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`} - data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${ctrlKey}+Shift+D)`} + data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${ctrlKey}+D)`} > -- cgit v1.2.3-54-g00ecf From 2243edb4aa8d837332e9727217983ec4fe334b58 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 4 Apr 2019 15:59:09 +0200 Subject: fix bug in workspace feature initialization --- src/features/workspaces/index.js | 8 ++------ src/features/workspaces/store.js | 13 +++++++------ 2 files changed, 9 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js index 524a83e3c..fb5135743 100644 --- a/src/features/workspaces/index.js +++ b/src/features/workspaces/index.js @@ -10,15 +10,11 @@ export const workspaceStore = new WorkspacesStore(); export default function initWorkspaces(stores, actions) { stores.workspaces = workspaceStore; - const { features, user } = stores; + const { features } = stores; // Toggle workspace feature reaction( - () => ( - features.features.isWorkspaceEnabled && ( - !features.features.isWorkspacePremiumFeature || user.data.isPremium - ) - ), + () => features.features.isWorkspaceEnabled, (isEnabled) => { if (isEnabled && !workspaceStore.isFeatureActive) { debug('Initializing `workspaces` feature'); diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 4d65712a7..7bd969be0 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -19,9 +19,11 @@ const debug = require('debug')('Franz:feature:workspaces:store'); export default class WorkspacesStore extends FeatureStore { @observable isFeatureEnabled = false; + @observable isFeatureActive = false; + @observable isPremiumFeature = true; - @observable isFeatureActive = false; + @observable isPremiumUpgradeRequired = true; @observable activeWorkspace = null; @@ -46,10 +48,6 @@ export default class WorkspacesStore extends FeatureStore { return getUserWorkspacesRequest.wasExecuted && this.workspaces.length > 0; } - @computed get isPremiumUpgradeRequired() { - return this.isFeatureEnabled && !this.isFeatureActive; - } - start(stores, actions) { debug('WorkspacesStore::start'); this.stores = stores; @@ -194,8 +192,11 @@ export default class WorkspacesStore extends FeatureStore { }; _setIsPremiumFeatureReaction = () => { - const { isWorkspacePremiumFeature } = this.stores.features.features; + const { features, user } = this.stores; + const { isPremium } = user.data; + const { isWorkspacePremiumFeature } = features.features; this.isPremiumFeature = isWorkspacePremiumFeature; + this.isPremiumUpgradeRequired = isWorkspacePremiumFeature && !isPremium; }; _setWorkspaceBeingEditedReaction = () => { -- cgit v1.2.3-54-g00ecf From 5ffd0230dc130bf20a0059aab3dd038683df93de Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 4 Apr 2019 15:59:29 +0200 Subject: show workspaces intro in drawer when user has none yet --- src/features/workspaces/api.js | 1 - src/features/workspaces/components/WorkspaceDrawer.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js index 356e48cdb..0ec20c9ea 100644 --- a/src/features/workspaces/api.js +++ b/src/features/workspaces/api.js @@ -1,5 +1,4 @@ import { pick } from 'lodash'; -import localStorage from 'mobx-localstorage'; import { sendAuthRequest } from '../../api/utils/auth'; import { API, API_VERSION } from '../../environment'; import Request from '../../stores/lib/Request'; diff --git a/src/features/workspaces/components/WorkspaceDrawer.js b/src/features/workspaces/components/WorkspaceDrawer.js index 6eacafa68..3602da792 100644 --- a/src/features/workspaces/components/WorkspaceDrawer.js +++ b/src/features/workspaces/components/WorkspaceDrawer.js @@ -119,7 +119,7 @@ class WorkspaceDrawer extends Component { /> - {workspaceStore.isPremiumUpgradeRequired ? ( + {!workspaceStore.userHasWorkspaces ? (
) : (
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js index a0a34c778..18813e267 100644 --- a/src/features/workspaces/components/WorkspacesDashboard.js +++ b/src/features/workspaces/components/WorkspacesDashboard.js @@ -147,38 +147,38 @@ class WorkspacesDashboard extends Component { onSubmit={onCreateWorkspaceSubmit} />
+ {getUserWorkspacesRequest.isExecuting ? ( + + ) : ( + + {/* ===== Workspace could not be loaded error ===== */} + {getUserWorkspacesRequest.error ? ( + + {intl.formatMessage(messages.workspacesRequestFailed)} + + ) : ( +
+ {/* ===== Workspaces list ===== */} + + {workspaces.map(workspace => ( + onWorkspaceClick(w)} + /> + ))} + +
+ )} +
+ )} - {getUserWorkspacesRequest.isExecuting ? ( - - ) : ( - - {/* ===== Workspace could not be loaded error ===== */} - {getUserWorkspacesRequest.error ? ( - - {intl.formatMessage(messages.workspacesRequestFailed)} - - ) : ( - - {/* ===== Workspaces list ===== */} - - {workspaces.map(workspace => ( - onWorkspaceClick(w)} - /> - ))} - -
- )} -
- )}
); diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 500053377..ec519bad5 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -3386,6 +3386,19 @@ "column": 25, "line": 32 } + }, + { + "defaultMessage": "!!!Reactivate your premium account!", + "end": { + "column": 3, + "line": 39 + }, + "file": "src/features/workspaces/components/WorkspaceDrawer.js", + "id": "workspaceDrawer.reactivatePremiumAccountLabel", + "start": { + "column": 28, + "line": 36 + } } ], "path": "src/features/workspaces/components/WorkspaceDrawer.json" diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 9770ff0d5..ed5d5e345 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -311,6 +311,7 @@ "workspaceDrawer.headline": "Workspaces", "workspaceDrawer.item.noServicesAddedYet": "No services added yet", "workspaceDrawer.premiumCtaButtonLabel": "Create your first workspace", + "workspaceDrawer.reactivatePremiumAccountLabel": "Reactivate premium account", "workspaceDrawer.workspaceFeatureInfo": "

Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaces.switchingIndicator.switchingTo": "Switching to" -} \ No newline at end of file +} diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json index acd304253..37bae262a 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json @@ -63,5 +63,18 @@ "line": 35, "column": 3 } + }, + { + "id": "workspaceDrawer.reactivatePremiumAccountLabel", + "defaultMessage": "!!!Reactivate premium account", + "file": "src/features/workspaces/components/WorkspaceDrawer.js", + "start": { + "line": 36, + "column": 28 + }, + "end": { + "line": 39, + "column": 3 + } } ] \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 387c73b2e6463238dc1c9c9ccde3c0e16ff33121 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 4 Apr 2019 16:18:33 +0200 Subject: border radius for premium intro in workspace settings --- src/features/workspaces/components/WorkspacesDashboard.js | 3 ++- src/i18n/locales/defaultMessages.json | 2 +- src/i18n/locales/en-US.json | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js index 18813e267..a8b3b376c 100644 --- a/src/features/workspaces/components/WorkspacesDashboard.js +++ b/src/features/workspaces/components/WorkspacesDashboard.js @@ -48,7 +48,7 @@ const messages = defineMessages({ }, }); -const styles = () => ({ +const styles = (theme) => ({ createForm: { height: 'auto', }, @@ -62,6 +62,7 @@ const styles = () => ({ marginBottom: '20px', height: 'auto', color: 'white', + borderRadius: theme.borderRadius, }, }); diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index ec519bad5..e5c1ea259 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -3388,7 +3388,7 @@ } }, { - "defaultMessage": "!!!Reactivate your premium account!", + "defaultMessage": "!!!Reactivate premium account", "end": { "column": 3, "line": 39 diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index ed5d5e345..c694b8729 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -314,4 +314,4 @@ "workspaceDrawer.reactivatePremiumAccountLabel": "Reactivate premium account", "workspaceDrawer.workspaceFeatureInfo": "

Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaces.switchingIndicator.switchingTo": "Switching to" -} +} \ No newline at end of file -- cgit v1.2.3-54-g00ecf From a4e4f18a17b502cd4fa16aafb57ee365084b180e Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 4 Apr 2019 16:30:33 +0200 Subject: close workspace drawer after clicking on a workspace --- src/features/workspaces/components/WorkspaceDrawer.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/features/workspaces/components/WorkspaceDrawer.js b/src/features/workspaces/components/WorkspaceDrawer.js index baf59a1fb..f35faf691 100644 --- a/src/features/workspaces/components/WorkspaceDrawer.js +++ b/src/features/workspaces/components/WorkspaceDrawer.js @@ -158,6 +158,7 @@ class WorkspaceDrawer extends Component { name={intl.formatMessage(messages.allServices)} onClick={() => { workspaceActions.deactivate(); + workspaceActions.toggleWorkspaceDrawer(); gaEvent(GA_CATEGORY_WORKSPACES, 'switch', 'drawer'); }} services={getServicesForWorkspace(null)} @@ -169,7 +170,9 @@ class WorkspaceDrawer extends Component { name={workspace.name} isActive={actualWorkspace === workspace} onClick={() => { + if (actualWorkspace === workspace) return; workspaceActions.activate({ workspace }); + workspaceActions.toggleWorkspaceDrawer(); gaEvent(GA_CATEGORY_WORKSPACES, 'switch', 'drawer'); }} services={getServicesForWorkspace(workspace)} -- cgit v1.2.3-54-g00ecf From 4346b0c0871c856d27c9ba088dcaf0e084552b12 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Thu, 4 Apr 2019 16:46:22 +0200 Subject: add hover effect for drawer workspace items --- packages/theme/src/themes/dark/index.ts | 1 + packages/theme/src/themes/default/index.ts | 1 + src/features/workspaces/components/WorkspaceDrawerItem.js | 6 ++++++ 3 files changed, 8 insertions(+) (limited to 'src') diff --git a/packages/theme/src/themes/dark/index.ts b/packages/theme/src/themes/dark/index.ts index cb7ffc1cf..1c0ede8e5 100644 --- a/packages/theme/src/themes/dark/index.ts +++ b/packages/theme/src/themes/dark/index.ts @@ -69,6 +69,7 @@ export const workspaceDrawerBackground = color(colorBackground).lighten(0.3).hex export const workspaceDrawerAddButtonColor = legacyStyles.darkThemeGrayLighter; export const workspaceDrawerAddButtonHoverColor = legacyStyles.darkThemeGraySmoke; export const workspaceDrawerItemBorder = color(workspaceDrawerBackground).lighten(0.2).hex(); +export const workspaceDrawerItemHoverBackground = color(workspaceDrawerBackground).lighten(0.2).hex(); export const workspaceDrawerItemActiveBackground = defaultStyles.brandPrimary; export const workspaceDrawerItemNameColor = colorText; export const workspaceDrawerItemNameActiveColor = 'white'; diff --git a/packages/theme/src/themes/default/index.ts b/packages/theme/src/themes/default/index.ts index f2632ee20..718ccf485 100644 --- a/packages/theme/src/themes/default/index.ts +++ b/packages/theme/src/themes/default/index.ts @@ -149,6 +149,7 @@ export const workspaceDrawerPadding = 20; export const workspaceDrawerBackground = color(colorBackground).lighten(0.1).hex(); export const workspaceDrawerAddButtonColor = legacyStyles.themeGrayLight; export const workspaceDrawerAddButtonHoverColor = color(legacyStyles.themeGrayLight).lighten(0.1).hex(); +export const workspaceDrawerItemHoverBackground = color(workspaceDrawerBackground).darken(0.01).hex(); export const workspaceDrawerItemActiveBackground = legacyStyles.themeGrayLightest; export const workspaceDrawerItemBorder = color(workspaceDrawerBackground).darken(0.05).hex(); export const workspaceDrawerItemNameColor = colorText; diff --git a/src/features/workspaces/components/WorkspaceDrawerItem.js b/src/features/workspaces/components/WorkspaceDrawerItem.js index 1e28ebea6..17a7882b8 100644 --- a/src/features/workspaces/components/WorkspaceDrawerItem.js +++ b/src/features/workspaces/components/WorkspaceDrawerItem.js @@ -20,9 +20,15 @@ const styles = theme => ({ '&:first-child': { borderTop: `1px solid ${theme.workspaceDrawerItemBorder}`, }, + '&:hover': { + backgroundColor: theme.workspaceDrawerItemHoverBackground, + }, }, isActiveItem: { backgroundColor: theme.workspaceDrawerItemActiveBackground, + '&:hover': { + backgroundColor: theme.workspaceDrawerItemActiveBackground, + }, }, name: { marginTop: '4px', -- cgit v1.2.3-54-g00ecf From 05d13dea31861df7366dfe40395c1b04462d02ce Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Fri, 5 Apr 2019 20:46:10 +0200 Subject: ensure drawer is open on workspace settings routes --- src/app.js | 5 +++-- src/features/workspaces/index.js | 5 +++++ src/features/workspaces/store.js | 26 ++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/app.js b/src/app.js index d3b540f62..fb9f1c6ab 100644 --- a/src/app.js +++ b/src/app.js @@ -41,6 +41,7 @@ import AuthLayoutContainer from './containers/auth/AuthLayoutContainer'; import SubscriptionPopupScreen from './containers/subscription/SubscriptionPopupScreen'; import WorkspacesScreen from './features/workspaces/containers/WorkspacesScreen'; import EditWorkspaceScreen from './features/workspaces/containers/EditWorkspaceScreen'; +import { WORKSPACES_ROUTES } from './features/workspaces'; // Add Polyfills smoothScroll.polyfill(); @@ -77,8 +78,8 @@ window.addEventListener('load', () => { - - + + diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js index fb5135743..ad9023b8b 100644 --- a/src/features/workspaces/index.js +++ b/src/features/workspaces/index.js @@ -30,3 +30,8 @@ export default function initWorkspaces(stores, actions) { }, ); } + +export const WORKSPACES_ROUTES = { + ROOT: '/settings/workspaces', + EDIT: '/settings/workspaces/:action/:id', +}; diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 7bd969be0..2e1764f99 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -13,6 +13,7 @@ import { getUserWorkspacesRequest, updateWorkspaceRequest, } from './api'; +import { WORKSPACES_ROUTES } from './index'; const debug = require('debug')('Franz:feature:workspaces:store'); @@ -70,6 +71,7 @@ export default class WorkspacesStore extends FeatureStore { this._setFeatureEnabledReaction, this._setIsPremiumFeatureReaction, this._activateLastUsedWorkspaceReaction, + this._openDrawerWithSettingsReaction, ]); getUserWorkspacesRequest.execute(); @@ -100,6 +102,10 @@ export default class WorkspacesStore extends FeatureStore { // ========== PRIVATE ========= // + _wasDrawerOpenBeforeSettingsRoute = null; + + _isSettingsRouteActive = null; + _getWorkspaceById = id => this.workspaces.find(w => w.id === id); _updateSettings = (changes) => { @@ -229,4 +235,24 @@ export default class WorkspacesStore extends FeatureStore { } } }; + + _openDrawerWithSettingsReaction = () => { + const { router } = this.stores; + const isWorkspaceSettingsRoute = router.location.pathname.includes(WORKSPACES_ROUTES.ROOT); + const isSwitchingToSettingsRoute = !this._isSettingsRouteActive && isWorkspaceSettingsRoute; + const isLeavingSettingsRoute = !isWorkspaceSettingsRoute && this._isSettingsRouteActive; + + if (isSwitchingToSettingsRoute) { + this._isSettingsRouteActive = true; + this._wasDrawerOpenBeforeSettingsRoute = this.isWorkspaceDrawerOpen; + if (!this._wasDrawerOpenBeforeSettingsRoute) { + workspaceActions.toggleWorkspaceDrawer(); + } + } else if (isLeavingSettingsRoute) { + this._isSettingsRouteActive = false; + if (!this._wasDrawerOpenBeforeSettingsRoute && this.isWorkspaceDrawerOpen) { + workspaceActions.toggleWorkspaceDrawer(); + } + } + }; } -- cgit v1.2.3-54-g00ecf From 7caccf36dd55a8c7ac9dcd5e154634607adf5ef6 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Fri, 5 Apr 2019 21:02:55 +0200 Subject: add small text label for adding new workspace to drawer --- .../workspaces/components/WorkspaceDrawer.js | 42 ++++++++++++++++++++-- src/i18n/locales/defaultMessages.json | 13 +++++++ src/i18n/locales/en-US.json | 1 + .../workspaces/components/WorkspaceDrawer.json | 13 +++++++ 4 files changed, 67 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/components/WorkspaceDrawer.js b/src/features/workspaces/components/WorkspaceDrawer.js index f35faf691..0befcc869 100644 --- a/src/features/workspaces/components/WorkspaceDrawer.js +++ b/src/features/workspaces/components/WorkspaceDrawer.js @@ -37,6 +37,10 @@ const messages = defineMessages({ id: 'workspaceDrawer.reactivatePremiumAccountLabel', defaultMessage: '!!!Reactivate premium account', }, + addNewWorkspaceLabel: { + id: 'workspaceDrawer.addNewWorkspaceLabel', + defaultMessage: '!!!add new workspace', + }, }); const styles = theme => ({ @@ -48,11 +52,11 @@ const styles = theme => ({ fontSize: '24px', marginTop: '38px', marginBottom: '25px', - marginLeft: `${theme.workspaceDrawerPadding}px`, + marginLeft: theme.workspaceDrawerPadding, }, addWorkspaceButton: { float: 'right', - marginRight: `${theme.workspaceDrawerPadding}px`, + marginRight: theme.workspaceDrawerPadding, marginTop: '2px', }, addWorkspaceButtonIcon: { @@ -74,6 +78,24 @@ const styles = theme => ({ width: '100%', color: 'white !important', }, + addNewWorkspaceLabel: { + height: 'auto', + color: theme.workspaceDrawerServicesColor, + marginTop: 20, + marginLeft: theme.workspaceDrawerPadding, + '& > span': { + fontSize: '13px', + marginLeft: 10, + position: 'relative', + top: -3, + }, + '&:hover': { + color: theme.workspaceDrawerAddButtonHoverColor, + '& > svg': { + fill: theme.workspaceDrawerAddButtonHoverColor, + }, + }, + }, }); @injectSheet(styles) @observer @@ -180,6 +202,22 @@ class WorkspaceDrawer extends Component { ))}
)} +
{ + workspaceActions.openWorkspaceSettings(); + gaEvent(GA_CATEGORY_WORKSPACES, 'add', 'drawerAddLabel'); + }} + > + + + {intl.formatMessage(messages.addNewWorkspaceLabel)} + +
); diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index e5c1ea259..05df4cbac 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -3399,6 +3399,19 @@ "column": 28, "line": 36 } + }, + { + "defaultMessage": "!!!add new workspace", + "end": { + "column": 3, + "line": 43 + }, + "file": "src/features/workspaces/components/WorkspaceDrawer.js", + "id": "workspaceDrawer.addNewWorkspaceLabel", + "start": { + "column": 24, + "line": 40 + } } ], "path": "src/features/workspaces/components/WorkspaceDrawer.json" diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index c694b8729..78dcd83d7 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -306,6 +306,7 @@ "validation.url": "{field} is not a valid URL", "welcome.loginButton": "Login to your account", "welcome.signupButton": "Create a free account", + "workspaceDrawer.addNewWorkspaceLabel": "add new workspace", "workspaceDrawer.addWorkspaceTooltip": "Add workspace", "workspaceDrawer.allServices": "All services", "workspaceDrawer.headline": "Workspaces", diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json index 37bae262a..9b0b80321 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json @@ -76,5 +76,18 @@ "line": 39, "column": 3 } + }, + { + "id": "workspaceDrawer.addNewWorkspaceLabel", + "defaultMessage": "!!!add new workspace", + "file": "src/features/workspaces/components/WorkspaceDrawer.js", + "start": { + "line": 40, + "column": 24 + }, + "end": { + "line": 43, + "column": 3 + } } ] \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 1fa1e165b159adf390375787df2af9b33e5f5856 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Sat, 6 Apr 2019 10:05:16 +0200 Subject: make workspace settings list items taller --- packages/theme/src/themes/dark/index.ts | 6 +++++ packages/theme/src/themes/default/index.ts | 6 +++++ .../workspaces/components/WorkspaceItem.js | 31 ++++++++++++---------- 3 files changed, 29 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/packages/theme/src/themes/dark/index.ts b/packages/theme/src/themes/dark/index.ts index 1c0ede8e5..a9d1e1b46 100644 --- a/packages/theme/src/themes/dark/index.ts +++ b/packages/theme/src/themes/dark/index.ts @@ -64,6 +64,12 @@ export const selectSearchColor = inputBackground; // Modal export const colorModalOverlayBackground = color(legacyStyles.darkThemeBlack).alpha(0.8).rgb().string(); +// Workspace settings +export const workspaceSettings = { + listItemBorderColor: legacyStyles.darkThemeGrayDarker, + listItemHoverBgColor: legacyStyles.darkThemeGrayDarker, +}; + // Workspace Drawer export const workspaceDrawerBackground = color(colorBackground).lighten(0.3).hex(); export const workspaceDrawerAddButtonColor = legacyStyles.darkThemeGrayLighter; diff --git a/packages/theme/src/themes/default/index.ts b/packages/theme/src/themes/default/index.ts index 718ccf485..e4c74a5c9 100644 --- a/packages/theme/src/themes/default/index.ts +++ b/packages/theme/src/themes/default/index.ts @@ -143,6 +143,12 @@ export const badgeBorderRadius = 50; // Modal export const colorModalOverlayBackground = color('#000').alpha(0.5).rgb().string(); +// Workspace settings +export const workspaceSettings = { + listItemBorderColor: legacyStyles.themeGrayLightest, + listItemHoverBgColor: legacyStyles.themeGrayLightest, +}; + // Workspace Drawer export const workspaceDrawerWidth = 300; export const workspaceDrawerPadding = 20; diff --git a/src/features/workspaces/components/WorkspaceItem.js b/src/features/workspaces/components/WorkspaceItem.js index b2c2a4830..a950a981a 100644 --- a/src/features/workspaces/components/WorkspaceItem.js +++ b/src/features/workspaces/components/WorkspaceItem.js @@ -2,14 +2,25 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { intlShape } from 'react-intl'; import { observer } from 'mobx-react'; -import classnames from 'classnames'; +import injectSheet from 'react-jss'; + import Workspace from '../models/Workspace'; -// const messages = defineMessages({}); +const styles = theme => ({ + row: { + height: 57, + borderBottom: `1px solid ${theme.workspaceSettings.listItemBorderColor}`, + '&:hover': { + background: theme.workspaceSettings.listItemHoverBgColor, + }, + }, + columnName: {}, +}); -@observer +@injectSheet(styles) @observer class WorkspaceItem extends Component { static propTypes = { + classes: PropTypes.object.isRequired, workspace: PropTypes.instanceOf(Workspace).isRequired, onItemClick: PropTypes.func.isRequired, }; @@ -19,19 +30,11 @@ class WorkspaceItem extends Component { }; render() { - const { workspace, onItemClick } = this.props; - // const { intl } = this.context; + const { classes, workspace, onItemClick } = this.props; return ( - - onItemClick(workspace)} - > + + onItemClick(workspace)}> {workspace.name} -- cgit v1.2.3-54-g00ecf From 625c3b0ab1ede0a7d54992e9a5f25bfd702e7952 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Sat, 6 Apr 2019 10:11:14 +0200 Subject: refactor workspace table css away from legacy styles --- .../workspaces/components/WorkspacesDashboard.js | 10 +++- .../workspaces/styles/workspaces-table.scss | 53 ---------------------- src/styles/main.scss | 3 -- 3 files changed, 8 insertions(+), 58 deletions(-) delete mode 100644 src/features/workspaces/styles/workspaces-table.scss (limited to 'src') diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js index a8b3b376c..dd4381a15 100644 --- a/src/features/workspaces/components/WorkspacesDashboard.js +++ b/src/features/workspaces/components/WorkspacesDashboard.js @@ -48,7 +48,13 @@ const messages = defineMessages({ }, }); -const styles = (theme) => ({ +const styles = theme => ({ + table: { + width: '100%', + '& td': { + padding: '10px', + }, + }, createForm: { height: 'auto', }, @@ -164,7 +170,7 @@ class WorkspacesDashboard extends Component { {intl.formatMessage(messages.workspacesRequestFailed)} ) : ( - +
{/* ===== Workspaces list ===== */} {workspaces.map(workspace => ( diff --git a/src/features/workspaces/styles/workspaces-table.scss b/src/features/workspaces/styles/workspaces-table.scss deleted file mode 100644 index 6d0e7b4f5..000000000 --- a/src/features/workspaces/styles/workspaces-table.scss +++ /dev/null @@ -1,53 +0,0 @@ -@import '../../../styles/config'; - -.theme__dark .workspace-table { - .workspace-table__column-info .mdi { color: $dark-theme-gray-lightest; } - - .workspace-table__row { - border-bottom: 1px solid $dark-theme-gray-darker; - - &:hover { background: $dark-theme-gray-darker; } - &.workspace-table__row--disabled { color: $dark-theme-gray; } - } -} - -.workspace-table { - width: 100%; - - .workspace-table__toggle { - width: 60px; - - .franz-form__field { - margin-bottom: 0; - } - } - - .workspace-table__column-action { - width: 40px - } - - .workspace-table__column-info { - width: 40px; - - .mdi { - color: $theme-gray-light; - display: block; - font-size: 18px; - } - } - - .workspace-table__row { - border-bottom: 1px solid $theme-gray-lightest; - - &:hover { - cursor: initial; - background: $theme-gray-lightest; - } - - &.workspace-table__row--disabled { - color: $theme-gray-light; - } - } - - td { padding: 10px; } -} diff --git a/src/styles/main.scss b/src/styles/main.scss index 9ba7f5827..784a04d3d 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -31,9 +31,6 @@ $mdi-font-path: '../node_modules/mdi/fonts'; @import './invite.scss'; @import './title-bar.scss'; -// Workspaces legacy css -@import '../features/workspaces/styles/workspaces-table'; - // form @import './input.scss'; @import './radio.scss'; -- cgit v1.2.3-54-g00ecf From b3afb9f45d47ebc352b28eb106b22fffc2f17707 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Sun, 7 Apr 2019 19:50:40 +0200 Subject: render workspace service list like services + toggle --- packages/forms/src/input/index.tsx | 1 + packages/forms/src/input/styles.ts | 5 ++ packages/forms/src/label/styles.ts | 4 +- packages/forms/src/select/index.tsx | 6 ++ packages/forms/src/toggle/index.tsx | 4 +- packages/theme/src/themes/dark/index.ts | 52 ++++++++++++++++- packages/theme/src/themes/default/index.ts | 57 +++++++++++++++++- src/components/ui/ServiceIcon.js | 67 ++++++++++++++++++++++ .../workspaces/components/EditWorkspaceForm.js | 4 +- .../workspaces/components/ServiceListItem.js | 48 ---------------- .../workspaces/components/WorkspaceItem.js | 6 +- .../components/WorkspaceServiceListItem.js | 50 ++++++++++++++++ 12 files changed, 243 insertions(+), 61 deletions(-) create mode 100644 src/components/ui/ServiceIcon.js delete mode 100644 src/features/workspaces/components/ServiceListItem.js create mode 100644 src/features/workspaces/components/WorkspaceServiceListItem.js (limited to 'src') diff --git a/packages/forms/src/input/index.tsx b/packages/forms/src/input/index.tsx index f89c91be5..e410f8fef 100644 --- a/packages/forms/src/input/index.tsx +++ b/packages/forms/src/input/index.tsx @@ -131,6 +131,7 @@ class InputComponent extends Component { title={label} showLabel={showLabel} htmlFor={id} + className={classes.label} >
({ }); export default (theme: Theme) => ({ + label: { + '& > div': { + marginTop: 5, + } + }, disabled: { opacity: theme.inputDisabledOpacity, }, diff --git a/packages/forms/src/label/styles.ts b/packages/forms/src/label/styles.ts index f3998de04..c64c9b285 100644 --- a/packages/forms/src/label/styles.ts +++ b/packages/forms/src/label/styles.ts @@ -1,9 +1,7 @@ import { Theme } from '../../../theme/lib'; export default (theme: Theme) => ({ - content: { - marginTop: 5, - }, + content: {}, label: { color: theme.labelColor, fontSize: theme.uiFontSize, diff --git a/packages/forms/src/select/index.tsx b/packages/forms/src/select/index.tsx index 4a9e3c56e..cfbe91dda 100644 --- a/packages/forms/src/select/index.tsx +++ b/packages/forms/src/select/index.tsx @@ -56,6 +56,11 @@ const styles = (theme: Theme) => ({ textAlign: 'left', color: theme.selectColor, }, + label: { + '& > div': { + marginTop: 5, + } + }, popup: { opacity: 0, height: 0, @@ -334,6 +339,7 @@ class SelectComponent extends Component { title={label} showLabel={showLabel} htmlFor={id} + className={classes.label} >
({ }, toggleLabel: { display: 'flex', + alignItems: 'center', '& > span': { order: 1, marginLeft: 15, - marginTop: 2, }, }, }); diff --git a/packages/theme/src/themes/dark/index.ts b/packages/theme/src/themes/dark/index.ts index a9d1e1b46..73ffa7f5e 100644 --- a/packages/theme/src/themes/dark/index.ts +++ b/packages/theme/src/themes/dark/index.ts @@ -1,4 +1,5 @@ import color from 'color'; +import { merge, cloneDeep } from 'lodash'; import * as defaultStyles from '../default'; import * as legacyStyles from '../legacy'; @@ -64,11 +65,51 @@ export const selectSearchColor = inputBackground; // Modal export const colorModalOverlayBackground = color(legacyStyles.darkThemeBlack).alpha(0.8).rgb().string(); +// Services +export const services = merge({}, defaultStyles.services, { + listItems: { + borderColor: legacyStyles.darkThemeGrayDarker, + hoverBgColor: legacyStyles.darkThemeGrayDarker, + disabled: { + color: legacyStyles.darkThemeGray, + }, + }, +}); + +// Workspaces +const drawerBg = color(colorBackground).lighten(0.3).hex(); + +export const workspaces = merge({}, defaultStyles.workspaces, { + settings: { + listItems: cloneDeep(services.listItems), + }, + drawer: { + background: drawerBg, + addButton: { + color: legacyStyles.darkThemeGrayLighter, + hoverColor: legacyStyles.darkThemeGraySmoke, + }, + listItem: { + border: color(drawerBg).lighten(0.2).hex(), + hoverBackground: color(drawerBg).lighten(0.2).hex(), + activeBackground: defaultStyles.brandPrimary, + name: { + color: colorText, + activeColor: 'white', + }, + services: { + color: color(colorText).darken(0.5).hex(), + active: color(defaultStyles.brandPrimary).lighten(0.5).hex(), + }, + }, + }, +}); + // Workspace settings -export const workspaceSettings = { +export const workspaceSettings = merge({}, defaultStyles.workspaceSettings, { listItemBorderColor: legacyStyles.darkThemeGrayDarker, listItemHoverBgColor: legacyStyles.darkThemeGrayDarker, -}; +}); // Workspace Drawer export const workspaceDrawerBackground = color(colorBackground).lighten(0.3).hex(); @@ -81,3 +122,10 @@ export const workspaceDrawerItemNameColor = colorText; export const workspaceDrawerItemNameActiveColor = 'white'; export const workspaceDrawerServicesColor = color(colorText).darken(0.5).hex(); export const workspaceDrawerServicesActiveColor = color(defaultStyles.brandPrimary).lighten(0.5).hex(); + +// Service Icon +export const serviceIcon = merge({}, defaultStyles.serviceIcon, { + isCustom: { + border: `1px solid ${legacyStyles.darkThemeGrayDark}`, + }, +}); diff --git a/packages/theme/src/themes/default/index.ts b/packages/theme/src/themes/default/index.ts index e4c74a5c9..d2b9014b4 100644 --- a/packages/theme/src/themes/default/index.ts +++ b/packages/theme/src/themes/default/index.ts @@ -1,4 +1,5 @@ import color from 'color'; +import { cloneDeep } from 'lodash'; import * as legacyStyles from '../legacy'; @@ -143,8 +144,52 @@ export const badgeBorderRadius = 50; // Modal export const colorModalOverlayBackground = color('#000').alpha(0.5).rgb().string(); -// Workspace settings +// Services +export const services = { + listItems: { + padding: 10, + height: 57, + borderColor: legacyStyles.themeGrayLightest, + hoverBgColor: legacyStyles.themeGrayLightest, + disabled: { + color: legacyStyles.themeGrayLight, + }, + }, +}; + +// Workspaces +const drawerBg = color(colorBackground).lighten(0.1).hex(); + +export const workspaces = { + settings: { + listItems: cloneDeep(services.listItems), + }, + drawer: { + width: 300, + padding: 20, + background: drawerBg, + addButton: { + color: legacyStyles.themeGrayLight, + hoverColor: color(legacyStyles.themeGrayLight).lighten(0.1).hex(), + }, + listItem: { + hoverBackground: color(drawerBg).darken(0.01).hex(), + activeBackground: legacyStyles.themeGrayLightest, + border: color(drawerBg).darken(0.05).hex(), + name: { + color: colorText, + activeColor: colorText, + }, + services: { + color: color(colorText).lighten(1.5).hex(), + active: color(colorText).lighten(1.5).hex(), + }, + }, + }, +}; + export const workspaceSettings = { + listItemHeight: 57, listItemBorderColor: legacyStyles.themeGrayLightest, listItemHoverBgColor: legacyStyles.themeGrayLightest, }; @@ -162,3 +207,13 @@ export const workspaceDrawerItemNameColor = colorText; export const workspaceDrawerItemNameActiveColor = colorText; export const workspaceDrawerServicesColor = color(colorText).lighten(1.5).hex(); export const workspaceDrawerServicesActiveColor = workspaceDrawerServicesColor; + +// Service Icon +export const serviceIcon = { + width: 35, + isCustom: { + border: `1px solid ${legacyStyles.themeGrayLighter}`, + borderRadius: legacyStyles.themeBorderRadius, + width: 37, + }, +}; diff --git a/src/components/ui/ServiceIcon.js b/src/components/ui/ServiceIcon.js new file mode 100644 index 000000000..0b9155a4e --- /dev/null +++ b/src/components/ui/ServiceIcon.js @@ -0,0 +1,67 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { observer } from 'mobx-react'; +import injectSheet from 'react-jss'; +import classnames from 'classnames'; + +import ServiceModel from '../../models/Service'; + +const styles = theme => ({ + root: { + height: 'auto', + }, + icon: { + width: theme.serviceIcon.width, + }, + isCustomIcon: { + width: theme.serviceIcon.isCustom.width, + border: theme.serviceIcon.isCustom.border, + borderRadius: theme.serviceIcon.isCustom.borderRadius, + }, + isDisabled: { + filter: 'grayscale(100%)', + opacity: '.5', + }, +}); + +@injectSheet(styles) @observer +class ServiceIcon extends Component { + static propTypes = { + classes: PropTypes.object.isRequired, + service: PropTypes.instanceOf(ServiceModel).isRequired, + className: PropTypes.string, + }; + + static defaultProps = { + className: '', + }; + + render() { + const { + classes, + className, + service, + } = this.props; + + return ( +
+ +
+ ); + } +} + +export default ServiceIcon; diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js index e4bf44248..bba4485ff 100644 --- a/src/features/workspaces/components/EditWorkspaceForm.js +++ b/src/features/workspaces/components/EditWorkspaceForm.js @@ -10,7 +10,7 @@ import Workspace from '../models/Workspace'; import Service from '../../../models/Service'; import Form from '../../../lib/Form'; import { required } from '../../../helpers/validation-helpers'; -import ServiceListItem from './ServiceListItem'; +import WorkspaceServiceListItem from './WorkspaceServiceListItem'; import Request from '../../../stores/lib/Request'; import { gaEvent } from '../../../lib/analytics'; import { GA_CATEGORY_WORKSPACES } from '../index'; @@ -151,7 +151,7 @@ class EditWorkspaceForm extends Component {

{intl.formatMessage(messages.servicesInWorkspaceHeadline)}

{services.map(s => ( - ({ - service: { - height: 'auto', - display: 'flex', - }, - name: { - marginTop: '4px', - }, -}); - -@injectSheet(styles) @observer -class ServiceListItem extends Component { - static propTypes = { - classes: PropTypes.object.isRequired, - isInWorkspace: PropTypes.bool.isRequired, - onToggle: PropTypes.func.isRequired, - service: PropTypes.instanceOf(Service).isRequired, - }; - - render() { - const { - classes, - isInWorkspace, - onToggle, - service, - } = this.props; - - return ( -
- -
- ); - } -} - -export default ServiceListItem; diff --git a/src/features/workspaces/components/WorkspaceItem.js b/src/features/workspaces/components/WorkspaceItem.js index a950a981a..cc4b1a3ba 100644 --- a/src/features/workspaces/components/WorkspaceItem.js +++ b/src/features/workspaces/components/WorkspaceItem.js @@ -8,10 +8,10 @@ import Workspace from '../models/Workspace'; const styles = theme => ({ row: { - height: 57, - borderBottom: `1px solid ${theme.workspaceSettings.listItemBorderColor}`, + height: theme.workspaces.settings.listItems.height, + borderBottom: `1px solid ${theme.workspaces.settings.listItems.borderColor}`, '&:hover': { - background: theme.workspaceSettings.listItemHoverBgColor, + background: theme.workspaces.settings.listItems.hoverBgColor, }, }, columnName: {}, diff --git a/src/features/workspaces/components/WorkspaceServiceListItem.js b/src/features/workspaces/components/WorkspaceServiceListItem.js new file mode 100644 index 000000000..7b516d056 --- /dev/null +++ b/src/features/workspaces/components/WorkspaceServiceListItem.js @@ -0,0 +1,50 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { observer } from 'mobx-react'; +import injectSheet from 'react-jss'; +import { Toggle } from '@meetfranz/forms'; + +import Service from '../../../models/Service'; +import ServiceIcon from '../../../components/ui/ServiceIcon'; + +const styles = theme => ({ + service: { + height: theme.workspaceSettings.listItemHeight, + display: 'flex', + }, + name: { + marginTop: '4px', + }, +}); + +@injectSheet(styles) @observer +class ServiceListItem extends Component { + static propTypes = { + classes: PropTypes.object.isRequired, + isInWorkspace: PropTypes.bool.isRequired, + onToggle: PropTypes.func.isRequired, + service: PropTypes.instanceOf(Service).isRequired, + }; + + render() { + const { + classes, + isInWorkspace, + onToggle, + service, + } = this.props; + + return ( +
+ + +
+ ); + } +} + +export default ServiceListItem; -- cgit v1.2.3-54-g00ecf From 4421584d41a5182b0f93f0ed7e3c73d34f98d3de Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Sun, 7 Apr 2019 19:56:00 +0200 Subject: change plus icon in workspace drawer to settings icon --- .../workspaces/components/WorkspaceDrawer.js | 22 +++++------ .../components/WorkspaceServiceListItem.js | 43 +++++++++++++++++----- src/i18n/locales/defaultMessages.json | 6 +-- src/i18n/locales/en-US.json | 2 +- .../workspaces/components/WorkspaceDrawer.json | 6 +-- 5 files changed, 52 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/components/WorkspaceDrawer.js b/src/features/workspaces/components/WorkspaceDrawer.js index 0befcc869..bb77aa72d 100644 --- a/src/features/workspaces/components/WorkspaceDrawer.js +++ b/src/features/workspaces/components/WorkspaceDrawer.js @@ -21,9 +21,9 @@ const messages = defineMessages({ id: 'workspaceDrawer.allServices', defaultMessage: '!!!All services', }, - addWorkspaceTooltip: { - id: 'workspaceDrawer.addWorkspaceTooltip', - defaultMessage: '!!!Add workspace', + workspacesSettingsTooltip: { + id: 'workspaceDrawer.workspacesSettingsTooltip', + defaultMessage: '!!!Workspaces settings', }, workspaceFeatureInfo: { id: 'workspaceDrawer.workspaceFeatureInfo', @@ -54,12 +54,12 @@ const styles = theme => ({ marginBottom: '25px', marginLeft: theme.workspaceDrawerPadding, }, - addWorkspaceButton: { + workspacesSettingsButton: { float: 'right', marginRight: theme.workspaceDrawerPadding, marginTop: '2px', }, - addWorkspaceButtonIcon: { + workspacesSettingsButtonIcon: { fill: theme.workspaceDrawerAddButtonColor, '&:hover': { fill: theme.workspaceDrawerAddButtonHoverColor, @@ -133,17 +133,17 @@ class WorkspaceDrawer extends Component {

{intl.formatMessage(messages.headline)} { workspaceActions.openWorkspaceSettings(); - gaEvent(GA_CATEGORY_WORKSPACES, 'add', 'drawerHeadline'); + gaEvent(GA_CATEGORY_WORKSPACES, 'settings', 'drawerHeadline'); }} - data-tip={`${intl.formatMessage(messages.addWorkspaceTooltip)}`} + data-tip={`${intl.formatMessage(messages.workspacesSettingsTooltip)}`} >

@@ -212,7 +212,7 @@ class WorkspaceDrawer extends Component { {intl.formatMessage(messages.addNewWorkspaceLabel)} diff --git a/src/features/workspaces/components/WorkspaceServiceListItem.js b/src/features/workspaces/components/WorkspaceServiceListItem.js index 7b516d056..e05b21440 100644 --- a/src/features/workspaces/components/WorkspaceServiceListItem.js +++ b/src/features/workspaces/components/WorkspaceServiceListItem.js @@ -2,23 +2,37 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { observer } from 'mobx-react'; import injectSheet from 'react-jss'; +import classnames from 'classnames'; import { Toggle } from '@meetfranz/forms'; import Service from '../../../models/Service'; import ServiceIcon from '../../../components/ui/ServiceIcon'; const styles = theme => ({ - service: { - height: theme.workspaceSettings.listItemHeight, + listItem: { + height: theme.workspaces.settings.listItems.height, + borderBottom: `1px solid ${theme.workspaces.settings.listItems.borderColor}`, display: 'flex', + alignItems: 'center', }, - name: { - marginTop: '4px', + serviceIcon: { + padding: theme.workspaces.settings.listItems.padding, + }, + toggle: { + height: 'auto', + margin: 0, + }, + label: { + padding: theme.workspaces.settings.listItems.padding, + flexGrow: 1, + }, + disabledLabel: { + color: theme.workspaces.settings.listItems.disabled.color, }, }); @injectSheet(styles) @observer -class ServiceListItem extends Component { +class WorkspaceServiceListItem extends Component { static propTypes = { classes: PropTypes.object.isRequired, isInWorkspace: PropTypes.bool.isRequired, @@ -35,16 +49,27 @@ class ServiceListItem extends Component { } = this.props; return ( -
- +
+ + + {service.name} +
); } } -export default ServiceListItem; +export default WorkspaceServiceListItem; diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 05df4cbac..f882e6030 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -3349,15 +3349,15 @@ } }, { - "defaultMessage": "!!!Add workspace", + "defaultMessage": "!!!Workspaces settings", "end": { "column": 3, "line": 27 }, "file": "src/features/workspaces/components/WorkspaceDrawer.js", - "id": "workspaceDrawer.addWorkspaceTooltip", + "id": "workspaceDrawer.workspacesSettingsTooltip", "start": { - "column": 23, + "column": 29, "line": 24 } }, diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 78dcd83d7..e55489418 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -307,12 +307,12 @@ "welcome.loginButton": "Login to your account", "welcome.signupButton": "Create a free account", "workspaceDrawer.addNewWorkspaceLabel": "add new workspace", - "workspaceDrawer.addWorkspaceTooltip": "Add workspace", "workspaceDrawer.allServices": "All services", "workspaceDrawer.headline": "Workspaces", "workspaceDrawer.item.noServicesAddedYet": "No services added yet", "workspaceDrawer.premiumCtaButtonLabel": "Create your first workspace", "workspaceDrawer.reactivatePremiumAccountLabel": "Reactivate premium account", "workspaceDrawer.workspaceFeatureInfo": "

Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", + "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", "workspaces.switchingIndicator.switchingTo": "Switching to" } \ No newline at end of file diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json index 9b0b80321..d347622d2 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json @@ -26,12 +26,12 @@ } }, { - "id": "workspaceDrawer.addWorkspaceTooltip", - "defaultMessage": "!!!Add workspace", + "id": "workspaceDrawer.workspacesSettingsTooltip", + "defaultMessage": "!!!Workspaces settings", "file": "src/features/workspaces/components/WorkspaceDrawer.js", "start": { "line": 24, - "column": 23 + "column": 29 }, "end": { "line": 27, -- cgit v1.2.3-54-g00ecf From 142880f89f30eff57ec3ffa45efe6c241474697b Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 10 Apr 2019 10:53:54 +0200 Subject: autofocus create workspace input field --- src/features/workspaces/components/CreateWorkspaceForm.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js index 0be2d528f..2c00ea63c 100644 --- a/src/features/workspaces/components/CreateWorkspaceForm.js +++ b/src/features/workspaces/components/CreateWorkspaceForm.js @@ -82,6 +82,7 @@ class CreateWorkspaceForm extends Component { {...form.$('name').bind()} showLabel={false} onEnterKey={this.submitForm.bind(this, form)} + focus />
diff --git a/src/features/workspaces/components/WorkspaceSwitchingIndicator.js b/src/features/workspaces/components/WorkspaceSwitchingIndicator.js index ded6b8f2a..c4a800a7b 100644 --- a/src/features/workspaces/components/WorkspaceSwitchingIndicator.js +++ b/src/features/workspaces/components/WorkspaceSwitchingIndicator.js @@ -3,9 +3,9 @@ import PropTypes from 'prop-types'; import { observer } from 'mobx-react'; import injectSheet from 'react-jss'; import classnames from 'classnames'; +import { Loader } from '@meetfranz/ui'; import { defineMessages, intlShape } from 'react-intl'; -import LoaderComponent from '../../../components/ui/Loader'; import { workspaceStore } from '../index'; const messages = defineMessages({ @@ -39,12 +39,14 @@ const styles = theme => ({ zIndex: 200, }, spinner: { - width: '40px', - marginRight: '5px', + width: 40, + height: 40, + marginRight: 10, }, message: { fontSize: 16, whiteSpace: 'nowrap', + color: theme.colorAppLoaderSpinner, }, }); @@ -52,6 +54,7 @@ const styles = theme => ({ class WorkspaceSwitchingIndicator extends Component { static propTypes = { classes: PropTypes.object.isRequired, + theme: PropTypes.object.isRequired, }; static contextTypes = { @@ -59,7 +62,7 @@ class WorkspaceSwitchingIndicator extends Component { }; render() { - const { classes } = this.props; + const { classes, theme } = this.props; const { intl } = this.context; const { isSwitchingWorkspace, isWorkspaceDrawerOpen, nextWorkspace } = workspaceStore; if (!isSwitchingWorkspace) return null; @@ -72,9 +75,10 @@ class WorkspaceSwitchingIndicator extends Component { ])} >
-
- -
+

{`${intl.formatMessage(messages.switchingTo)} ${nextWorkspaceName}`}

-- cgit v1.2.3-54-g00ecf From 073212bf046b9218f9e3129988b1b63fba5d685d Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 10 Apr 2019 16:12:38 +0200 Subject: added generic pro badge component for settings nav --- packages/ui/src/badge/ProBadge.tsx | 65 ++++++++++++++++++++++ packages/ui/src/index.ts | 1 + .../settings/navigation/SettingsNavigation.js | 13 +++-- src/features/workspaces/store.js | 12 ++-- src/i18n/locales/defaultMessages.json | 28 +++++----- src/i18n/locales/en-US.json | 2 +- .../settings/navigation/SettingsNavigation.json | 28 +++++----- src/stores/UIStore.js | 9 +-- src/styles/settings.scss | 26 --------- uidev/src/stories/badge.stories.tsx | 12 +++- 10 files changed, 125 insertions(+), 71 deletions(-) create mode 100644 packages/ui/src/badge/ProBadge.tsx (limited to 'src') diff --git a/packages/ui/src/badge/ProBadge.tsx b/packages/ui/src/badge/ProBadge.tsx new file mode 100644 index 000000000..eb00e156d --- /dev/null +++ b/packages/ui/src/badge/ProBadge.tsx @@ -0,0 +1,65 @@ +import { Theme } from '@meetfranz/theme'; +import classnames from 'classnames'; +import React, { Component } from 'react'; +import injectStyle from 'react-jss'; + +import { Icon, Badge } from '../'; +import { IWithStyle } from '../typings/generic'; + +interface IProps extends IWithStyle { + badgeClasses?: string; + iconClasses?: string; + inverted?: boolean; +} + +const styles = (theme: Theme) => ({ + badge: { + height: 'auto', + padding: [4, 6, 2, 7], + borderRadius: theme.borderRadiusSmall, + }, + invertedBadge: { + background: theme.styleTypes.primary.contrast, + color: theme.styleTypes.primary.accent, + }, + icon: { + fill: theme.styleTypes.primary.contrast, + }, + invertedIcon: { + fill: theme.styleTypes.primary.accent, + }, +}); + +class ProBadgeComponent extends Component { + render() { + const { + classes, + badgeClasses, + iconClasses, + inverted, + } = this.props; + + return ( + + + + ); + } +} + +export const ProBadge = injectStyle(styles)(ProBadgeComponent); diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 1eeec5144..666495ce9 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -3,3 +3,4 @@ export { Infobox } from './infobox'; export * from './headline'; export { Loader } from './loader'; export { Badge } from './badge'; +export { ProBadge } from './badge/ProBadge'; diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 1c51d50d6..993b0a44a 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js @@ -2,10 +2,11 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { defineMessages, intlShape } from 'react-intl'; import { inject, observer } from 'mobx-react'; -import { Icon } from '@meetfranz/ui'; +import { ProBadge } from '@meetfranz/ui'; import Link from '../../ui/Link'; import { workspaceStore } from '../../../features/workspaces'; +import UIStore from '../../../stores/UIStore'; const messages = defineMessages({ availableServices: { @@ -40,6 +41,9 @@ const messages = defineMessages({ export default @inject('stores') @observer class SettingsNavigation extends Component { static propTypes = { + stores: PropTypes.shape({ + ui: PropTypes.instanceOf(UIStore).isRequired, + }).isRequired, serviceCount: PropTypes.number.isRequired, workspaceCount: PropTypes.number.isRequired, }; @@ -49,7 +53,8 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp }; render() { - const { serviceCount, workspaceCount } = this.props; + const { serviceCount, workspaceCount, stores } = this.props; + const { isDarkThemeActive } = stores.ui; const { intl } = this.context; return ( @@ -79,9 +84,7 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp {intl.formatMessage(messages.yourWorkspaces)} {' '} {workspaceStore.isPremiumUpgradeRequired ? ( - - - + ) : ( {workspaceCount} )} diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 2e1764f99..ba48022c2 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -36,6 +36,8 @@ export default class WorkspacesStore extends FeatureStore { @observable isWorkspaceDrawerOpen = false; + @observable isSettingsRouteActive = null; + @computed get workspaces() { if (!this.isFeatureActive) return []; return getUserWorkspacesRequest.result || []; @@ -104,8 +106,6 @@ export default class WorkspacesStore extends FeatureStore { _wasDrawerOpenBeforeSettingsRoute = null; - _isSettingsRouteActive = null; - _getWorkspaceById = id => this.workspaces.find(w => w.id === id); _updateSettings = (changes) => { @@ -239,17 +239,17 @@ export default class WorkspacesStore extends FeatureStore { _openDrawerWithSettingsReaction = () => { const { router } = this.stores; const isWorkspaceSettingsRoute = router.location.pathname.includes(WORKSPACES_ROUTES.ROOT); - const isSwitchingToSettingsRoute = !this._isSettingsRouteActive && isWorkspaceSettingsRoute; - const isLeavingSettingsRoute = !isWorkspaceSettingsRoute && this._isSettingsRouteActive; + const isSwitchingToSettingsRoute = !this.isSettingsRouteActive && isWorkspaceSettingsRoute; + const isLeavingSettingsRoute = !isWorkspaceSettingsRoute && this.isSettingsRouteActive; if (isSwitchingToSettingsRoute) { - this._isSettingsRouteActive = true; + this.isSettingsRouteActive = true; this._wasDrawerOpenBeforeSettingsRoute = this.isWorkspaceDrawerOpen; if (!this._wasDrawerOpenBeforeSettingsRoute) { workspaceActions.toggleWorkspaceDrawer(); } } else if (isLeavingSettingsRoute) { - this._isSettingsRouteActive = false; + this.isSettingsRouteActive = false; if (!this._wasDrawerOpenBeforeSettingsRoute && this.isWorkspaceDrawerOpen) { workspaceActions.toggleWorkspaceDrawer(); } diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index f882e6030..791c4dd53 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -1302,91 +1302,91 @@ "defaultMessage": "!!!Available services", "end": { "column": 3, - "line": 14 + "line": 15 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.availableServices", "start": { "column": 21, - "line": 11 + "line": 12 } }, { "defaultMessage": "!!!Your services", "end": { "column": 3, - "line": 18 + "line": 19 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.yourServices", "start": { "column": 16, - "line": 15 + "line": 16 } }, { "defaultMessage": "!!!Your workspaces", "end": { "column": 3, - "line": 22 + "line": 23 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.yourWorkspaces", "start": { "column": 18, - "line": 19 + "line": 20 } }, { "defaultMessage": "!!!Account", "end": { "column": 3, - "line": 26 + "line": 27 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.account", "start": { "column": 11, - "line": 23 + "line": 24 } }, { "defaultMessage": "!!!Settings", "end": { "column": 3, - "line": 30 + "line": 31 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.settings", "start": { "column": 12, - "line": 27 + "line": 28 } }, { "defaultMessage": "!!!Invite Friends", "end": { "column": 3, - "line": 34 + "line": 35 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.inviteFriends", "start": { "column": 17, - "line": 31 + "line": 32 } }, { "defaultMessage": "!!!Logout", "end": { "column": 3, - "line": 38 + "line": 39 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.logout", "start": { "column": 10, - "line": 35 + "line": 36 } } ], diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index db1d51f3b..6591af2e2 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -315,4 +315,4 @@ "workspaceDrawer.workspaceFeatureInfo": "

Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", "workspaces.switchingIndicator.switchingTo": "Switching to" -} +} \ No newline at end of file diff --git a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json index de78a71cf..77b0ed8a4 100644 --- a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json +++ b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Available services", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 11, + "line": 12, "column": 21 }, "end": { - "line": 14, + "line": 15, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!Your services", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 15, + "line": 16, "column": 16 }, "end": { - "line": 18, + "line": 19, "column": 3 } }, @@ -30,11 +30,11 @@ "defaultMessage": "!!!Your workspaces", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 19, + "line": 20, "column": 18 }, "end": { - "line": 22, + "line": 23, "column": 3 } }, @@ -43,11 +43,11 @@ "defaultMessage": "!!!Account", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 23, + "line": 24, "column": 11 }, "end": { - "line": 26, + "line": 27, "column": 3 } }, @@ -56,11 +56,11 @@ "defaultMessage": "!!!Settings", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 27, + "line": 28, "column": 12 }, "end": { - "line": 30, + "line": 31, "column": 3 } }, @@ -69,11 +69,11 @@ "defaultMessage": "!!!Invite Friends", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 31, + "line": 32, "column": 17 }, "end": { - "line": 34, + "line": 35, "column": 3 } }, @@ -82,11 +82,11 @@ "defaultMessage": "!!!Logout", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 35, + "line": 36, "column": 10 }, "end": { - "line": 38, + "line": 39, "column": 3 } } diff --git a/src/stores/UIStore.js b/src/stores/UIStore.js index bb7965a4a..a95a8e1e0 100644 --- a/src/stores/UIStore.js +++ b/src/stores/UIStore.js @@ -21,11 +21,12 @@ export default class UIStore extends Store { return (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || !settings.isAppMuted; } - @computed get theme() { - if (this.stores.settings.all.app.darkMode) { - return theme('dark'); - } + @computed get isDarkThemeActive() { + return this.stores.settings.all.app.darkMode; + } + @computed get theme() { + if (this.isDarkThemeActive) return theme('dark'); return theme('default'); } diff --git a/src/styles/settings.scss b/src/styles/settings.scss index 6340f2951..dd6f56d2b 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss @@ -85,11 +85,6 @@ .badge { background: $dark-theme-gray-lighter; color: $dark-theme-gray-smoke; - - &.badge--pro { - background: $theme-brand-primary; - padding: 4px 6px 3px 7px; - } } &:hover { @@ -98,11 +93,6 @@ .badge { background: $dark-theme-gray-lighter; color: $dark-theme-gray-smoke; - - &.badge--pro { - background: $theme-brand-primary; - padding: 4px 6px 3px 7px; - } } } @@ -433,15 +423,6 @@ text-decoration: none; transition: background $theme-transition-time, color $theme-transition-time; - .badge--pro { - background: $theme-brand-primary !important; - padding: 4px 6px 3px 7px; - - .badge-icon-pro { - fill: white; - } - } - &:hover { background: darken($theme-gray-lightest, 5%); @@ -454,13 +435,6 @@ background: $theme-brand-primary; color: #FFF; - .badge--pro { - background: white !important; - .badge-icon-pro { - fill: $theme-brand-primary; - } - } - .badge { background: #FFF; color: $theme-brand-primary; diff --git a/uidev/src/stories/badge.stories.tsx b/uidev/src/stories/badge.stories.tsx index 6de2034bf..d7b4d55b5 100644 --- a/uidev/src/stories/badge.stories.tsx +++ b/uidev/src/stories/badge.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Badge } from '@meetfranz/ui'; +import { Badge, ProBadge } from '@meetfranz/ui'; import { storiesOf } from '../stores/stories'; storiesOf('Badge') @@ -18,4 +18,14 @@ storiesOf('Badge') danger inverted + )) + .add('Pro Badge', () => ( + <> + + + )) + .add('Pro Badge inverted', () => ( + <> + + )); -- cgit v1.2.3-54-g00ecf From 4c762972ab51e6017607f0450c2647f4c0e5660f Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 10 Apr 2019 16:27:44 +0200 Subject: add premium badge to workspace drawer headline --- packages/ui/src/badge/ProBadge.tsx | 1 - .../workspaces/components/WorkspaceDrawer.js | 49 ++++++++++++++-------- src/i18n/locales/defaultMessages.json | 13 ++++++ src/i18n/locales/en-US.json | 1 + .../workspaces/components/WorkspaceDrawer.json | 13 ++++++ 5 files changed, 59 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/packages/ui/src/badge/ProBadge.tsx b/packages/ui/src/badge/ProBadge.tsx index eb00e156d..612e23210 100644 --- a/packages/ui/src/badge/ProBadge.tsx +++ b/packages/ui/src/badge/ProBadge.tsx @@ -47,7 +47,6 @@ class ProBadgeComponent extends Component { inverted && classes.invertedBadge, badgeClasses, ])} - data-type="franz-badge" > ({ @@ -54,6 +58,9 @@ const styles = theme => ({ marginBottom: '25px', marginLeft: theme.workspaces.drawer.padding, }, + headlineProBadge: { + marginRight: 15, + }, workspacesSettingsButton: { float: 'right', marginRight: theme.workspaces.drawer.padding, @@ -134,6 +141,14 @@ class WorkspaceDrawer extends Component { return (

+ {workspaceStore.isPremiumUpgradeRequired && ( + + + + )} {intl.formatMessage(messages.headline)} ))} +
{ + workspaceActions.openWorkspaceSettings(); + gaEvent(GA_CATEGORY_WORKSPACES, 'add', 'drawerAddLabel'); + }} + > + + + {intl.formatMessage(messages.addNewWorkspaceLabel)} + +

)} -
{ - workspaceActions.openWorkspaceSettings(); - gaEvent(GA_CATEGORY_WORKSPACES, 'add', 'drawerAddLabel'); - }} - > - - - {intl.formatMessage(messages.addNewWorkspaceLabel)} - -
); diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 791c4dd53..11a23805c 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -3412,6 +3412,19 @@ "column": 24, "line": 40 } + }, + { + "defaultMessage": "!!!Premium feature", + "end": { + "column": 3, + "line": 47 + }, + "file": "src/features/workspaces/components/WorkspaceDrawer.js", + "id": "workspaceDrawer.proFeatureBadge", + "start": { + "column": 23, + "line": 44 + } } ], "path": "src/features/workspaces/components/WorkspaceDrawer.json" diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 6591af2e2..a2f460f67 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -311,6 +311,7 @@ "workspaceDrawer.headline": "Workspaces", "workspaceDrawer.item.noServicesAddedYet": "No services added yet", "workspaceDrawer.premiumCtaButtonLabel": "Create your first workspace", + "workspaceDrawer.proFeatureBadge": "Premium feature", "workspaceDrawer.reactivatePremiumAccountLabel": "Reactivate premium account", "workspaceDrawer.workspaceFeatureInfo": "

Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json index d347622d2..9f0935620 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json @@ -89,5 +89,18 @@ "line": 43, "column": 3 } + }, + { + "id": "workspaceDrawer.proFeatureBadge", + "defaultMessage": "!!!Premium feature", + "file": "src/features/workspaces/components/WorkspaceDrawer.js", + "start": { + "line": 44, + "column": 23 + }, + "end": { + "line": 47, + "column": 3 + } } ] \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 664b59789ca032eaa393af52ff2559e173a9b0b5 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 10 Apr 2019 16:37:04 +0200 Subject: add context menu for workspace drawer items --- .../workspaces/components/WorkspaceDrawer.js | 1 + .../workspaces/components/WorkspaceDrawerItem.js | 29 ++++++++++++++++++++++ src/i18n/locales/defaultMessages.json | 17 +++++++++++-- src/i18n/locales/en-US.json | 3 ++- .../workspaces/components/WorkspaceDrawerItem.json | 17 +++++++++++-- 5 files changed, 62 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/features/workspaces/components/WorkspaceDrawer.js b/src/features/workspaces/components/WorkspaceDrawer.js index 64c98dc63..684e50dd0 100644 --- a/src/features/workspaces/components/WorkspaceDrawer.js +++ b/src/features/workspaces/components/WorkspaceDrawer.js @@ -215,6 +215,7 @@ class WorkspaceDrawer extends Component { workspaceActions.toggleWorkspaceDrawer(); gaEvent(GA_CATEGORY_WORKSPACES, 'switch', 'drawer'); }} + onContextMenuEditClick={() => workspaceActions.edit({ workspace })} services={getServicesForWorkspace(workspace)} /> ))} diff --git a/src/features/workspaces/components/WorkspaceDrawerItem.js b/src/features/workspaces/components/WorkspaceDrawerItem.js index 57f0754d9..59a2144d3 100644 --- a/src/features/workspaces/components/WorkspaceDrawerItem.js +++ b/src/features/workspaces/components/WorkspaceDrawerItem.js @@ -1,3 +1,4 @@ +import { remote } from 'electron'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { observer } from 'mobx-react'; @@ -5,11 +6,17 @@ import injectSheet from 'react-jss'; import classnames from 'classnames'; import { defineMessages, intlShape } from 'react-intl'; +const { Menu } = remote; + const messages = defineMessages({ noServicesAddedYet: { id: 'workspaceDrawer.item.noServicesAddedYet', defaultMessage: '!!!No services added yet', }, + contextMenuEdit: { + id: 'workspaceDrawer.item.contextMenuEdit', + defaultMessage: '!!!edit', + }, }); const styles = theme => ({ @@ -61,6 +68,11 @@ class WorkspaceDrawerItem extends Component { name: PropTypes.string.isRequired, onClick: PropTypes.func.isRequired, services: PropTypes.arrayOf(PropTypes.string).isRequired, + onContextMenuEditClick: PropTypes.func, + }; + + static defaultProps = { + onContextMenuEditClick: null, }; static contextTypes = { @@ -73,9 +85,23 @@ class WorkspaceDrawerItem extends Component { isActive, name, onClick, + onContextMenuEditClick, services, } = this.props; const { intl } = this.context; + + const contextMenuTemplate = [{ + label: name, + enabled: false, + }, { + type: 'separator', + }, { + label: intl.formatMessage(messages.contextMenuEdit), + click: onContextMenuEditClick, + }]; + + const contextMenu = Menu.buildFromTemplate(contextMenuTemplate); + return (
( + onContextMenuEditClick && contextMenu.popup(remote.getCurrentWindow()) + )} > Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", "workspaces.switchingIndicator.switchingTo": "Switching to" -} \ No newline at end of file +} diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json index cdbd1d5b5..4ff190606 100644 --- a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json +++ b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json @@ -4,11 +4,24 @@ "defaultMessage": "!!!No services added yet", "file": "src/features/workspaces/components/WorkspaceDrawerItem.js", "start": { - "line": 9, + "line": 12, "column": 22 }, "end": { - "line": 12, + "line": 15, + "column": 3 + } + }, + { + "id": "workspaceDrawer.item.contextMenuEdit", + "defaultMessage": "!!!edit", + "file": "src/features/workspaces/components/WorkspaceDrawerItem.js", + "start": { + "line": 16, + "column": 19 + }, + "end": { + "line": 19, "column": 3 } } -- cgit v1.2.3-54-g00ecf From adf5ac074626dac5bfec9d8fb54b28149e492e1b Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Wed, 10 Apr 2019 17:17:02 +0200 Subject: handle deleted services that are attached to workspaces --- src/containers/layout/AppLayoutContainer.js | 2 +- src/features/workspaces/store.js | 32 ++++++++++++++++++++++------- src/i18n/locales/en-US.json | 2 +- 3 files changed, 27 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index 52d4e0c27..2d855c78f 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js @@ -88,7 +88,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e const workspacesDrawer = ( ( - workspace ? workspace.services.map(id => services.one(id).name) : services.all.map(s => s.name) + workspace ? workspaceStore.getWorkspaceServices(workspace).map(s => s.name) : services.all.map(s => s.name) )} onUpgradeAccountClick={() => openSettings({ path: 'user' })} /> diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index ba48022c2..ea601700e 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js @@ -74,6 +74,7 @@ export default class WorkspacesStore extends FeatureStore { this._setIsPremiumFeatureReaction, this._activateLastUsedWorkspaceReaction, this._openDrawerWithSettingsReaction, + this._cleanupInvalidServiceReferences, ]); getUserWorkspacesRequest.execute(); @@ -92,16 +93,17 @@ export default class WorkspacesStore extends FeatureStore { filterServicesByActiveWorkspace = (services) => { const { activeWorkspace, isFeatureActive } = this; - - if (!isFeatureActive) return services; - if (activeWorkspace) { - return services.filter(s => ( - activeWorkspace.services.includes(s.id) - )); + if (isFeatureActive && activeWorkspace) { + return this.getWorkspaceServices(activeWorkspace); } return services; }; + getWorkspaceServices(workspace) { + const { services } = this.stores; + return workspace.services.map(id => services.one(id)).filter(s => !!s); + } + // ========== PRIVATE ========= // _wasDrawerOpenBeforeSettingsRoute = null; @@ -218,7 +220,8 @@ export default class WorkspacesStore extends FeatureStore { if (this.activeWorkspace) { const services = this.stores.services.allDisplayed; const activeService = services.find(s => s.isActive); - const workspaceServices = this.filterServicesByActiveWorkspace(services); + const workspaceServices = this.getWorkspaceServices(this.activeWorkspace); + if (workspaceServices.length <= 0) return; const isActiveServiceInWorkspace = workspaceServices.includes(activeService); if (!isActiveServiceInWorkspace) { this.actions.service.setActive({ serviceId: workspaceServices[0].id }); @@ -255,4 +258,19 @@ export default class WorkspacesStore extends FeatureStore { } } }; + + _cleanupInvalidServiceReferences = () => { + const { services } = this.stores; + let invalidServiceReferencesExist = false; + this.workspaces.forEach((workspace) => { + workspace.services.forEach((serviceId) => { + if (!services.one(serviceId)) { + invalidServiceReferencesExist = true; + } + }); + }); + if (invalidServiceReferencesExist) { + getUserWorkspacesRequest.execute(); + } + }; } diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index da7649b90..84a71117a 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -317,4 +317,4 @@ "workspaceDrawer.workspaceFeatureInfo": "

Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", "workspaces.switchingIndicator.switchingTo": "Switching to" -} +} \ No newline at end of file -- cgit v1.2.3-54-g00ecf