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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 From 6fb07bcb716af76ec2e96345f37624d12d0d1af0 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Tue, 12 Mar 2019 21:36:10 +0100 Subject: implements basic release announcement feature --- .eslintrc | 2 +- package-lock.json | 5 ++ package.json | 1 + src/actions/index.js | 6 +- src/actions/service.js | 1 + src/components/layout/AppLayout.js | 4 + src/config.js | 1 + src/containers/layout/AppLayoutContainer.js | 2 + src/features/announcements/Component.js | 77 ++++++++++++++++++ src/features/announcements/actions.js | 8 ++ src/features/announcements/api.js | 19 +++++ src/features/announcements/index.js | 37 +++++++++ src/features/announcements/state.js | 17 ++++ src/features/announcements/store.js | 95 ++++++++++++++++++++++ src/i18n/locales/defaultMessages.json | 95 ++++++++++++++-------- src/i18n/locales/en-US.json | 2 + .../messages/src/components/layout/AppLayout.json | 24 +++--- .../src/features/announcements/Component.json | 15 ++++ src/i18n/messages/src/lib/Menu.json | 53 +++++++----- src/lib/Menu.js | 10 +++ src/stores/FeaturesStore.js | 2 + src/stores/ServicesStore.js | 6 ++ 22 files changed, 416 insertions(+), 66 deletions(-) create mode 100644 src/features/announcements/Component.js create mode 100644 src/features/announcements/actions.js create mode 100644 src/features/announcements/api.js create mode 100644 src/features/announcements/index.js create mode 100644 src/features/announcements/state.js create mode 100644 src/features/announcements/store.js create mode 100644 src/i18n/messages/src/features/announcements/Component.json (limited to 'src') diff --git a/.eslintrc b/.eslintrc index 743946d35..a4ffd505c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,7 +14,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/package-lock.json b/package-lock.json index 8499abda9..bc333ae50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12094,6 +12094,11 @@ "object-visit": "^1.0.0" } }, + "marked": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.6.1.tgz", + "integrity": "sha512-+H0L3ibcWhAZE02SKMqmvYsErLo4EAVJxu5h3bHBBDvvjeWXtl92rGUSBYHL2++5Y+RSNgl8dYOAXcYe7lp1fA==" + }, "matchdep": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", diff --git a/package.json b/package.json index 14e0df7ca..4ddc83777 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "hex-to-rgba": "1.0.2", "jsonwebtoken": "^7.4.1", "lodash": "^4.17.4", + "marked": "0.6.1", "mdi": "^1.9.33", "mime-types": "2.1.21", "mobx": "5.7.0", diff --git a/src/actions/index.js b/src/actions/index.js index 59acabb0b..dc1d3b6b2 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 announcements from '../features/announcements/actions'; const actions = Object.assign({}, { service, @@ -25,4 +26,7 @@ const actions = Object.assign({}, { requests, }); -export default defineActions(actions, PropTypes.checkPropTypes); +export default Object.assign( + defineActions(actions, PropTypes.checkPropTypes), + { announcements }, +); diff --git a/src/actions/service.js b/src/actions/service.js index ceaabc31e..ce62560a9 100644 --- a/src/actions/service.js +++ b/src/actions/service.js @@ -5,6 +5,7 @@ export default { setActive: { serviceId: PropTypes.string.isRequired, }, + blurActive: {}, setActiveNext: {}, setActivePrev: {}, showAddServiceInterface: { diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index 593149e72..2bda91f73 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js @@ -13,6 +13,7 @@ import ErrorBoundary from '../util/ErrorBoundary'; // import globalMessages from '../../i18n/globalMessages'; import { isWindows } from '../../environment'; +import AnnouncementScreen from '../../features/announcements/Component'; function createMarkup(HTMLString) { return { __html: HTMLString }; @@ -64,6 +65,7 @@ export default @observer class AppLayout extends Component { areRequiredRequestsLoading: PropTypes.bool.isRequired, darkMode: PropTypes.bool.isRequired, isDelayAppScreenVisible: PropTypes.bool.isRequired, + isAnnouncementVisible: PropTypes.bool.isRequired, }; static defaultProps = { @@ -93,6 +95,7 @@ export default @observer class AppLayout extends Component { areRequiredRequestsLoading, darkMode, isDelayAppScreenVisible, + isAnnouncementVisible, } = this.props; const { intl } = this.context; @@ -166,6 +169,7 @@ export default @observer class AppLayout extends Component { {isDelayAppScreenVisible && ()} + {isAnnouncementVisible && ()} {services}
diff --git a/src/config.js b/src/config.js index 479572edb..47d22ca7d 100644 --- a/src/config.js +++ b/src/config.js @@ -41,6 +41,7 @@ export const DEFAULT_FEATURES_CONFIG = { }, isServiceProxyEnabled: false, isServiceProxyPremiumFeature: true, + isAnnouncementsEnabled: true, }; export const DEFAULT_WINDOW_OPTIONS = { diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index 5a05ce431..f26e51517 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js @@ -20,6 +20,7 @@ import Services from '../../components/services/content/Services'; import AppLoader from '../../components/ui/AppLoader'; import { state as delayAppState } from '../../features/delayApp'; +import { announcementsState } from '../../features/announcements/state'; export default @inject('stores', 'actions') @observer class AppLayoutContainer extends Component { static defaultProps = { @@ -134,6 +135,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e areRequiredRequestsLoading={requests.areRequiredRequestsLoading} darkMode={settings.all.app.darkMode} isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} + isAnnouncementVisible={announcementsState.isAnnouncementVisible} > {React.Children.count(children) > 0 ? children : null} diff --git a/src/features/announcements/Component.js b/src/features/announcements/Component.js new file mode 100644 index 000000000..5d95f5d84 --- /dev/null +++ b/src/features/announcements/Component.js @@ -0,0 +1,77 @@ +import React, { Component } from 'react'; +import marked from 'marked'; +import PropTypes from 'prop-types'; +import { inject, observer } from 'mobx-react'; +import { defineMessages, intlShape } from 'react-intl'; +import injectSheet from 'react-jss'; +import { themeSidebarWidth } from '@meetfranz/theme/lib/themes/legacy'; +import state from './state'; + +const messages = defineMessages({ + headline: { + id: 'feature.announcements.headline', + defaultMessage: '!!!What\'s new in Franz {version}?', + }, +}); + +const styles = theme => ({ + container: { + background: theme.colorBackground, + position: 'absolute', + top: 0, + zIndex: 140, + width: `calc(100% - ${themeSidebarWidth})`, + display: 'flex', + 'flex-direction': 'column', + 'align-items': 'center', + 'justify-content': 'center', + }, + headline: { + color: theme.colorHeadline, + margin: [25, 0, 40], + 'max-width': 500, + 'text-align': 'center', + 'line-height': '1.3em', + }, + body: { + '& h3': { + fontSize: '24px', + margin: '1.5em 0 1em 0', + }, + '& li': { + marginBottom: '1em', + }, + }, +}); + + +@inject('actions') @injectSheet(styles) @observer +class AnnouncementScreen extends Component { + static propTypes = { + classes: PropTypes.object.isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + render() { + const { classes } = this.props; + const { intl } = this.context; + return ( +
+

+ {intl.formatMessage(messages.headline, { version: state.currentVersion })} +

+
+
+ ); + } +} + +export default AnnouncementScreen; diff --git a/src/features/announcements/actions.js b/src/features/announcements/actions.js new file mode 100644 index 000000000..68b262ded --- /dev/null +++ b/src/features/announcements/actions.js @@ -0,0 +1,8 @@ +import PropTypes from 'prop-types'; +import { createActionsFromDefinitions } from '../../actions/lib/actions'; + +export const announcementActions = createActionsFromDefinitions({ + show: {}, +}, PropTypes.checkPropTypes); + +export default announcementActions; diff --git a/src/features/announcements/api.js b/src/features/announcements/api.js new file mode 100644 index 000000000..ec16066a6 --- /dev/null +++ b/src/features/announcements/api.js @@ -0,0 +1,19 @@ +import { remote } from 'electron'; + +const debug = require('debug')('Franz:feature:announcements:api'); + +export default { + async getCurrentVersion() { + debug('getting current version of electron app'); + return Promise.resolve(remote.app.getVersion()); + }, + + async getAnnouncementForVersion(version) { + debug('fetching release announcement from Github'); + const url = `https://api.github.com/repos/meetfranz/franz/releases/tags/v${version}`; + const request = await window.fetch(url, { method: 'GET' }); + if (!request.ok) throw request; + const data = await request.json(); + return data.body; + }, +}; diff --git a/src/features/announcements/index.js b/src/features/announcements/index.js new file mode 100644 index 000000000..5ea74e0af --- /dev/null +++ b/src/features/announcements/index.js @@ -0,0 +1,37 @@ +import { reaction, runInAction } from 'mobx'; +import { AnnouncementsStore } from './store'; +import api from './api'; +import state, { resetState } from './state'; + +const debug = require('debug')('Franz:feature:announcements'); + +let store = null; + +export default function initAnnouncements(stores, actions) { + // const { features } = stores; + + // Toggle workspace feature + reaction( + () => ( + true + // features.features.isAnnouncementsEnabled + ), + (isEnabled) => { + if (isEnabled) { + debug('Initializing `announcements` feature'); + store = new AnnouncementsStore(stores, api, actions, state); + store.initialize(); + runInAction(() => { state.isFeatureActive = true; }); + } else if (store) { + debug('Disabling `announcements` feature'); + runInAction(() => { state.isFeatureActive = false; }); + store.teardown(); + store = null; + resetState(); // Reset state to default + } + }, + { + fireImmediately: true, + }, + ); +} diff --git a/src/features/announcements/state.js b/src/features/announcements/state.js new file mode 100644 index 000000000..81b632253 --- /dev/null +++ b/src/features/announcements/state.js @@ -0,0 +1,17 @@ +import { observable } from 'mobx'; + +const defaultState = { + announcement: null, + currentVersion: null, + lastUsedVersion: null, + isAnnouncementVisible: false, + isFeatureActive: false, +}; + +export const announcementsState = observable(defaultState); + +export function resetState() { + Object.assign(announcementsState, defaultState); +} + +export default announcementsState; diff --git a/src/features/announcements/store.js b/src/features/announcements/store.js new file mode 100644 index 000000000..004a44062 --- /dev/null +++ b/src/features/announcements/store.js @@ -0,0 +1,95 @@ +import { action, observable, reaction } from 'mobx'; +import semver from 'semver'; + +import Request from '../../stores/lib/Request'; +import Store from '../../stores/lib/Store'; + +const debug = require('debug')('Franz:feature:announcements:store'); + +export class AnnouncementsStore extends Store { + @observable getCurrentVersion = new Request(this.api, 'getCurrentVersion'); + + @observable getAnnouncement = new Request(this.api, 'getAnnouncementForVersion'); + + constructor(stores, api, actions, state) { + super(stores, api, actions); + this.state = state; + } + + async setup() { + await this.fetchLastUsedVersion(); + await this.fetchCurrentVersion(); + await this.fetchReleaseAnnouncement(); + this.showAnnouncementIfNotSeenYet(); + + this.actions.announcements.show.listen(this._showAnnouncement.bind(this)); + } + + // ====== PUBLIC ====== + + async fetchLastUsedVersion() { + debug('getting last used version from local storage'); + const lastUsedVersion = window.localStorage.getItem('lastUsedVersion'); + this._setLastUsedVersion(lastUsedVersion == null ? '0.0.0' : lastUsedVersion); + } + + async fetchCurrentVersion() { + debug('getting current version from api'); + const version = await this.getCurrentVersion.execute(); + this._setCurrentVersion(version); + } + + async fetchReleaseAnnouncement() { + debug('getting release announcement from api'); + try { + const announcement = await this.getAnnouncement.execute(this.state.currentVersion); + this._setAnnouncement(announcement); + } catch (error) { + this._setAnnouncement(null); + } + } + + showAnnouncementIfNotSeenYet() { + const { announcement, currentVersion, lastUsedVersion } = this.state; + if (announcement && semver.gt(currentVersion, lastUsedVersion)) { + debug(`${currentVersion} < ${lastUsedVersion}: announcement is shown`); + this._showAnnouncement(); + } else { + debug(`${currentVersion} >= ${lastUsedVersion}: announcement is hidden`); + this._hideAnnouncement(); + } + } + + // ====== PRIVATE ====== + + @action _setCurrentVersion(version) { + debug(`setting current version to ${version}`); + this.state.currentVersion = version; + } + + @action _setLastUsedVersion(version) { + debug(`setting last used version to ${version}`); + this.state.lastUsedVersion = version; + } + + @action _setAnnouncement(announcement) { + debug(`setting announcement to ${announcement}`); + this.state.announcement = announcement; + } + + @action _showAnnouncement() { + this.state.isAnnouncementVisible = true; + this.actions.service.blurActive(); + const dispose = reaction( + () => this.stores.services.active, + () => { + this._hideAnnouncement(); + dispose(); + }, + ); + } + + @action _hideAnnouncement() { + this.state.isAnnouncementVisible = false; + } +} diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 0641c510c..fcd24c7ef 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -625,78 +625,78 @@ "defaultMessage": "!!!Your services have been updated.", "end": { "column": 3, - "line": 25 + "line": 26 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.servicesUpdated", "start": { "column": 19, - "line": 22 + "line": 23 } }, { "defaultMessage": "!!!A new update for Franz is available.", "end": { "column": 3, - "line": 29 + "line": 30 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.updateAvailable", "start": { "column": 19, - "line": 26 + "line": 27 } }, { "defaultMessage": "!!!Reload services", "end": { "column": 3, - "line": 33 + "line": 34 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.buttonReloadServices", "start": { "column": 24, - "line": 30 + "line": 31 } }, { "defaultMessage": "!!!Changelog", "end": { "column": 3, - "line": 37 + "line": 38 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.buttonChangelog", "start": { "column": 13, - "line": 34 + "line": 35 } }, { "defaultMessage": "!!!Restart & install update", "end": { "column": 3, - "line": 41 + "line": 42 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.buttonInstallUpdate", "start": { "column": 23, - "line": 38 + "line": 39 } }, { "defaultMessage": "!!!Could not load services and user information", "end": { "column": 3, - "line": 45 + "line": 46 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.requiredRequestsFailed", "start": { "column": 26, - "line": 42 + "line": 43 } } ], @@ -3022,6 +3022,24 @@ ], "path": "src/containers/settings/EditUserScreen.json" }, + { + "descriptors": [ + { + "defaultMessage": "!!!What's new in Franz {version}?", + "end": { + "column": 3, + "line": 14 + }, + "file": "src/features/announcements/Component.js", + "id": "feature.announcements.headline", + "start": { + "column": 12, + "line": 11 + } + } + ], + "path": "src/features/announcements/Component.json" + }, { "descriptors": [ { @@ -3799,133 +3817,146 @@ } }, { - "defaultMessage": "!!!Settings", + "defaultMessage": "!!!What's new in Franz?", "end": { "column": 3, "line": 161 }, "file": "src/lib/Menu.js", + "id": "menu.app.announcement", + "start": { + "column": 16, + "line": 158 + } + }, + { + "defaultMessage": "!!!Settings", + "end": { + "column": 3, + "line": 165 + }, + "file": "src/lib/Menu.js", "id": "menu.app.settings", "start": { "column": 12, - "line": 158 + "line": 162 } }, { "defaultMessage": "!!!Hide", "end": { "column": 3, - "line": 165 + "line": 169 }, "file": "src/lib/Menu.js", "id": "menu.app.hide", "start": { "column": 8, - "line": 162 + "line": 166 } }, { "defaultMessage": "!!!Hide Others", "end": { "column": 3, - "line": 169 + "line": 173 }, "file": "src/lib/Menu.js", "id": "menu.app.hideOthers", "start": { "column": 14, - "line": 166 + "line": 170 } }, { "defaultMessage": "!!!Unhide", "end": { "column": 3, - "line": 173 + "line": 177 }, "file": "src/lib/Menu.js", "id": "menu.app.unhide", "start": { "column": 10, - "line": 170 + "line": 174 } }, { "defaultMessage": "!!!Quit", "end": { "column": 3, - "line": 177 + "line": 181 }, "file": "src/lib/Menu.js", "id": "menu.app.quit", "start": { "column": 8, - "line": 174 + "line": 178 } }, { "defaultMessage": "!!!Add New Service...", "end": { "column": 3, - "line": 181 + "line": 185 }, "file": "src/lib/Menu.js", "id": "menu.services.addNewService", "start": { "column": 17, - "line": 178 + "line": 182 } }, { "defaultMessage": "!!!Activate next service...", "end": { "column": 3, - "line": 185 + "line": 189 }, "file": "src/lib/Menu.js", "id": "menu.services.setNextServiceActive", "start": { "column": 23, - "line": 182 + "line": 186 } }, { "defaultMessage": "!!!Activate previous service...", "end": { "column": 3, - "line": 189 + "line": 193 }, "file": "src/lib/Menu.js", "id": "menu.services.activatePreviousService", "start": { "column": 27, - "line": 186 + "line": 190 } }, { "defaultMessage": "!!!Disable notifications & audio", "end": { "column": 3, - "line": 193 + "line": 197 }, "file": "src/lib/Menu.js", "id": "sidebar.muteApp", "start": { "column": 11, - "line": 190 + "line": 194 } }, { "defaultMessage": "!!!Enable notifications & audio", "end": { "column": 3, - "line": 197 + "line": 201 }, "file": "src/lib/Menu.js", "id": "sidebar.unmuteApp", "start": { "column": 13, - "line": 194 + "line": 198 } } ], diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 7543d38bd..573231c45 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -1,6 +1,7 @@ { "app.errorHandler.action": "Reload", "app.errorHandler.headline": "Something went wrong", + "feature.announcements.headline": "What's new in Franz {version}?", "feature.delayApp.action": "Get a Franz Supporter License", "feature.delayApp.headline": "Please purchase a Franz Supporter License to skip waiting", "feature.delayApp.text": "Franz will continue in {seconds} seconds.", @@ -43,6 +44,7 @@ "login.submit.label": "Sign in", "login.tokenExpired": "Your session expired, please login again.", "menu.app.about": "About Franz", + "menu.app.announcement": "What's new in Franz?", "menu.app.hide": "Hide", "menu.app.hideOthers": "Hide Others", "menu.app.quit": "Quit", diff --git a/src/i18n/messages/src/components/layout/AppLayout.json b/src/i18n/messages/src/components/layout/AppLayout.json index 07603d062..384d4b441 100644 --- a/src/i18n/messages/src/components/layout/AppLayout.json +++ b/src/i18n/messages/src/components/layout/AppLayout.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Your services have been updated.", "file": "src/components/layout/AppLayout.js", "start": { - "line": 22, + "line": 23, "column": 19 }, "end": { - "line": 25, + "line": 26, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!A new update for Franz is available.", "file": "src/components/layout/AppLayout.js", "start": { - "line": 26, + "line": 27, "column": 19 }, "end": { - "line": 29, + "line": 30, "column": 3 } }, @@ -30,11 +30,11 @@ "defaultMessage": "!!!Reload services", "file": "src/components/layout/AppLayout.js", "start": { - "line": 30, + "line": 31, "column": 24 }, "end": { - "line": 33, + "line": 34, "column": 3 } }, @@ -43,11 +43,11 @@ "defaultMessage": "!!!Changelog", "file": "src/components/layout/AppLayout.js", "start": { - "line": 34, + "line": 35, "column": 13 }, "end": { - "line": 37, + "line": 38, "column": 3 } }, @@ -56,11 +56,11 @@ "defaultMessage": "!!!Restart & install update", "file": "src/components/layout/AppLayout.js", "start": { - "line": 38, + "line": 39, "column": 23 }, "end": { - "line": 41, + "line": 42, "column": 3 } }, @@ -69,11 +69,11 @@ "defaultMessage": "!!!Could not load services and user information", "file": "src/components/layout/AppLayout.js", "start": { - "line": 42, + "line": 43, "column": 26 }, "end": { - "line": 45, + "line": 46, "column": 3 } } diff --git a/src/i18n/messages/src/features/announcements/Component.json b/src/i18n/messages/src/features/announcements/Component.json new file mode 100644 index 000000000..18e1b84c5 --- /dev/null +++ b/src/i18n/messages/src/features/announcements/Component.json @@ -0,0 +1,15 @@ +[ + { + "id": "feature.announcements.headline", + "defaultMessage": "!!!What's new in Franz {version}?", + "file": "src/features/announcements/Component.js", + "start": { + "line": 11, + "column": 12 + }, + "end": { + "line": 14, + "column": 3 + } + } +] \ No newline at end of file diff --git a/src/i18n/messages/src/lib/Menu.json b/src/i18n/messages/src/lib/Menu.json index 9314f5cce..0db994871 100644 --- a/src/i18n/messages/src/lib/Menu.json +++ b/src/i18n/messages/src/lib/Menu.json @@ -480,16 +480,29 @@ "column": 3 } }, + { + "id": "menu.app.announcement", + "defaultMessage": "!!!What's new in Franz?", + "file": "src/lib/Menu.js", + "start": { + "line": 158, + "column": 16 + }, + "end": { + "line": 161, + "column": 3 + } + }, { "id": "menu.app.settings", "defaultMessage": "!!!Settings", "file": "src/lib/Menu.js", "start": { - "line": 158, + "line": 162, "column": 12 }, "end": { - "line": 161, + "line": 165, "column": 3 } }, @@ -498,11 +511,11 @@ "defaultMessage": "!!!Hide", "file": "src/lib/Menu.js", "start": { - "line": 162, + "line": 166, "column": 8 }, "end": { - "line": 165, + "line": 169, "column": 3 } }, @@ -511,11 +524,11 @@ "defaultMessage": "!!!Hide Others", "file": "src/lib/Menu.js", "start": { - "line": 166, + "line": 170, "column": 14 }, "end": { - "line": 169, + "line": 173, "column": 3 } }, @@ -524,11 +537,11 @@ "defaultMessage": "!!!Unhide", "file": "src/lib/Menu.js", "start": { - "line": 170, + "line": 174, "column": 10 }, "end": { - "line": 173, + "line": 177, "column": 3 } }, @@ -537,11 +550,11 @@ "defaultMessage": "!!!Quit", "file": "src/lib/Menu.js", "start": { - "line": 174, + "line": 178, "column": 8 }, "end": { - "line": 177, + "line": 181, "column": 3 } }, @@ -550,11 +563,11 @@ "defaultMessage": "!!!Add New Service...", "file": "src/lib/Menu.js", "start": { - "line": 178, + "line": 182, "column": 17 }, "end": { - "line": 181, + "line": 185, "column": 3 } }, @@ -563,11 +576,11 @@ "defaultMessage": "!!!Activate next service...", "file": "src/lib/Menu.js", "start": { - "line": 182, + "line": 186, "column": 23 }, "end": { - "line": 185, + "line": 189, "column": 3 } }, @@ -576,11 +589,11 @@ "defaultMessage": "!!!Activate previous service...", "file": "src/lib/Menu.js", "start": { - "line": 186, + "line": 190, "column": 27 }, "end": { - "line": 189, + "line": 193, "column": 3 } }, @@ -589,11 +602,11 @@ "defaultMessage": "!!!Disable notifications & audio", "file": "src/lib/Menu.js", "start": { - "line": 190, + "line": 194, "column": 11 }, "end": { - "line": 193, + "line": 197, "column": 3 } }, @@ -602,11 +615,11 @@ "defaultMessage": "!!!Enable notifications & audio", "file": "src/lib/Menu.js", "start": { - "line": 194, + "line": 198, "column": 13 }, "end": { - "line": 197, + "line": 201, "column": 3 } } diff --git a/src/lib/Menu.js b/src/lib/Menu.js index 7a60c448f..70f3b2877 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js @@ -155,6 +155,10 @@ const menuItems = defineMessages({ id: 'menu.app.about', defaultMessage: '!!!About Franz', }, + announcement: { + id: 'menu.app.announcement', + defaultMessage: '!!!What\'s new in Franz?', + }, settings: { id: 'menu.app.settings', defaultMessage: '!!!Settings', @@ -589,6 +593,12 @@ export default class FranzMenu { label: intl.formatMessage(menuItems.about), role: 'about', }, + { + label: intl.formatMessage(menuItems.announcement), + click: () => { + this.actions.announcements.show(); + }, + }, { type: 'separator', }, diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index d2842083c..1c9044b07 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js @@ -8,6 +8,7 @@ import spellchecker from '../features/spellchecker'; import serviceProxy from '../features/serviceProxy'; import basicAuth from '../features/basicAuth'; import shareFranz from '../features/shareFranz'; +import announcements from '../features/announcements'; import { DEFAULT_FEATURES_CONFIG } from '../config'; @@ -58,5 +59,6 @@ export default class FeaturesStore extends Store { serviceProxy(this.stores, this.actions); basicAuth(this.stores, this.actions); shareFranz(this.stores, this.actions); + announcements(this.stores, this.actions); } } diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 69e616f0c..88b0331bf 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -35,6 +35,7 @@ export default class ServicesStore extends Store { // Register action handlers this.actions.service.setActive.listen(this._setActive.bind(this)); + this.actions.service.blurActive.listen(this._blurActive.bind(this)); this.actions.service.setActiveNext.listen(this._setActiveNext.bind(this)); this.actions.service.setActivePrev.listen(this._setActivePrev.bind(this)); this.actions.service.showAddServiceInterface.listen(this._showAddServiceInterface.bind(this)); @@ -298,6 +299,11 @@ export default class ServicesStore extends Store { this._focusActiveService(); } + @action _blurActive() { + if (!this.active) return; + this.active.isActive = false; + } + @action _setActiveNext() { const nextIndex = this._wrapIndex(this.allDisplayed.findIndex(service => service.isActive), 1, this.allDisplayed.length); -- cgit v1.2.3-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 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-70-g09d2 From ea71fced95a6923926c92ada523840ebdbd0ef64 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 8 Apr 2019 15:18:58 +0200 Subject: Replace invoices & subscription info with links to website --- src/api/PaymentApi.js | 8 -- src/api/server/ServerApi.js | 17 ---- .../settings/account/AccountDashboard.js | 107 +++++++-------------- src/config.js | 5 + src/containers/settings/AccountScreen.js | 69 +++++++------ src/environment.js | 14 ++- src/stores/PaymentStore.js | 17 ---- src/styles/badge.scss | 1 + src/styles/settings.scss | 13 ++- 9 files changed, 103 insertions(+), 148 deletions(-) (limited to 'src') diff --git a/src/api/PaymentApi.js b/src/api/PaymentApi.js index 3f6bb442e..7325151e9 100644 --- a/src/api/PaymentApi.js +++ b/src/api/PaymentApi.js @@ -11,12 +11,4 @@ export default class PaymentApi { getHostedPage(planId) { return this.server.getHostedPage(planId); } - - getDashboardUrl() { - return this.server.getPaymentDashboardUrl(); - } - - getOrders() { - return this.server.getSubscriptionOrders(); - } } diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index bafeef005..f6bc9c283 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js @@ -418,23 +418,6 @@ export default class ServerApi { return data; } - async getPaymentDashboardUrl() { - const request = await sendAuthRequest(`${API_URL}/me/billing`); - if (!request.ok) throw request; - const data = await request.json(); - debug('ServerApi::getPaymentDashboardUrl resolves', data); - return data; - } - - async getSubscriptionOrders() { - const request = await sendAuthRequest(`${API_URL}/me/subscription`); - if (!request.ok) throw request; - const data = await request.json(); - const orders = this._mapOrderModels(data); - debug('ServerApi::getSubscriptionOrders resolves', orders); - return orders; - } - // News async getLatestNews() { const url = `${API_URL}/news?platform=${os.platform()}&arch=${os.arch()}&version=${app.getVersion()}`; diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js index 181b95c8c..ca8b9e1bd 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js @@ -3,12 +3,10 @@ import PropTypes from 'prop-types'; import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; import { defineMessages, intlShape } from 'react-intl'; import ReactTooltip from 'react-tooltip'; -import moment from 'moment'; import Loader from '../../ui/Loader'; import Button from '../../ui/Button'; import Infobox from '../../ui/Infobox'; -import Link from '../../ui/Link'; import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen'; const messages = defineMessages({ @@ -24,10 +22,6 @@ const messages = defineMessages({ id: 'settings.account.headlineUpgrade', defaultMessage: '!!!Upgrade your Account', }, - headlineInvoices: { - id: 'settings.account.headlineInvoices', - defaultMessage: '!!Invoices', - }, headlineDangerZone: { id: 'settings.account.headlineDangerZone', defaultMessage: '!!Danger Zone', @@ -48,6 +42,10 @@ const messages = defineMessages({ id: 'settings.account.account.editButton', defaultMessage: '!!!Edit Account', }, + invoicesButton: { + id: 'settings.account.headlineInvoices', + defaultMessage: '!!Invoices', + }, invoiceDownload: { id: 'settings.account.invoiceDownload', defaultMessage: '!!!Download', @@ -77,19 +75,17 @@ const messages = defineMessages({ export default @observer class AccountDashboard extends Component { static propTypes = { user: MobxPropTypes.observableObject.isRequired, - orders: MobxPropTypes.arrayOrObservableArray.isRequired, isLoading: PropTypes.bool.isRequired, - isLoadingOrdersInfo: PropTypes.bool.isRequired, isLoadingPlans: PropTypes.bool.isRequired, - isCreatingPaymentDashboardUrl: PropTypes.bool.isRequired, userInfoRequestFailed: PropTypes.bool.isRequired, retryUserInfoRequest: PropTypes.func.isRequired, - openDashboard: PropTypes.func.isRequired, - openExternalUrl: PropTypes.func.isRequired, onCloseSubscriptionWindow: PropTypes.func.isRequired, deleteAccount: PropTypes.func.isRequired, isLoadingDeleteAccount: PropTypes.bool.isRequired, isDeleteAccountSuccessful: PropTypes.bool.isRequired, + openEditAccount: PropTypes.func.isRequired, + openBilling: PropTypes.func.isRequired, + openInvoices: PropTypes.func.isRequired, }; static contextTypes = { @@ -99,12 +95,7 @@ export default @observer class AccountDashboard extends Component { render() { const { user, - orders, isLoading, - isCreatingPaymentDashboardUrl, - openDashboard, - openExternalUrl, - isLoadingOrdersInfo, isLoadingPlans, userInfoRequestFailed, retryUserInfoRequest, @@ -112,6 +103,9 @@ export default @observer class AccountDashboard extends Component { deleteAccount, isLoadingDeleteAccount, isDeleteAccountSuccessful, + openEditAccount, + openBilling, + openInvoices, } = this.props; const { intl } = this.context; @@ -161,68 +155,39 @@ export default @observer class AccountDashboard extends Component {

{`${user.firstname} ${user.lastname}`} + {user.isPremium && ( + <> + {' '} + {intl.formatMessage(messages.accountTypePremium)} + + )}

{user.organization && `${user.organization}, `} {user.email} -
- {user.isPremium && ( - {intl.formatMessage(messages.accountTypePremium)} - )} -
- - {intl.formatMessage(messages.accountEditButton)} - - {user.emailValidated} -
-
- )} - - {user.isSubscriptionOwner && ( - isLoadingOrdersInfo ? ( - - ) : ( -
- {orders.length > 0 && ( - -
-

{intl.formatMessage(messages.headlineSubscription)}

-
- {orders[0].name} - {orders[0].price} +
+
-
-
-

{intl.formatMessage(messages.headlineInvoices)}

-
- - {orders.map(order => ( - - - - - ))} - -
- {moment(order.date).format('DD.MM.YYYY')} - - -
-
- - )} +
+
- ) + )} {!user.isPremium && ( diff --git a/src/config.js b/src/config.js index 479572edb..4423e61e9 100644 --- a/src/config.js +++ b/src/config.js @@ -12,6 +12,11 @@ export const CHECK_INTERVAL = ms('1h'); // How often should we perform checks export const LOCAL_API = 'http://localhost:3000'; export const DEV_API = 'https://dev.franzinfra.com'; export const LIVE_API = 'https://api.franzinfra.com'; + +export const LOCAL_API_WEBSITE = 'http://localhost:3333'; +export const DEV_API_WEBSITE = 'https://meetfranz.com'; +export const LIVE_API_WEBSITE = 'https://meetfranz.com'; + export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12'; export const DEFAULT_APP_SETTINGS = { diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js index ce1b9c333..0c837fab9 100644 --- a/src/containers/settings/AccountScreen.js +++ b/src/containers/settings/AccountScreen.js @@ -9,6 +9,7 @@ import AppStore from '../../stores/AppStore'; import AccountDashboard from '../../components/settings/account/AccountDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; +import { WEBSITE } from '../../environment'; const { BrowserWindow } = remote; @@ -24,69 +25,77 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend onCloseWindow() { const { user, payment } = this.props.stores; user.getUserInfoRequest.invalidate({ immediately: true }); - payment.ordersDataRequest.invalidate({ immediately: true }); } reloadData() { const { user, payment } = this.props.stores; user.getUserInfoRequest.reload(); - payment.ordersDataRequest.reload(); payment.plansRequest.reload(); } async handlePaymentDashboard() { const { actions, stores } = this.props; - actions.payment.createDashboardUrl(); - - const dashboard = await stores.payment.createDashboardUrlRequest; - - if (dashboard.url) { - const paymentWindow = new BrowserWindow({ - title: '🔒 Franz Subscription Dashboard', - parent: remote.getCurrentWindow(), - modal: false, - width: 900, - minWidth: 600, - webPreferences: { - nodeIntegration: false, - }, - }); - paymentWindow.loadURL(dashboard.url); - - paymentWindow.on('closed', () => { - this.onCloseWindow(); - }); - } + // actions.payment.createDashboardUrl(); + + // const dashboard = await stores.payment.createDashboardUrlRequest; + + // if (dashboard.url) { + // const paymentWindow = new BrowserWindow({ + // title: '🔒 Franz Subscription Dashboard', + // parent: remote.getCurrentWindow(), + // modal: false, + // width: 900, + // minWidth: 600, + // webPreferences: { + // nodeIntegration: false, + // }, + // }); + // paymentWindow.loadURL(dashboard.url); + + // paymentWindow.on('closed', () => { + // this.onCloseWindow(); + // }); + // } + + const url = `${WEBSITE}/user/billing?token=${stores.user.authToken}&utm_source=app&utm_medium=edit_profile`; + + actions.app.openExternalUrl({ url }); + } + + handleWebsiteLink(route) { + const { actions, stores } = this.props; + + const url = `${WEBSITE}${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; + console.log(url); + + actions.app.openExternalUrl({ url }); } render() { const { user, payment } = this.props.stores; - const { openExternalUrl } = this.props.actions.app; const { user: userActions } = this.props.actions; const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; - const isLoadingOrdersInfo = payment.ordersDataRequest.isExecuting; const isLoadingPlans = payment.plansRequest.isExecuting; return ( this.reloadData()} - isCreatingPaymentDashboardUrl={payment.createDashboardUrlRequest.isExecuting} - openDashboard={price => this.handlePaymentDashboard(price)} - openExternalUrl={url => openExternalUrl({ url })} onCloseSubscriptionWindow={() => this.onCloseWindow()} deleteAccount={userActions.delete} isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting} isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError} + openEditAccount={() => this.handleWebsiteLink('/user/profile')} + openBilling={() => this.handleWebsiteLink('/user/billing')} + openInvoices={() => this.handleWebsiteLink('/user/invoices')} /> ); diff --git a/src/environment.js b/src/environment.js index 73b1c7ab2..68fa45173 100644 --- a/src/environment.js +++ b/src/environment.js @@ -1,6 +1,13 @@ import isDev from 'electron-is-dev'; -import { LIVE_API, DEV_API, LOCAL_API } from './config'; +import { + LIVE_API, + DEV_API, + LOCAL_API, + LOCAL_API_WEBSITE, + DEV_API_WEBSITE, + LIVE_API_WEBSITE, +} from './config'; export const isDevMode = isDev; export const useLiveAPI = process.env.LIVE_API; @@ -19,12 +26,17 @@ export const ctrlKey = isMac ? '⌘' : 'Ctrl'; export const cmdKey = isMac ? 'Cmd' : 'Ctrl'; let api; +let web; if (!isDevMode || (isDevMode && useLiveAPI)) { api = LIVE_API; + web = LIVE_API_WEBSITE; } else if (isDevMode && useLocalAPI) { api = LOCAL_API; + web = LOCAL_API_WEBSITE; } else { api = DEV_API; + web = DEV_API_WEBSITE; } export const API = api; +export const WEBSITE = web; diff --git a/src/stores/PaymentStore.js b/src/stores/PaymentStore.js index 4cabee194..d4de476c8 100644 --- a/src/stores/PaymentStore.js +++ b/src/stores/PaymentStore.js @@ -10,15 +10,10 @@ export default class PaymentStore extends Store { @observable createHostedPageRequest = new Request(this.api.payment, 'getHostedPage'); - @observable createDashboardUrlRequest = new Request(this.api.payment, 'getDashboardUrl'); - - @observable ordersDataRequest = new CachedRequest(this.api.payment, 'getOrders'); - constructor(...args) { super(...args); this.actions.payment.createHostedPage.listen(this._createHostedPage.bind(this)); - this.actions.payment.createDashboardUrl.listen(this._createDashboardUrl.bind(this)); } @computed get plan() { @@ -28,10 +23,6 @@ export default class PaymentStore extends Store { return this.plansRequest.execute().result || {}; } - @computed get orders() { - return this.ordersDataRequest.execute().result || []; - } - @action _createHostedPage({ planId }) { const request = this.createHostedPageRequest.execute(planId); @@ -39,12 +30,4 @@ export default class PaymentStore extends Store { return request; } - - @action _createDashboardUrl() { - const request = this.createDashboardUrlRequest.execute(); - - gaEvent('Payment', 'createDashboardUrl'); - - return request; - } } diff --git a/src/styles/badge.scss b/src/styles/badge.scss index f9fac039a..be3a1055d 100644 --- a/src/styles/badge.scss +++ b/src/styles/badge.scss @@ -19,6 +19,7 @@ display: inline-block; font-size: 14px; padding: 5px 10px; + letter-spacing: 0; &.badge--primary, &.badge--premium { diff --git a/src/styles/settings.scss b/src/styles/settings.scss index 750b6bedd..b286c6f1b 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss @@ -62,13 +62,18 @@ .account { .account__box { background: $dark-theme-gray-darker; } - .invoices { - td { border-bottom: 1px solid $dark-theme-gray-darker; } - .invoices__action button { color: $theme-brand-primary; } + .badge--premium { + margin-left: 10px; + } + + .manage-user-links { + margin-top: 20px; + display: flex; + justify-content: space-between; } } - .premium-info { + .premium-info { background: $dark-theme-gray-darker; border: 2px solid $theme-brand-primary; } -- cgit v1.2.3-70-g09d2 From 229c6017efbd0198747cba6e8997dc8ce4f9a7d4 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 8 Apr 2019 15:32:16 +0200 Subject: Clean up --- src/containers/settings/AccountScreen.js | 36 +------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) (limited to 'src') diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js index 0c837fab9..4ac7328c6 100644 --- a/src/containers/settings/AccountScreen.js +++ b/src/containers/settings/AccountScreen.js @@ -1,4 +1,3 @@ -import { remote } from 'electron'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { inject, observer } from 'mobx-react'; @@ -11,8 +10,6 @@ import AccountDashboard from '../../components/settings/account/AccountDashboard import ErrorBoundary from '../../components/util/ErrorBoundary'; import { WEBSITE } from '../../environment'; -const { BrowserWindow } = remote; - export default @inject('stores', 'actions') @observer class AccountScreen extends Component { componentWillMount() { const { @@ -23,7 +20,7 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend } onCloseWindow() { - const { user, payment } = this.props.stores; + const { user } = this.props.stores; user.getUserInfoRequest.invalidate({ immediately: true }); } @@ -34,36 +31,6 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend payment.plansRequest.reload(); } - async handlePaymentDashboard() { - const { actions, stores } = this.props; - - // actions.payment.createDashboardUrl(); - - // const dashboard = await stores.payment.createDashboardUrlRequest; - - // if (dashboard.url) { - // const paymentWindow = new BrowserWindow({ - // title: '🔒 Franz Subscription Dashboard', - // parent: remote.getCurrentWindow(), - // modal: false, - // width: 900, - // minWidth: 600, - // webPreferences: { - // nodeIntegration: false, - // }, - // }); - // paymentWindow.loadURL(dashboard.url); - - // paymentWindow.on('closed', () => { - // this.onCloseWindow(); - // }); - // } - - const url = `${WEBSITE}/user/billing?token=${stores.user.authToken}&utm_source=app&utm_medium=edit_profile`; - - actions.app.openExternalUrl({ url }); - } - handleWebsiteLink(route) { const { actions, stores } = this.props; @@ -84,7 +51,6 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend Date: Mon, 8 Apr 2019 15:57:21 +0200 Subject: Update strings --- .../settings/account/AccountDashboard.json | 82 +++++++++++----------- 1 file changed, 41 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/i18n/messages/src/components/settings/account/AccountDashboard.json b/src/i18n/messages/src/components/settings/account/AccountDashboard.json index 603950395..22eaf0381 100644 --- a/src/i18n/messages/src/components/settings/account/AccountDashboard.json +++ b/src/i18n/messages/src/components/settings/account/AccountDashboard.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 15, + "line": 13, "column": 12 }, "end": { - "line": 18, + "line": 16, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!Your Subscription", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 19, + "line": 17, "column": 24 }, "end": { - "line": 22, + "line": 20, "column": 3 } }, @@ -30,24 +30,11 @@ "defaultMessage": "!!!Upgrade your Account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 23, + "line": 21, "column": 19 }, "end": { - "line": 26, - "column": 3 - } - }, - { - "id": "settings.account.headlineInvoices", - "defaultMessage": "!!Invoices", - "file": "src/components/settings/account/AccountDashboard.js", - "start": { - "line": 27, - "column": 20 - }, - "end": { - "line": 30, + "line": 24, "column": 3 } }, @@ -56,11 +43,11 @@ "defaultMessage": "!!Danger Zone", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 31, + "line": 25, "column": 22 }, "end": { - "line": 34, + "line": 28, "column": 3 } }, @@ -69,11 +56,11 @@ "defaultMessage": "!!!Manage your subscription", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 35, + "line": 29, "column": 33 }, "end": { - "line": 38, + "line": 32, "column": 3 } }, @@ -82,11 +69,11 @@ "defaultMessage": "!!!Basic Account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 39, + "line": 33, "column": 20 }, "end": { - "line": 42, + "line": 36, "column": 3 } }, @@ -95,11 +82,11 @@ "defaultMessage": "!!!Premium Supporter Account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 43, + "line": 37, "column": 22 }, "end": { - "line": 46, + "line": 40, "column": 3 } }, @@ -108,11 +95,24 @@ "defaultMessage": "!!!Edit Account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 47, + "line": 41, "column": 21 }, "end": { - "line": 50, + "line": 44, + "column": 3 + } + }, + { + "id": "settings.account.headlineInvoices", + "defaultMessage": "!!Invoices", + "file": "src/components/settings/account/AccountDashboard.js", + "start": { + "line": 45, + "column": 18 + }, + "end": { + "line": 48, "column": 3 } }, @@ -121,11 +121,11 @@ "defaultMessage": "!!!Download", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 51, + "line": 49, "column": 19 }, "end": { - "line": 54, + "line": 52, "column": 3 } }, @@ -134,11 +134,11 @@ "defaultMessage": "!!!Could not load user information", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 55, + "line": 53, "column": 25 }, "end": { - "line": 58, + "line": 56, "column": 3 } }, @@ -147,11 +147,11 @@ "defaultMessage": "!!!Try again", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 59, + "line": 57, "column": 28 }, "end": { - "line": 62, + "line": 60, "column": 3 } }, @@ -160,11 +160,11 @@ "defaultMessage": "!!!Delete account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 63, + "line": 61, "column": 17 }, "end": { - "line": 66, + "line": 64, "column": 3 } }, @@ -173,11 +173,11 @@ "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 67, + "line": 65, "column": 14 }, "end": { - "line": 70, + "line": 68, "column": 3 } }, @@ -186,11 +186,11 @@ "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 71, + "line": 69, "column": 19 }, "end": { - "line": 74, + "line": 72, "column": 3 } } -- cgit v1.2.3-70-g09d2 From c41bf73d129d2fba3ec23c1b7b463aaf9dc80dc6 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 8 Apr 2019 15:57:32 +0200 Subject: Add new Team page in settings --- src/app.js | 2 + .../settings/navigation/SettingsNavigation.js | 11 ++ src/components/settings/team/TeamDashboard.js | 125 ++++++++++++++ .../ui/PremiumFeatureContainer/styles.js | 1 + src/containers/settings/TeamScreen.js | 63 +++++++ src/i18n/locales/defaultMessages.json | 192 +++++++++++++++------ src/i18n/locales/en-US.json | 7 + .../settings/navigation/SettingsNavigation.json | 25 ++- .../components/settings/team/TeamDashboard.json | 80 +++++++++ 9 files changed, 452 insertions(+), 54 deletions(-) create mode 100644 src/components/settings/team/TeamDashboard.js create mode 100644 src/containers/settings/TeamScreen.js create mode 100644 src/i18n/messages/src/components/settings/team/TeamDashboard.json (limited to 'src') diff --git a/src/app.js b/src/app.js index 6660feb46..96454779e 100644 --- a/src/app.js +++ b/src/app.js @@ -27,6 +27,7 @@ import RecipesScreen from './containers/settings/RecipesScreen'; import ServicesScreen from './containers/settings/ServicesScreen'; import EditServiceScreen from './containers/settings/EditServiceScreen'; import AccountScreen from './containers/settings/AccountScreen'; +import TeamScreen from './containers/settings/TeamScreen'; import EditUserScreen from './containers/settings/EditUserScreen'; import EditSettingsScreen from './containers/settings/EditSettingsScreen'; import InviteSettingsScreen from './containers/settings/InviteScreen'; @@ -77,6 +78,7 @@ window.addEventListener('load', () => { + diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 953f702f8..0be1a22ba 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js @@ -18,6 +18,10 @@ const messages = defineMessages({ id: 'settings.navigation.account', defaultMessage: '!!!Account', }, + team: { + id: 'settings.navigation.team', + defaultMessage: '!!!Manage Team', + }, settings: { id: 'settings.navigation.settings', defaultMessage: '!!!Settings', @@ -70,6 +74,13 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp > {intl.formatMessage(messages.account)} + + {intl.formatMessage(messages.team)} + ({ + cta: { + marginTop: 40, + }, +}); + + +export default @injectSheet(styles) @observer class TeamDashboard extends Component { + static propTypes = { + user: MobxPropTypes.observableObject.isRequired, + isLoading: PropTypes.bool.isRequired, + userInfoRequestFailed: PropTypes.bool.isRequired, + retryUserInfoRequest: PropTypes.func.isRequired, + openTeamManagement: PropTypes.func.isRequired, + upgradeAccount: PropTypes.func.isRequired, + classes: PropTypes.object.isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + render() { + const { + user, + isLoading, + userInfoRequestFailed, + retryUserInfoRequest, + openTeamManagement, + upgradeAccount, + classes, + } = this.props; + const { intl } = this.context; + + return ( +
+
+ + {intl.formatMessage(messages.headline)} + +
+
+ {isLoading && ( + + )} + + {!isLoading && userInfoRequestFailed && ( + + {intl.formatMessage(messages.userInfoRequestFailed)} + + )} + + {!userInfoRequestFailed && ( + <> + {!isLoading && ( + <> + + <> +

{intl.formatMessage(messages.contentHeadline)}

+

{intl.formatMessage(messages.intro)}

+

{intl.formatMessage(messages.copy)}

+ {user.isSubscriptionOwner && ( +
+ +
+ ); + } +} diff --git a/src/components/ui/PremiumFeatureContainer/styles.js b/src/components/ui/PremiumFeatureContainer/styles.js index 81d6666c6..11cbfbb90 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', diff --git a/src/containers/settings/TeamScreen.js b/src/containers/settings/TeamScreen.js new file mode 100644 index 000000000..3a4b7ef77 --- /dev/null +++ b/src/containers/settings/TeamScreen.js @@ -0,0 +1,63 @@ +import { remote } from 'electron'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { inject, observer } from 'mobx-react'; + +import PaymentStore from '../../stores/PaymentStore'; +import UserStore from '../../stores/UserStore'; +import AppStore from '../../stores/AppStore'; + +import TeamDashboard from '../../components/settings/team/TeamDashboard'; +import ErrorBoundary from '../../components/util/ErrorBoundary'; +import { WEBSITE } from '../../environment'; + +const { BrowserWindow } = remote; + +export default @inject('stores', 'actions') @observer class TeamScreen extends Component { + handleWebsiteLink(route) { + const { actions, stores } = this.props; + + const url = `${WEBSITE}${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; + console.log(url); + + actions.app.openExternalUrl({ url }); + } + + render() { + const { user } = this.props.stores; + + const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; + + return ( + + this.reloadData()} + openTeamManagement={() => this.handleWebsiteLink('/user/team')} + /> + + ); + } +} + +TeamScreen.wrappedComponent.propTypes = { + stores: PropTypes.shape({ + user: PropTypes.instanceOf(UserStore).isRequired, + payment: PropTypes.instanceOf(PaymentStore).isRequired, + app: PropTypes.instanceOf(AppStore).isRequired, + }).isRequired, + actions: PropTypes.shape({ + payment: PropTypes.shape({ + createDashboardUrl: PropTypes.func.isRequired, + }).isRequired, + app: PropTypes.shape({ + openExternalUrl: PropTypes.func.isRequired, + }).isRequired, + user: PropTypes.shape({ + update: PropTypes.func.isRequired, + delete: PropTypes.func.isRequired, + }).isRequired, + }).isRequired, +}; diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 0641c510c..3046f50ce 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -1076,195 +1076,195 @@ "defaultMessage": "!!!Account", "end": { "column": 3, - "line": 18 + "line": 16 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.headline", "start": { "column": 12, - "line": 15 + "line": 13 } }, { "defaultMessage": "!!!Your Subscription", "end": { "column": 3, - "line": 22 + "line": 20 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.headlineSubscription", "start": { "column": 24, - "line": 19 + "line": 17 } }, { "defaultMessage": "!!!Upgrade your Account", "end": { "column": 3, - "line": 26 + "line": 24 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.headlineUpgrade", "start": { "column": 19, - "line": 23 - } - }, - { - "defaultMessage": "!!Invoices", - "end": { - "column": 3, - "line": 30 - }, - "file": "src/components/settings/account/AccountDashboard.js", - "id": "settings.account.headlineInvoices", - "start": { - "column": 20, - "line": 27 + "line": 21 } }, { "defaultMessage": "!!Danger Zone", "end": { "column": 3, - "line": 34 + "line": 28 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.headlineDangerZone", "start": { "column": 22, - "line": 31 + "line": 25 } }, { "defaultMessage": "!!!Manage your subscription", "end": { "column": 3, - "line": 38 + "line": 32 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.manageSubscription.label", "start": { "column": 33, - "line": 35 + "line": 29 } }, { "defaultMessage": "!!!Basic Account", "end": { "column": 3, - "line": 42 + "line": 36 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.accountType.basic", "start": { "column": 20, - "line": 39 + "line": 33 } }, { "defaultMessage": "!!!Premium Supporter Account", "end": { "column": 3, - "line": 46 + "line": 40 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.accountType.premium", "start": { "column": 22, - "line": 43 + "line": 37 } }, { "defaultMessage": "!!!Edit Account", "end": { "column": 3, - "line": 50 + "line": 44 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.account.editButton", "start": { "column": 21, - "line": 47 + "line": 41 + } + }, + { + "defaultMessage": "!!Invoices", + "end": { + "column": 3, + "line": 48 + }, + "file": "src/components/settings/account/AccountDashboard.js", + "id": "settings.account.headlineInvoices", + "start": { + "column": 18, + "line": 45 } }, { "defaultMessage": "!!!Download", "end": { "column": 3, - "line": 54 + "line": 52 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.invoiceDownload", "start": { "column": 19, - "line": 51 + "line": 49 } }, { "defaultMessage": "!!!Could not load user information", "end": { "column": 3, - "line": 58 + "line": 56 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.userInfoRequestFailed", "start": { "column": 25, - "line": 55 + "line": 53 } }, { "defaultMessage": "!!!Try again", "end": { "column": 3, - "line": 62 + "line": 60 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.tryReloadUserInfoRequest", "start": { "column": 28, - "line": 59 + "line": 57 } }, { "defaultMessage": "!!!Delete account", "end": { "column": 3, - "line": 66 + "line": 64 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.deleteAccount", "start": { "column": 17, - "line": 63 + "line": 61 } }, { "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", "end": { "column": 3, - "line": 70 + "line": 68 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.deleteInfo", "start": { "column": 14, - "line": 67 + "line": 65 } }, { "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", "end": { "column": 3, - "line": 74 + "line": 72 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.deleteEmailSent", "start": { "column": 19, - "line": 71 + "line": 69 } } ], @@ -1312,42 +1312,55 @@ } }, { - "defaultMessage": "!!!Settings", + "defaultMessage": "!!!Manage Team", "end": { "column": 3, "line": 24 }, "file": "src/components/settings/navigation/SettingsNavigation.js", + "id": "settings.navigation.team", + "start": { + "column": 8, + "line": 21 + } + }, + { + "defaultMessage": "!!!Settings", + "end": { + "column": 3, + "line": 28 + }, + "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.settings", "start": { "column": 12, - "line": 21 + "line": 25 } }, { "defaultMessage": "!!!Invite Friends", "end": { "column": 3, - "line": 28 + "line": 32 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.inviteFriends", "start": { "column": 17, - "line": 25 + "line": 29 } }, { "defaultMessage": "!!!Logout", "end": { "column": 3, - "line": 32 + "line": 36 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.logout", "start": { "column": 10, - "line": 29 + "line": 33 } } ], @@ -2202,6 +2215,89 @@ ], "path": "src/components/settings/settings/EditSettingsForm.json" }, + { + "descriptors": [ + { + "defaultMessage": "!!!Team", + "end": { + "column": 3, + "line": 16 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.headline", + "start": { + "column": 12, + "line": 13 + } + }, + { + "defaultMessage": "!!!Franz for Teams", + "end": { + "column": 3, + "line": 20 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.contentHeadline", + "start": { + "column": 19, + "line": 17 + } + }, + { + "defaultMessage": "!!!You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", + "end": { + "column": 3, + "line": 24 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.intro", + "start": { + "column": 9, + "line": 21 + } + }, + { + "defaultMessage": "!!!Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", + "end": { + "column": 3, + "line": 28 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.copy", + "start": { + "column": 8, + "line": 25 + } + }, + { + "defaultMessage": "!!!Manage your Team", + "end": { + "column": 3, + "line": 32 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.manageAction", + "start": { + "column": 16, + "line": 29 + } + }, + { + "defaultMessage": "!!!Upgrade your Account", + "end": { + "column": 3, + "line": 36 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.upgradeAction", + "start": { + "column": 17, + "line": 33 + } + } + ], + "path": "src/components/settings/team/TeamDashboard.json" + }, { "descriptors": [ { @@ -3147,7 +3243,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 06cda4aca..8d46f7e29 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -168,6 +168,7 @@ "settings.navigation.inviteFriends": "Invite Friends", "settings.navigation.logout": "Logout", "settings.navigation.settings": "Settings", + "settings.navigation.team": "Manage Team", "settings.navigation.yourServices": "Your services", "settings.recipes.all": "All services", "settings.recipes.dev": "Development", @@ -226,6 +227,12 @@ "settings.services.tooltip.isMuted": "All sounds are muted", "settings.services.tooltip.notificationsDisabled": "Notifications are disabled", "settings.services.updatedInfo": "Your changes have been saved", + "settings.team.contentHeadline": "Franz for Teams", + "settings.team.copy": "Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", + "settings.team.headline": "Team", + "settings.team.intro": "You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", + "settings.team.manageAction": "Manage your Team", + "settings.team.upgradeAction": "Upgrade your Account", "settings.user.form.accountType.company": "Company", "settings.user.form.accountType.individual": "Individual", "settings.user.form.accountType.label": "Account type", diff --git a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json index 785ce9f29..5b854641a 100644 --- a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json +++ b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json @@ -38,16 +38,29 @@ "column": 3 } }, + { + "id": "settings.navigation.team", + "defaultMessage": "!!!Manage Team", + "file": "src/components/settings/navigation/SettingsNavigation.js", + "start": { + "line": 21, + "column": 8 + }, + "end": { + "line": 24, + "column": 3 + } + }, { "id": "settings.navigation.settings", "defaultMessage": "!!!Settings", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 21, + "line": 25, "column": 12 }, "end": { - "line": 24, + "line": 28, "column": 3 } }, @@ -56,11 +69,11 @@ "defaultMessage": "!!!Invite Friends", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 25, + "line": 29, "column": 17 }, "end": { - "line": 28, + "line": 32, "column": 3 } }, @@ -69,11 +82,11 @@ "defaultMessage": "!!!Logout", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 29, + "line": 33, "column": 10 }, "end": { - "line": 32, + "line": 36, "column": 3 } } diff --git a/src/i18n/messages/src/components/settings/team/TeamDashboard.json b/src/i18n/messages/src/components/settings/team/TeamDashboard.json new file mode 100644 index 000000000..91b6754ea --- /dev/null +++ b/src/i18n/messages/src/components/settings/team/TeamDashboard.json @@ -0,0 +1,80 @@ +[ + { + "id": "settings.team.headline", + "defaultMessage": "!!!Team", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 14, + "column": 12 + }, + "end": { + "line": 17, + "column": 3 + } + }, + { + "id": "settings.team.contentHeadline", + "defaultMessage": "!!!Franz for Teams", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 18, + "column": 19 + }, + "end": { + "line": 21, + "column": 3 + } + }, + { + "id": "settings.team.intro", + "defaultMessage": "!!!You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 25, + "column": 3 + } + }, + { + "id": "settings.team.copy", + "defaultMessage": "!!!Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 26, + "column": 8 + }, + "end": { + "line": 29, + "column": 3 + } + }, + { + "id": "settings.team.manageAction", + "defaultMessage": "!!!Manage your Team", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 30, + "column": 16 + }, + "end": { + "line": 33, + "column": 3 + } + }, + { + "id": "settings.team.upgradeAction", + "defaultMessage": "!!!Upgrade your Account", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 34, + "column": 17 + }, + "end": { + "line": 37, + "column": 3 + } + } +] \ No newline at end of file -- cgit v1.2.3-70-g09d2 From b92541305cbeaf32f54ed2751f4ddd880baa2b69 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 8 Apr 2019 16:01:39 +0200 Subject: Clean up --- src/components/settings/team/TeamDashboard.js | 6 ++---- src/containers/settings/TeamScreen.js | 5 ----- 2 files changed, 2 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js index a29a262e9..e222bb14c 100644 --- a/src/components/settings/team/TeamDashboard.js +++ b/src/components/settings/team/TeamDashboard.js @@ -37,11 +37,11 @@ const messages = defineMessages({ }, }); -const styles = theme => ({ +const styles = { cta: { marginTop: 40, }, -}); +}; export default @injectSheet(styles) @observer class TeamDashboard extends Component { @@ -51,7 +51,6 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon userInfoRequestFailed: PropTypes.bool.isRequired, retryUserInfoRequest: PropTypes.func.isRequired, openTeamManagement: PropTypes.func.isRequired, - upgradeAccount: PropTypes.func.isRequired, classes: PropTypes.object.isRequired, }; @@ -66,7 +65,6 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon userInfoRequestFailed, retryUserInfoRequest, openTeamManagement, - upgradeAccount, classes, } = this.props; const { intl } = this.context; diff --git a/src/containers/settings/TeamScreen.js b/src/containers/settings/TeamScreen.js index 3a4b7ef77..30b0895e3 100644 --- a/src/containers/settings/TeamScreen.js +++ b/src/containers/settings/TeamScreen.js @@ -1,9 +1,7 @@ -import { remote } from 'electron'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { inject, observer } from 'mobx-react'; -import PaymentStore from '../../stores/PaymentStore'; import UserStore from '../../stores/UserStore'; import AppStore from '../../stores/AppStore'; @@ -11,8 +9,6 @@ import TeamDashboard from '../../components/settings/team/TeamDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; import { WEBSITE } from '../../environment'; -const { BrowserWindow } = remote; - export default @inject('stores', 'actions') @observer class TeamScreen extends Component { handleWebsiteLink(route) { const { actions, stores } = this.props; @@ -45,7 +41,6 @@ export default @inject('stores', 'actions') @observer class TeamScreen extends C TeamScreen.wrappedComponent.propTypes = { stores: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, - payment: PropTypes.instanceOf(PaymentStore).isRequired, app: PropTypes.instanceOf(AppStore).isRequired, }).isRequired, actions: PropTypes.shape({ -- cgit v1.2.3-70-g09d2 From 827e4b7727e7f4abcb5472eb84c45c3f65efaf9c Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 8 Apr 2019 16:40:44 +0200 Subject: Restore classic layout when user has no subscription --- .../settings/account/AccountDashboard.js | 47 ++++++++++++---------- 1 file changed, 26 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js index ca8b9e1bd..2a9c9a599 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js @@ -164,28 +164,33 @@ export default @observer class AccountDashboard extends Component { {user.organization && `${user.organization}, `} {user.email} -
-
+ {user.isSubscriptionOwner && ( +
+
+ )} + {!user.isSubscriptionOwner && ( + )} {isDelayAppScreenVisible && ()} diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index 8c1d2dfc1..d2891a6a4 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js @@ -136,6 +136,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e isOnline={app.isOnline} showServicesUpdatedInfoBar={ui.showServicesUpdatedInfoBar} appUpdateIsDownloaded={app.updateStatus === app.updateStatusTypes.DOWNLOADED} + nextAppReleaseVersion={app.nextAppReleaseVersion} sidebar={sidebar} workspacesDrawer={workspacesDrawer} services={servicesContainer} diff --git a/src/electron/ipc-api/autoUpdate.js b/src/electron/ipc-api/autoUpdate.js index 74b718734..9a04c1958 100644 --- a/src/electron/ipc-api/autoUpdate.js +++ b/src/electron/ipc-api/autoUpdate.js @@ -30,9 +30,12 @@ export default (params) => { params.mainWindow.webContents.send('autoUpdate', { available: false }); }); - autoUpdater.on('update-available', () => { + autoUpdater.on('update-available', (event) => { debug('update-available'); - params.mainWindow.webContents.send('autoUpdate', { available: true }); + params.mainWindow.webContents.send('autoUpdate', { + version: event.version, + available: true, + }); }); autoUpdater.on('download-progress', (progressObj) => { diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 3323aa310..df7f04a06 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -625,78 +625,78 @@ "defaultMessage": "!!!Your services have been updated.", "end": { "column": 3, - "line": 29 + "line": 30 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.servicesUpdated", "start": { "column": 19, - "line": 26 + "line": 27 } }, { "defaultMessage": "!!!A new update for Franz is available.", "end": { "column": 3, - "line": 33 + "line": 34 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.updateAvailable", "start": { "column": 19, - "line": 30 + "line": 31 } }, { "defaultMessage": "!!!Reload services", "end": { "column": 3, - "line": 37 + "line": 38 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.buttonReloadServices", "start": { "column": 24, - "line": 34 + "line": 35 } }, { "defaultMessage": "!!!Changelog", "end": { "column": 3, - "line": 41 + "line": 42 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.buttonChangelog", "start": { "column": 13, - "line": 38 + "line": 39 } }, { "defaultMessage": "!!!Restart & install update", "end": { "column": 3, - "line": 45 + "line": 46 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.buttonInstallUpdate", "start": { "column": 23, - "line": 42 + "line": 43 } }, { "defaultMessage": "!!!Could not load services and user information", "end": { "column": 3, - "line": 49 + "line": 50 }, "file": "src/components/layout/AppLayout.js", "id": "infobar.requiredRequestsFailed", "start": { "column": 26, - "line": 46 + "line": 47 } } ], diff --git a/src/i18n/messages/src/components/layout/AppLayout.json b/src/i18n/messages/src/components/layout/AppLayout.json index 4dd354afc..26b8ce040 100644 --- a/src/i18n/messages/src/components/layout/AppLayout.json +++ b/src/i18n/messages/src/components/layout/AppLayout.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Your services have been updated.", "file": "src/components/layout/AppLayout.js", "start": { - "line": 26, + "line": 27, "column": 19 }, "end": { - "line": 29, + "line": 30, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!A new update for Franz is available.", "file": "src/components/layout/AppLayout.js", "start": { - "line": 30, + "line": 31, "column": 19 }, "end": { - "line": 33, + "line": 34, "column": 3 } }, @@ -30,11 +30,11 @@ "defaultMessage": "!!!Reload services", "file": "src/components/layout/AppLayout.js", "start": { - "line": 34, + "line": 35, "column": 24 }, "end": { - "line": 37, + "line": 38, "column": 3 } }, @@ -43,11 +43,11 @@ "defaultMessage": "!!!Changelog", "file": "src/components/layout/AppLayout.js", "start": { - "line": 38, + "line": 39, "column": 13 }, "end": { - "line": 41, + "line": 42, "column": 3 } }, @@ -56,11 +56,11 @@ "defaultMessage": "!!!Restart & install update", "file": "src/components/layout/AppLayout.js", "start": { - "line": 42, + "line": 43, "column": 23 }, "end": { - "line": 45, + "line": 46, "column": 3 } }, @@ -69,11 +69,11 @@ "defaultMessage": "!!!Could not load services and user information", "file": "src/components/layout/AppLayout.js", "start": { - "line": 46, + "line": 47, "column": 26 }, "end": { - "line": 49, + "line": 50, "column": 3 } } diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index ca0c9175b..e68e797ef 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js @@ -67,6 +67,8 @@ export default class AppStore extends Store { @observable isFocused = true; + @observable nextAppReleaseVersion = null; + dictionaries = []; constructor(...args) { @@ -123,7 +125,7 @@ export default class AppStore extends Store { ipcRenderer.on('autoUpdate', (event, data) => { if (data.available) { this.updateStatus = this.updateStatusTypes.AVAILABLE; - + this.nextAppReleaseVersion = data.version; if (isMac) { app.dock.bounce(); } diff --git a/src/styles/info-bar.scss b/src/styles/info-bar.scss index fb4917358..d3010942f 100644 --- a/src/styles/info-bar.scss +++ b/src/styles/info-bar.scss @@ -43,6 +43,10 @@ } } + .info-bar__inline-button { + color: white; + } + &.info-bar--bottom { order: 10; } &.info-bar--primary { -- cgit v1.2.3-70-g09d2 From bf43589edd454ee295ee0e09831aeddcd75a2dd9 Mon Sep 17 00:00:00 2001 From: FranzBot Date: Fri, 12 Apr 2019 15:37:34 +0000 Subject: Automatic i18n update (i18n.meetfranz.com) --- src/i18n/locales/ca.json | 42 +++++++++++++- src/i18n/locales/cs.json | 48 ++++++++++++++-- src/i18n/locales/de.json | 136 ++++++++++++++++++++++++++------------------ src/i18n/locales/el.json | 42 +++++++++++++- src/i18n/locales/es.json | 64 ++++++++++++++++----- src/i18n/locales/fr.json | 68 +++++++++++++++++----- src/i18n/locales/ga.json | 42 +++++++++++++- src/i18n/locales/hr.json | 42 +++++++++++++- src/i18n/locales/hu.json | 42 +++++++++++++- src/i18n/locales/id.json | 78 ++++++++++++++++++------- src/i18n/locales/it.json | 74 ++++++++++++++++++------ src/i18n/locales/ja.json | 66 ++++++++++++++++----- src/i18n/locales/ka.json | 42 +++++++++++++- src/i18n/locales/nl-BE.json | 42 +++++++++++++- src/i18n/locales/nl.json | 42 +++++++++++++- src/i18n/locales/pl.json | 42 +++++++++++++- src/i18n/locales/pt-BR.json | 54 +++++++++++++++--- src/i18n/locales/pt.json | 48 ++++++++++++++-- src/i18n/locales/ru.json | 60 +++++++++++++++---- src/i18n/locales/sk.json | 42 +++++++++++++- src/i18n/locales/sr.json | 42 +++++++++++++- src/i18n/locales/tr.json | 42 +++++++++++++- src/i18n/locales/uk.json | 42 +++++++++++++- src/i18n/locales/zh-TW.json | 42 +++++++++++++- 24 files changed, 1092 insertions(+), 192 deletions(-) (limited to 'src') diff --git a/src/i18n/locales/ca.json b/src/i18n/locales/ca.json index dabe4ba16..240f45afc 100644 --- a/src/i18n/locales/ca.json +++ b/src/i18n/locales/ca.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Recarrega", "app.errorHandler.headline" : "Quelcom ha anat malament", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Aconsegueix una llicència de suport per a Franz", "feature.delayApp.headline" : "Si us plau, compra una llicència de suport per a Franz per saltar l'espera", "feature.delayApp.text" : "Franz continuarà en {seconds} segons", @@ -9,7 +10,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" : "No es pot connectar amb els serveis en línia de Franz", "global.notConnectedToTheInternet" : "No esteu connectat a Internet.", @@ -43,6 +44,7 @@ "login.submit.label" : "Accedir", "login.tokenExpired" : "La teva sessió ha caducat, torna a iniciar la sessió.", "menu.app.about" : "Sobre Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Amaga", "menu.app.hideOthers" : "Amaga altres", "menu.app.quit" : "Surt", @@ -87,6 +89,11 @@ "menu.window" : "Finestra", "menu.window.close" : "Tanca", "menu.window.minimize" : "Minimitza", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Tots els serveis", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Correu electrònic", "password.headline" : "Restablir contrasenya", "password.link.login" : "Inicia la sessió al teu compte", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Oh no!", "service.errorHandler.message" : "Error", "service.errorHandler.text" : "{name} ha fallat al carregar", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Introducció", "services.welcome" : "Benvingut a Franz", "settings.account.account.editButton" : "Editar Compte", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "General", "settings.app.headlineLanguage" : "Idioma", "settings.app.headlineUpdates" : "Actualitzacions", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Els canvis requereixen reiniciar", "settings.app.subheadlineCache" : "Memòria cau", "settings.app.translationHelp" : "Ajuda'ns a traduir Franz en la teva llengua.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Sortir", "settings.navigation.settings" : "Configuració", "settings.navigation.yourServices" : "Els vostres serveis", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Tots els serveis", "settings.recipes.dev" : "Desenvolupament", "settings.recipes.headline" : "Serveis disponibles", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Nom", "settings.user.form.lastname" : "Cognoms", "settings.user.form.newPassword" : "Nova contrasenya", + "settings.workspace.add.form.name" : "Nom", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Nom", + "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" : "Torna a provar-ho", + "settings.workspaces.updatedInfo" : "S'han desat els canvis", + "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" : "Afegeix nou servei", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Desactivar notificacions i àudio", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Configuració", "sidebar.unmuteApp" : "Activar notificacions i àudio", "signup.company.label" : "Empresa", @@ -281,5 +308,16 @@ "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.signupButton" : "Crea un compte gratuït", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Tots els serveis", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/cs.json b/src/i18n/locales/cs.json index f0b0b7c81..c053604b7 100644 --- a/src/i18n/locales/cs.json +++ b/src/i18n/locales/cs.json @@ -1,15 +1,16 @@ { "app.errorHandler.action" : "Obnovit", "app.errorHandler.headline" : "Něco se pokazilo", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Podpoř Franz a získej Supporter licenci", "feature.delayApp.headline" : "Kup si Franz Supporter licenci a nebudeš už muset čekat", "feature.delayApp.text" : "Franz bude pokračovat v {seconds} sekundách.", - "feature.shareFranz.action.email" : "Send as email", - "feature.shareFranz.action.facebook" : "Share on Facebook", - "feature.shareFranz.action.twitter" : "Share on Twitter", + "feature.shareFranz.action.email" : "Poslat jako e-mail", + "feature.shareFranz.action.facebook" : "Sdílet na Facebooku", + "feature.shareFranz.action.twitter" : "Sdílet na Twitteru", "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" : "Nemůžeme připojit Franz k online službám", "global.notConnectedToTheInternet" : "Připojení k internetu není k dispozici.", @@ -43,6 +44,7 @@ "login.submit.label" : "Přihlásit se", "login.tokenExpired" : "Sezení vypršelo, prosím přihlaste se znovu", "menu.app.about" : "O aplikaci", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Skrýt", "menu.app.hideOthers" : "Skryt ostatní", "menu.app.quit" : "Ukončit", @@ -87,6 +89,11 @@ "menu.window" : "Okno", "menu.window.close" : "Zavřít", "menu.window.minimize" : "Minimalizovat", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Všechny služby", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "E-mailová adresa", "password.headline" : "Obnovit heslo", "password.link.login" : "Přihlásit se k účtu", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Ale ne!", "service.errorHandler.message" : "Chyba", "service.errorHandler.text" : "{name} se nepodařilo načíst.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Začněme", "services.welcome" : "Vítejte v programu Franz", "settings.account.account.editButton" : "Upravit účet", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Obecné", "settings.app.headlineLanguage" : "Jazyk", "settings.app.headlineUpdates" : "Aktualizace", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Změny vyžadují restart", "settings.app.subheadlineCache" : "Mezipaměť", "settings.app.translationHelp" : "Pomozte nám přeložit Franz do svého jazyka.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Odhlásit", "settings.navigation.settings" : "Nastavení", "settings.navigation.yourServices" : "Vaše služby", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Všechny služby", "settings.recipes.dev" : "Vývoj", "settings.recipes.headline" : "Dostupné služby", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Jméno", "settings.user.form.lastname" : "Příjmení", "settings.user.form.newPassword" : "Nové heslo", + "settings.workspace.add.form.name" : "Jméno", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Jméno", + "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" : "Zkusit opět", + "settings.workspaces.updatedInfo" : "Vaše změny byly uloženy", + "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" : "Přidat novou službu", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Vypnout upozornění a zvuky", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Nastavení", "sidebar.unmuteApp" : "Zapnout upozornění a zvuky", "signup.company.label" : "Společnost", @@ -281,5 +308,16 @@ "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.signupButton" : "Vytvořit účet zdarma", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Všechny služby", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 06a03db65..a96ddd03d 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -1,41 +1,42 @@ { "app.errorHandler.action" : "Neu laden", - "app.errorHandler.headline" : "Es trat ein Fehler auf", - "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.", + "app.errorHandler.headline" : "Es ist ein Fehler aufgetreten", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", + "feature.delayApp.action" : "Hol dir Franz Premium!", + "feature.delayApp.headline" : "Erspare dir das Warten mit Franz Premium!", + "feature.delayApp.text" : "In {seconds} Sekunden geht's weiter!", "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", + "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" : "Bitte erzähle deinen Freunden und Kolleginnen, warum du Franz toll findest.", + "global.api.unhealthy" : "Verbindung zum Franz Online Service fehlgeschlagen", "global.notConnectedToTheInternet" : "Du bist nicht mit dem Internet verbunden.", "global.spellchecker.useDefault" : "Standard benutzen ({default})", "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.headline" : "Deine Franz-4-Dienste importieren", "import.notSupportedHeadline" : "Dienste, die noch nicht von Franz 5 unterstützt werden", "import.skip.label" : "Ich möchte Dienste selbst hinzufügen", "import.submit.label" : "Dienste importieren", - "infobar.buttonChangelog" : "Was ist neu?", + "infobar.buttonChangelog" : "Was gibt es Neues?", "infobar.buttonInstallUpdate" : "Neu starten & Update installieren", - "infobar.buttonReloadServices" : "Dienste neuladen", + "infobar.buttonReloadServices" : "Dienste neu laden", "infobar.requiredRequestsFailed" : "Dienste und Benutzerinformationen konnten nicht geladen werden", "infobar.servicesUpdated" : "Deine Dienste wurden aktualisiert.", - "infobar.updateAvailable" : "Eine neue Version von Franz ist verfügbar.", + "infobar.updateAvailable" : "Eine neue Version von Franz ist verfügbar!", "invite.email.label" : "E-Mail-Adresse", - "invite.headline.friends" : "Lade 3 Freunde oder Kollegen ein", + "invite.headline.friends" : "Lade drei Freunde oder Kolleginnen ein!", "invite.name.label" : "Name", - "invite.skip.label" : "Ich möchte das später tun", + "invite.skip.label" : "Jetzt nicht! Ich möchte das später tun.", "invite.submit.label" : "Einladungen schicken", - "invite.successInfo" : "Die Einladungen wurden erfolgreich gesendet.", + "invite.successInfo" : "Die Einladungen wurden erfolgreich versendet.", "login.email.label" : "E-Mail-Adresse", "login.headline" : "Anmelden", - "login.invalidCredentials" : "E-Mail Adresse oder Passwort ungültig", + "login.invalidCredentials" : "E-Mail-Adresse oder Passwort ungültig", "login.link.password" : "Passwort zurücksetzen", "login.link.signup" : "Kostenloses Konto erstellen", "login.password.label" : "Passwort", @@ -43,6 +44,7 @@ "login.submit.label" : "Anmelden", "login.tokenExpired" : "Deine Sitzung ist abgelaufen, bitte melde Dich erneut an.", "menu.app.about" : "Über Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Ausblenden", "menu.app.hideOthers" : "Andere ausblenden", "menu.app.quit" : "Beenden", @@ -87,12 +89,14 @@ "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", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Alle Dienste", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", + "password.email.label" : "E-Mail-Adresse", "password.headline" : "Passwort zurücksetzen", - "password.link.login" : "An Deinem Konto anmelden", + "password.link.login" : "Mit deinem Konto anmelden", "password.link.signup" : "Kostenloses Konto erstellen", "password.noUser" : "Es wurde kein Benutzer mit dieser E-Mail-Adresse gefunden.", "password.submit.label" : "Absenden", @@ -102,28 +106,29 @@ "pricing.link.skipPayment" : "Ich möchte die Entwicklung von Franz nicht unterstützen.", "pricing.submit.label" : "Ich möchte die Entwicklung von Franz unterstützen.", "pricing.support.label" : "Wie möchtest Du Franz unterstützen?", - "service.crashHandler.action" : "{name} neuladen", + "service.crashHandler.action" : "{name} neu laden", "service.crashHandler.autoReload" : "{name} wird in {seconds} Sekunden automatisch wiederhergestellt", "service.crashHandler.headline" : "Oh nein!", "service.crashHandler.text" : "{name} hat einen Fehler verursacht.", "service.disabledHandler.action" : "{name} aktivieren", "service.disabledHandler.headline" : "{name} ist deaktiviert", - "service.errorHandler.action" : "{name} neuladen", + "service.errorHandler.action" : "{name} neu laden", "service.errorHandler.editAction" : "{name} bearbeiten", "service.errorHandler.headline" : "Oh nein!", "service.errorHandler.message" : "Fehler", "service.errorHandler.text" : "{name} konnte nicht geladen werden.", - "services.getStarted" : "Loslegen", - "services.welcome" : "Willkommen bei Franz.", + "service.webviewLoader.loading" : "Loading", + "services.getStarted" : "Los geht's!", + "services.welcome" : "Willkommen bei Franz!", "settings.account.account.editButton" : "Konto bearbeiten", - "settings.account.accountType.basic" : "Basis Konto", - "settings.account.accountType.premium" : "Premium-Supporter Konto", + "settings.account.accountType.basic" : "Basis-Konto", + "settings.account.accountType.premium" : "Premium Lizenz", "settings.account.buttonSave" : "Profil aktualisieren", "settings.account.deleteAccount" : "Benutzerkonto löschen", - "settings.account.deleteEmailSent" : "Du hast eine Email zur Bestätigung der Löschung Deines Benutzerkontos erhalten. Dein Benutzerkonto und Deine Daten können nach der Löschung nicht wiederhergestellt werden!", - "settings.account.deleteInfo" : "Wenn du dein Franz Benutzerkonto nicht mehr länger benötigst, kannst du hier deinen Account und alle dazugehörigen Daten löschen.", + "settings.account.deleteEmailSent" : "Du hast eine E-Mail zur Bestätigung der Löschung Deines Benutzerkontos erhalten. Dein Benutzerkonto und Deine Daten können nach der Löschung nicht wiederhergestellt werden!", + "settings.account.deleteInfo" : "Wenn du dein Franz-Benutzerkonto nicht mehr länger benötigst, kannst du es hier mit allen dazugehörigen Daten löschen.", "settings.account.headline" : "Konto", - "settings.account.headlineAccount" : "Konto Informationen", + "settings.account.headlineAccount" : "Konto-Informationen", "settings.account.headlineDangerZone" : "Benutzerkonto löschen", "settings.account.headlineInvoices" : "Rechnungen", "settings.account.headlinePassword" : "Passwort ändern", @@ -144,7 +149,7 @@ "settings.app.form.autoLaunchInBackground" : "Im Hintergrund öffnen", "settings.app.form.autoLaunchOnStart" : "Franz beim Systemstart ausführen", "settings.app.form.beta" : "Beta-Versionen einbeziehen", - "settings.app.form.darkMode" : "Die dunkle Seite erwartet dich (Dark Mode)", + "settings.app.form.darkMode" : "Die dunkle Seite erwartet dich! (Dark Mode)", "settings.app.form.enableGPUAcceleration" : "Hardwarebeschleunigung aktivieren", "settings.app.form.enableSpellchecking" : "Rechtschreibprüfung aktivieren", "settings.app.form.enableSystemTray" : "Franz im Infobereich anzeigen", @@ -159,26 +164,27 @@ "settings.app.headlineGeneral" : "Allgemeines", "settings.app.headlineLanguage" : "Sprache", "settings.app.headlineUpdates" : "Updates", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Änderungen werden erst nach einem Neustart wirksam.", "settings.app.subheadlineCache" : "Cache", "settings.app.translationHelp" : "Hilf uns, Franz in Deine Sprache zu übersetzen.", - "settings.app.updateStatusAvailable" : "Update verfügbar, lädt herunter...", + "settings.app.updateStatusAvailable" : "Update verfügbar, lädt herunter ...", "settings.app.updateStatusSearching" : "Suche nach Updates", "settings.app.updateStatusUpToDate" : "Du nutzt die aktuellste Version von Franz", - "settings.invite.headline" : "Lade 3 Deiner Freunde ein", + "settings.invite.headline" : "Lade drei Deiner Freunde ein", "settings.navigation.account" : "Konto", "settings.navigation.availableServices" : "Verfügbare Dienste", "settings.navigation.inviteFriends" : "Freunde einladen", "settings.navigation.logout" : "Abmelden", "settings.navigation.settings" : "Einstellungen", "settings.navigation.yourServices" : "Deine Dienste", - "settings.navigation.yourWorkspaces": "Deine Workspaces", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Alle Dienste", "settings.recipes.dev" : "Entwicklung", "settings.recipes.headline" : "Verfügbare Dienste", "settings.recipes.missingService" : "Fehlt ein Dienst?", "settings.recipes.mostPopular" : "Am beliebtesten", - "settings.recipes.nothingFound" : "Entschuldigung, aber der von Dir gesuchte Dienst konnte nicht gefunden werden.", + "settings.recipes.nothingFound" : "Entschuldigung, der gesuchte Dienst konnte nicht gefunden werden.", "settings.recipes.servicesSuccessfulAddedInfo" : "Dienst erfolgreich hinzugefügt", "settings.searchService" : "Dienst suchen", "settings.service.error.goBack" : "Zurück zu den Diensten", @@ -187,7 +193,7 @@ "settings.service.form.addServiceHeadline" : "{name} hinzufügen", "settings.service.form.availableServices" : "Verfügbare Dienste", "settings.service.form.customUrl" : "Eigener Server", - "settings.service.form.customUrlPremiumInfo" : "Um einen selbst gehosteten Dienst hinzuzufügen, brauchst Du ein Franz Premium-Supporter Konto.", + "settings.service.form.customUrlPremiumInfo" : "Um einen selbst gehosteten Dienst hinzuzufügen, brauchst Du ein Franz Premium Konto.", "settings.service.form.customUrlUpgradeAccount" : "Dein Konto upgraden", "settings.service.form.customUrlValidationError" : "Dein {name}-Server konnte nicht verifiziert werden.", "settings.service.form.deleteButton" : "Dienst löschen", @@ -207,13 +213,13 @@ "settings.service.form.indirectMessages" : "Nachrichten-Badge für alle neuen Nachrichten anzeigen", "settings.service.form.isMutedInfo" : "Sämtliche Wiedergabe von Tönen wird deaktiviert", "settings.service.form.name" : "Name", - "settings.service.form.proxy.headline" : "HTTP\/HTTPS Proxy Einstellungen", + "settings.service.form.proxy.headline" : "HTTP-\/HTTPS-Proxy-Einstellungen", "settings.service.form.proxy.host" : "Proxy Host\/IP", - "settings.service.form.proxy.info" : "Proxy Einstellungen werden nicht mit den Franz Servern synchronisiert.", - "settings.service.form.proxy.isEnabled" : "Proxy Server verwenden", + "settings.service.form.proxy.info" : "Proxy-Einstellungen werden nicht mit den Franz Servern synchronisiert.", + "settings.service.form.proxy.isEnabled" : "Proxy-Server verwenden", "settings.service.form.proxy.password" : "Passwort (optional)", "settings.service.form.proxy.port" : "Port", - "settings.service.form.proxy.restartInfo" : "Bitte starte Franz nach dem Ändern der Proxy Einstellungen neu.", + "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.tabHosted" : "Gehostet", @@ -230,14 +236,6 @@ "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.add.form.submitButton": "Workspace erstellen", - "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.servicesInWorkspaceHeadline": "Services in diesem Workspace", "settings.user.form.accountType.company" : "Firma", "settings.user.form.accountType.individual" : "Einzelperson", "settings.user.form.accountType.label" : "Konto-Typ", @@ -247,30 +245,47 @@ "settings.user.form.firstname" : "Vorname", "settings.user.form.lastname" : "Nachname", "settings.user.form.newPassword" : "Neues Passwort", + "settings.workspace.add.form.name" : "Name", + "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" : "Erneut versuchen", + "settings.workspaces.updatedInfo" : "Deine Änderungen wurden gespeichert", + "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" : "Neuen Dienst hinzufügen", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Benachrichtigungen & Audio deaktivieren", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Einstellungen", "sidebar.unmuteApp" : "Benachrichtigungen & Audio aktivieren", "signup.company.label" : "Firma", - "signup.email.label" : "E-Mail Adresse", + "signup.email.label" : "E-Mail-Adresse", "signup.emailDuplicate" : "Es existiert bereits ein Benutzer mit dieser E-Mail Adresse.", "signup.firstname.label" : "Vorname", "signup.headline" : "Anmelden", "signup.lastname.label" : "Nachname", - "signup.legal.info" : "Mit der Erstellung eines Franz Kontos akzeptierst Du die", + "signup.legal.info" : "Mit der Erstellung eines Franz-Kontos akzeptierst Du die", "signup.legal.privacy" : "Datenschutzerklärung", "signup.legal.terms" : "Nutzungsbedingungen", "signup.link.login" : "Du hast bereits ein Konto? Melde Dich an.", "signup.password.label" : "Passwort", "signup.submit.label" : "Konto erstellen", - "subscription.euTaxInfo" : "Preise sind exklusive Steuern.", + "subscription.euTaxInfo" : "Preise zuzüglich allfälliger Steuern", "subscription.features.ads" : "Werbefrei auf Lebenszeit!", "subscription.features.comingSoon" : "folgt bald", - "subscription.features.noInterruptions" : "Keine Wartezeiten um Franz zu verwenden", - "subscription.features.onpremise.mattermost" : "Integration von gehosteten Diensten, wie Mattermost", + "subscription.features.noInterruptions" : "Verwende Franz ohne Wartezeiten", + "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", - "subscription.includedFeatures" : "Bezahlte Franz Premium Support Konten beinhalten", + "subscription.includedFeatures" : "Bezahlte Franz Premium Lizenzen beinhalten", "subscription.paymentSessionError" : "Das Zahlungs-Formular konnte nicht geladen werden.", "subscription.submit.label" : "Ich möchte die Entwicklung von Franz unterstützen", "subscription.type.free" : "kostenlos", @@ -286,12 +301,23 @@ "tabs.item.enableAudio" : "Audio aktivieren", "tabs.item.enableNotification" : "Benachrichtigungen aktivieren", "tabs.item.enableService" : "Dienst aktivieren", - "tabs.item.reload" : "Neuladen", + "tabs.item.reload" : "Neu laden", "validation.email" : "{field} ist ungültig", "validation.minLength" : "{field} muss mindestens {length} Zeichen enthalten", "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", - "welcome.signupButton" : "Kostenloses Konto erstellen" + "welcome.signupButton" : "Kostenloses Konto erstellen", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Alle Dienste", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/el.json b/src/i18n/locales/el.json index 626abfddd..b675d25c5 100644 --- a/src/i18n/locales/el.json +++ b/src/i18n/locales/el.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Επαναφόρτωση", "app.errorHandler.headline" : "Κάτι δεν λειτουργεί", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Get a Franz Supporter License", "feature.delayApp.headline" : "Please purchase a Franz Supporter License to skip waiting", "feature.delayApp.text" : "Franz θα συνεχίσει σε {seconds} δευτερόλεπτα.", @@ -9,7 +10,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" : "Δεν είναι δυνατή η σύνδεση με τις ζωντανές υπηρεσίες του Franz", "global.notConnectedToTheInternet" : "Έχετε αποσυνδεθεί από το Διαδίκτυο", @@ -43,6 +44,7 @@ "login.submit.label" : "Σύνδεση", "login.tokenExpired" : "Η συνεδρία σας έληξε, συνδεθείτε ξανά.", "menu.app.about" : "Σχετικά με το Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Απόκρυψη", "menu.app.hideOthers" : "Απόκρυψη των άλλων", "menu.app.quit" : "Έξοδος", @@ -87,6 +89,11 @@ "menu.window" : "Παράθυρο", "menu.window.close" : "Κλείσιμο", "menu.window.minimize" : "Ελαχιστοποίηση", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Όλες οι υπηρεσίες", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Διεύθυνση ηλεκτρονικού ταχυδρομείου", "password.headline" : "Επαναφορά κωδικού πρόσβασης", "password.link.login" : "Σύνδεση στο λογαριασμό σας", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Ω, όχι!", "service.errorHandler.message" : "Σφάλμα", "service.errorHandler.text" : "{name} has failed to load.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Ξεκινήστε", "services.welcome" : "Καλώς ορίσατε στον Franz", "settings.account.account.editButton" : "Επεξεργασία λογαριασμού", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Γενικά", "settings.app.headlineLanguage" : "Γλώσσα", "settings.app.headlineUpdates" : "Ενημερώσεις", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Οι αλλαγές απαιτούν επανεκκίνηση", "settings.app.subheadlineCache" : "Λανθάνουσα μνήμη", "settings.app.translationHelp" : "Βοηθήστε μας να μεταφράσουμε το Franz στη δική σας γλώσσα.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Αποσύνδεση", "settings.navigation.settings" : "Ρυθμίσεις", "settings.navigation.yourServices" : "Οι υπηρεσίες σας", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Όλες οι υπηρεσίες", "settings.recipes.dev" : "Ανάπτυξη", "settings.recipes.headline" : "Διαθέσιμες υπηρεσίες", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Όνομα", "settings.user.form.lastname" : "Επίθετο", "settings.user.form.newPassword" : "Νέος κωδικός πρόσβασης", + "settings.workspace.add.form.name" : "Όνομα", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.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" : "Δοκιμάστε ξανά", + "settings.workspaces.updatedInfo" : "Οι αλλαγές σας έχουν αποθηκευτεί", + "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" : "Προσθήκη νέας υπηρεσίας", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Απενεργοποίηση ειδοποιήσεων & ήχου", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Ρυθμίσεις", "sidebar.unmuteApp" : "Ενεργοποίηση ειδοποιήσεων & ήχου", "signup.company.label" : "Εταιρεία", @@ -281,5 +308,16 @@ "validation.required" : "{field} είναι υποχρεωτικό", "validation.url" : "{field} δεν είναι έγκυρος σύνδεσμος URL", "welcome.loginButton" : "Σύνδεση στο λογαριασμό σας", - "welcome.signupButton" : "Δημιουργία δωρεάν λογαριασμού" + "welcome.signupButton" : "Δημιουργία δωρεάν λογαριασμού", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Όλες οι υπηρεσίες", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 5c26b456c..5d542569b 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -1,21 +1,22 @@ { "app.errorHandler.action" : "Recargar", "app.errorHandler.headline" : "Ha surgido un error", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Consigue una Licencia de Soporte de Franz", "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.email" : "Envía como correo", "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", - "feature.shareFranz.text" : "Tell your friends and colleagues how awesome Franz is and help us to spread the word.", + "feature.shareFranz.headline" : "¡Juntos mejoramos Franz!", + "feature.shareFranz.shareText.email" : "¡He añadido {count} servicios a Franz! Obtén la aplicación gratuita para WhatsApp, Messenger, Slack, Skype en 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 @FranzMessenger", + "feature.shareFranz.text" : "Dile a tus amigos y colegas lo asombroso que es Franz y ayúdanos a correr la voz.", "global.api.unhealthy" : "No es posible conectarse a los servicios en línea de Franz.", "global.notConnectedToTheInternet" : "No estás conectado a Internet", "global.spellchecker.useDefault" : "Utilizar estándar del sistema ({default})", - "global.spellchecking.autodetect" : "Detect language automatically", - "global.spellchecking.autodetect.short" : "Automatic", + "global.spellchecking.autodetect" : "Detectar el idioma automáticamente", + "global.spellchecking.autodetect.short" : "Automático", "global.spellchecking.language" : "Corrector de ortografía", "import.headline" : "Importa tus servicios de Franz 4", "import.notSupportedHeadline" : "Servicios no admitidos aún en Franz 5", @@ -43,6 +44,7 @@ "login.submit.label" : "Iniciar sesión", "login.tokenExpired" : "Tu sesión ha expirado, por favor inicia sesión de nuevo.", "menu.app.about" : "Sobre Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Ocultar", "menu.app.hideOthers" : "Ocultar otros", "menu.app.quit" : "Salir", @@ -70,9 +72,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.activatePreviousService" : "Activa el servicio previo", "menu.services.addNewService" : "Añadir Nuevo Servicio...", - "menu.services.setNextServiceActive" : "Activate next service", + "menu.services.setNextServiceActive" : "Activa el siguiente servicio", "menu.view" : "Mostrar", "menu.view.enterFullScreen" : "Pasar a pantalla completa", "menu.view.exitFullScreen" : "Salir de Pantalla Completa", @@ -87,6 +89,11 @@ "menu.window" : "Ventana", "menu.window.close" : "Cerrar", "menu.window.minimize" : "Minimizar", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Todos los servicios", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Dirección de correo electrónico", "password.headline" : "Restablecer contraseña", "password.link.login" : "Inicia sesión en tu cuenta", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "¡Oh, no!", "service.errorHandler.message" : "Error", "service.errorHandler.text" : "{name} ha fallado la carga", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Primeros pasos", "services.welcome" : "Bienvenido a Franz", "settings.account.account.editButton" : "Editar cuenta", @@ -131,7 +139,7 @@ "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.tryReloadUserInfoRequest" : "Intenta de nuevo", "settings.account.userInfoRequestFailed" : "No se pudo cargar la información de usuario", "settings.app.buttonClearAllCache" : "Limpiar caché", "settings.app.buttonInstallUpdate" : "Reiniciar e instalar actualizaciones", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "General", "settings.app.headlineLanguage" : "Idioma", "settings.app.headlineUpdates" : "Actualizaciones", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Los cambios requieren reiniciar", "settings.app.subheadlineCache" : "Caché", "settings.app.translationHelp" : "Ayúdanos a traducir Franz a tu idioma.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Cerrar sesión", "settings.navigation.settings" : "Configuración", "settings.navigation.yourServices" : "Tus servicios", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Todos los servicios", "settings.recipes.dev" : "Desarrollo", "settings.recipes.headline" : "Servicios disponibles", @@ -221,7 +231,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.servicesRequestFailed" : "No pudo cargar tus servicios", "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", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Nombre", "settings.user.form.lastname" : "Apellido", "settings.user.form.newPassword" : "Nueva contraseña", + "settings.workspace.add.form.name" : "Nombre", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Nombre", + "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" : "Tus cambios han sido guardados", + "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" : "Añadir nuevo servicio", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Desactivar notificaciones y sonido", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Configuración", "sidebar.unmuteApp" : "Activar notificaciones y sonido", "signup.company.label" : "Compañía", @@ -277,9 +304,20 @@ "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.oneRequired" : "Al menos uno es requerido", "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.signupButton" : "Crear una cuenta gratuita", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Todos los servicios", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 6f9d81713..8e5ee55a0 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Recharger", "app.errorHandler.headline" : "Une erreur s'est produite", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "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.", @@ -9,7 +10,7 @@ "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.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" : "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.", @@ -43,6 +44,7 @@ "login.submit.label" : "Se connecter", "login.tokenExpired" : "Votre session a expiré, veuillez vous reconnecter.", "menu.app.about" : "À propos de Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Masquer", "menu.app.hideOthers" : "Masquer les autres", "menu.app.quit" : "Quitter", @@ -70,9 +72,9 @@ "menu.help.support" : "Support", "menu.help.tos" : "Conditions d'utilisation", "menu.services" : "Services", - "menu.services.activatePreviousService" : "Activate previous service", + "menu.services.activatePreviousService" : "Activer le service précédent", "menu.services.addNewService" : "Ajouter un nouveau service...", - "menu.services.setNextServiceActive" : "Activate next service", + "menu.services.setNextServiceActive" : "Activer le service suivant", "menu.view" : "Aperçu", "menu.view.enterFullScreen" : "Entrer en mode plein écran", "menu.view.exitFullScreen" : "Sortir du mode plein écran", @@ -87,13 +89,18 @@ "menu.window" : "Fenêtre", "menu.window.close" : "Fermer", "menu.window.minimize" : "Réduire", - "password.email.label" : "Adresse e-mail", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Tous les services", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", + "password.email.label" : "Adresse email", "password.headline" : "Réinitialiser le mot de passe", "password.link.login" : "Connectez-vous à votre compte", "password.link.signup" : "Créer un compte gratuit.", - "password.noUser" : "Aucun utilisateur n'a été trouvé avec cette adresse e-mail", + "password.noUser" : "Aucun utilisateur n'a été trouvé avec cette adresse email", "password.submit.label" : "Soumettre", - "password.successInfo" : "Merci de consulter vos e-mails", + "password.successInfo" : "Merci de consulter vos emails", "premiumFeature.button.upgradeAccount" : "Mettre à niveau mon compte", "pricing.headline" : "Soutenez Franz", "pricing.link.skipPayment" : "Je ne veux pas soutenir le développement de Franz.", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Oh non !", "service.errorHandler.message" : "Erreur", "service.errorHandler.text" : "Le chargement de {name} a échoué.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Commencer", "services.welcome" : "Bienvenue dans Franz", "settings.account.account.editButton" : "Modifier le compte", @@ -121,7 +129,7 @@ "settings.account.deleteInfo" : "Si vous n'avez plus besoin de votre compte Franz, vous pouvez le supprimer avec toutes ses données associées.", "settings.account.headline" : "Compte", "settings.account.headlineAccount" : "Informations sur le compte", - "settings.account.headlineDangerZone" : "Zone Dangereuse !", + "settings.account.headlineDangerZone" : "Zone dangereuse !", "settings.account.headlineInvoices" : "Factures", "settings.account.headlinePassword" : "Changer le mot de passe", "settings.account.headlineProfile" : "Mettre à jour le profil", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Général", "settings.app.headlineLanguage" : "Langue", "settings.app.headlineUpdates" : "Mises à jour", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Les modifications nécessitent un redémarrage", "settings.app.subheadlineCache" : "Cache", "settings.app.translationHelp" : "Aidez-nous à traduire Franz dans votre langue.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Se déconnecter", "settings.navigation.settings" : "Paramètres", "settings.navigation.yourServices" : "Vos services", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Tous les services", "settings.recipes.dev" : "Développement", "settings.recipes.headline" : "Services disponibles", @@ -203,7 +213,7 @@ "settings.service.form.indirectMessages" : "Afficher le badge des messages pour tous les nouveaux messages", "settings.service.form.isMutedInfo" : "Lorsque désactivé, tous les sons de notifications ainsi que l'audio sont coupés", "settings.service.form.name" : "Nom", - "settings.service.form.proxy.headline" : "Paramètres Proxy HTTP\/HTTPS", + "settings.service.form.proxy.headline" : "Paramètres proxy HTTP\/HTTPS", "settings.service.form.proxy.host" : "Hôte\/IP du proxy", "settings.service.form.proxy.info" : "Les paramètres de proxy ne seront pas synchronisés avec les serveurs de Franz.", "settings.service.form.proxy.isEnabled" : "Utiliser un proxy", @@ -213,7 +223,7 @@ "settings.service.form.proxy.user" : "Utilisateur (facultatif)", "settings.service.form.saveButton" : "Enregistrer le service", "settings.service.form.tabHosted" : "Hébergé", - "settings.service.form.tabOnPremise" : "Auto-hébergé ⭐️", + "settings.service.form.tabOnPremise" : "hébergé par soi-même ⭐️", "settings.service.form.team" : "Équipe", "settings.service.form.useHostedService" : "Utilisez le service hébergé {name}.", "settings.service.form.yourServices" : "Vos services", @@ -221,7 +231,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.servicesRequestFailed" : "Impossible de charger vos 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.", @@ -231,17 +241,34 @@ "settings.user.form.accountType.label" : "Type de compte", "settings.user.form.accountType.non-profit" : "Non-lucratif", "settings.user.form.currentPassword" : "Mot de passe actuel", - "settings.user.form.email" : "E-mail", + "settings.user.form.email" : "Email", "settings.user.form.firstname" : "Prénom", "settings.user.form.lastname" : "Nom", "settings.user.form.newPassword" : "Nouveau mot de passe", + "settings.workspace.add.form.name" : "Nom", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Nom", + "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" : "Réessayer", + "settings.workspaces.updatedInfo" : "Vos modifications ont été enregistrées", + "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" : "Ajouter un nouveau service", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Désactiver les notifications et les sons", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Paramètres", "sidebar.unmuteApp" : "Activer les notifications et les sons", "signup.company.label" : "Entreprise", - "signup.email.label" : "Adresse e-mail", - "signup.emailDuplicate" : "Cette adresse e-mail est déjà utilisée", + "signup.email.label" : "Adresse email", + "signup.emailDuplicate" : "Cette adresse email est déjà utilisée", "signup.firstname.label" : "Prénom", "signup.headline" : "S'inscrire", "signup.lastname.label" : "Nom", @@ -277,9 +304,20 @@ "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.oneRequired" : "Au moins un de ces champs est requis", "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.signupButton" : "Créer un compte gratuit", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Tous les services", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/ga.json b/src/i18n/locales/ga.json index eb7c04491..c58c8ee4f 100644 --- a/src/i18n/locales/ga.json +++ b/src/i18n/locales/ga.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Athlódáil", "app.errorHandler.headline" : "Something went wrong", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Get a Franz Supporter License", "feature.delayApp.headline" : "Please purchase a Franz Supporter License to skip waiting", "feature.delayApp.text" : "Franz will continue in {seconds} seconds.", @@ -9,7 +10,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" : "Ní féidir nascadh le seirbhísí Franz ar líne", "global.notConnectedToTheInternet" : "Níl tú nasctha leis an Idirlíon.", @@ -43,6 +44,7 @@ "login.submit.label" : "Logáil isteach", "login.tokenExpired" : "D'éag do sheisiún, logáil isteach arís le do thoil.", "menu.app.about" : "Faoi Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Cuir Franz i bhfolach", "menu.app.hideOthers" : "Folaigh feidhmchláir eile", "menu.app.quit" : "Scoir", @@ -87,6 +89,11 @@ "menu.window" : "Fuinneog", "menu.window.close" : "Dún", "menu.window.minimize" : "Íoslaghdaigh", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Gach seirbhís", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Seoladh ríomhphoist", "password.headline" : "Athshocraigh pasfhocal", "password.link.login" : "Logáil isteach i do chuntas", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Oró, ní hea!", "service.errorHandler.message" : "Earráid", "service.errorHandler.text" : "{name} has failed to load.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Cuir tús", "services.welcome" : "Fáilte go Franz", "settings.account.account.editButton" : "Cuir cuntas in eagar", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Ginearálta", "settings.app.headlineLanguage" : "Teanga", "settings.app.headlineUpdates" : "Nuashonruithe", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Ní gá atosú chun athruithe a chur i bhfeidhm.", "settings.app.subheadlineCache" : "Taisce", "settings.app.translationHelp" : "Cabhraigh linn Franz a aistriú i do theanga.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Logáil amach", "settings.navigation.settings" : "Socruithe", "settings.navigation.yourServices" : "Do sheirbhísí", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Gach seirbhís", "settings.recipes.dev" : "Forbairt", "settings.recipes.headline" : "Seirbhísí le fáil", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Céadainm", "settings.user.form.lastname" : "Sloinne", "settings.user.form.newPassword" : "Pasfhocal nua", + "settings.workspace.add.form.name" : "Ainm", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Ainm", + "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" : "Atriail", + "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" : "Cuir seirbhís nua leis", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Díchumasaigh fógraí ⁊ fuaim", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Socruithe", "sidebar.unmuteApp" : "Cumasaigh fógraí ⁊ fuaim", "signup.company.label" : "Comhlacht", @@ -281,5 +308,16 @@ "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.signupButton" : "Cruthaigh cuntas nua", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Gach seirbhís", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/hr.json b/src/i18n/locales/hr.json index 95920c4ce..6cae83a4c 100644 --- a/src/i18n/locales/hr.json +++ b/src/i18n/locales/hr.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Ponovno učitavanje", "app.errorHandler.headline" : "Something went wrong", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Get a Franz Supporter License", "feature.delayApp.headline" : "Please purchase a Franz Supporter License to skip waiting", "feature.delayApp.text" : "Franz will continue in {seconds} seconds.", @@ -9,7 +10,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" : "Nije se moguće povezati na Francove on-line servise. ", "global.notConnectedToTheInternet" : "Sada ste povezani s internetom. ", @@ -43,6 +44,7 @@ "login.submit.label" : "Prijavite se", "login.tokenExpired" : "Vaša sesija je istekla, prijavite se ponovo.", "menu.app.about" : "O aplikaciji", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Hide", "menu.app.hideOthers" : "Hide Others", "menu.app.quit" : "Quit", @@ -87,6 +89,11 @@ "menu.window" : "Window", "menu.window.close" : "Close", "menu.window.minimize" : "Minimize", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Sve usluge", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Vaša e-adresa", "password.headline" : "Stvorite novu zaporku", "password.link.login" : "Prijavite se na Vaš račun", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "O, ne! ", "service.errorHandler.message" : "Greška", "service.errorHandler.text" : "{name} has failed to load.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Započnimo!", "services.welcome" : "Dobrodošli u Franz", "settings.account.account.editButton" : "Uredi račun", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Općenito", "settings.app.headlineLanguage" : "Jezik", "settings.app.headlineUpdates" : "Nadogradnje", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Promjene postavki zahtijevaju ponovni zagon", "settings.app.subheadlineCache" : "Predmemorija", "settings.app.translationHelp" : "Pomozite nam prevesti aplikaciju na Vaš jezik. ", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Odjava", "settings.navigation.settings" : "Postavke", "settings.navigation.yourServices" : "Vaše usluge", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Sve usluge", "settings.recipes.dev" : "Razvoj", "settings.recipes.headline" : "Dostupne usluge", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Ime", "settings.user.form.lastname" : "Prezime", "settings.user.form.newPassword" : "Nova lozinka", + "settings.workspace.add.form.name" : "Ime", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Ime", + "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" : "Pokušajte ponovno", + "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" : "Dodajte novu uslugu", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Ugasi obavijesti i zvuk", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Postavke", "sidebar.unmuteApp" : "Omogući obavijesti i zvuk", "signup.company.label" : "Tvrtka", @@ -281,5 +308,16 @@ "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.signupButton" : "Stvorite novi korisnički račun", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Sve usluge", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/hu.json b/src/i18n/locales/hu.json index bce9a368e..52644c5bb 100644 --- a/src/i18n/locales/hu.json +++ b/src/i18n/locales/hu.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Újratöltés", "app.errorHandler.headline" : "Valami nem jött össze", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Szerezz egy Franz Támogatói Liszencet", "feature.delayApp.headline" : "Kérjük vásárolj egy Franc Támogatói Liszencet a várakozás átugrásához", "feature.delayApp.text" : "A Franz továbblép {seconds} másodperc múlva.", @@ -9,7 +10,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" : "Nem lehet csatlakozni a Franz online szolgáltatáshoz", "global.notConnectedToTheInternet" : "Nincs hálózati kapcsolat.", @@ -43,6 +44,7 @@ "login.submit.label" : "Bejelentkezés", "login.tokenExpired" : "A munkamenet lejárt, kérlek lépj be újra.", "menu.app.about" : "Névjegy", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Elrejt", "menu.app.hideOthers" : "Többi elrejtése", "menu.app.quit" : "Kilépés", @@ -87,6 +89,11 @@ "menu.window" : "Ablak", "menu.window.close" : "Bezárás", "menu.window.minimize" : "Tálcára", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Összes szolgáltatás", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Email cím", "password.headline" : "Jelszó visszaállítása", "password.link.login" : "Jelentkezz be a fiókodba", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Jajj ne!", "service.errorHandler.message" : "Hiba", "service.errorHandler.text" : "{name} nem tudott betöltődni.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Kezdj hozzá", "services.welcome" : "Üdvözöl a Franz", "settings.account.account.editButton" : "Fiók szerkesztése", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Általános", "settings.app.headlineLanguage" : "Nyelv", "settings.app.headlineUpdates" : "Frissítések", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Újraindítást igénylő módosítás", "settings.app.subheadlineCache" : "Gyorsítótár", "settings.app.translationHelp" : "Segíts nekünk a Franz-ot lefordítani a nyelvedre.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Kijelentkezés", "settings.navigation.settings" : "Beállítások", "settings.navigation.yourServices" : "Szolgáltatásaid", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Összes szolgáltatás", "settings.recipes.dev" : "Fejlesztés", "settings.recipes.headline" : "Elérhető szolgáltatások", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Keresztnév", "settings.user.form.lastname" : "Vezetéknév", "settings.user.form.newPassword" : "Új jelszó", + "settings.workspace.add.form.name" : "Név", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Név", + "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" : "Próbáld újra", + "settings.workspaces.updatedInfo" : "A módosításokat elmentettük", + "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" : "Szolgáltatás hozzáadása", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Értesítések és hangok letiltása", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Beállítások", "sidebar.unmuteApp" : "Értesítések és hangok engedélyezése", "signup.company.label" : "Cég", @@ -281,5 +308,16 @@ "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.signupButton" : "Új fiók létrehozása", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Összes szolgáltatás", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/id.json b/src/i18n/locales/id.json index 73271dceb..728d394a6 100644 --- a/src/i18n/locales/id.json +++ b/src/i18n/locales/id.json @@ -1,22 +1,23 @@ { "app.errorHandler.action" : "Muat Ulang", "app.errorHandler.headline" : "Terjadi kesalahan", - "feature.delayApp.action" : "Dapatkan Franz Supporter License", - "feature.delayApp.headline" : "Beli Franz Supporter License agar tidak perlu menunggu", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", + "feature.delayApp.action" : "Dapatkan Lisensi Pendukung Franz", + "feature.delayApp.headline" : "Beli Lisensi Pendukung Franz agar tidak perlu menunggu", "feature.delayApp.text" : "Franz akan melanjutkan dalam {seconds} detik.", - "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" : "Kirim sebagai email", + "feature.shareFranz.action.facebook" : "Bagikan di Facebook", + "feature.shareFranz.action.twitter" : "Bagikan di Twitter", + "feature.shareFranz.headline" : "Franz lebih baik bersama!", + "feature.shareFranz.shareText.email" : "Saya telah menambahkan layanan {count} ke Franz! Dapatkan aplikasi gratis untuk WhatsApp, Messenger, Slack, Skype dan co di 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 @FranzMessenger", + "feature.shareFranz.text" : "Beri tahu teman dan kolega Anda betapa hebatnya Franz dan bantu kami menyebarkan berita.", "global.api.unhealthy" : "Tidak dapat tersambung ke layanan Franz", "global.notConnectedToTheInternet" : "Anda tidak tersambung ke internet.", "global.spellchecker.useDefault" : "Gunakan Bawaan Sistem ({default})", - "global.spellchecking.autodetect" : "Detect language automatically", - "global.spellchecking.autodetect.short" : "Automatic", - "global.spellchecking.language" : "Periksa ejaan", + "global.spellchecking.autodetect" : "Deteksi bahasa secara otomatis", + "global.spellchecking.autodetect.short" : "Otomatis", + "global.spellchecking.language" : "Periksa ejaan bahasa", "import.headline" : "Impor layanan Franz 4 Anda", "import.notSupportedHeadline" : "Layanan belum didukung di Franz 5", "import.skip.label" : "Saya ingin menambahkan layanan secara manual", @@ -30,12 +31,12 @@ "invite.email.label" : "Alamat email", "invite.headline.friends" : "Undang 3 teman atau kolega Anda", "invite.name.label" : "Nama", - "invite.skip.label" : "Nanti saja", + "invite.skip.label" : "Saya ingin melakukan ini nanti", "invite.submit.label" : "Kirim undangan", "invite.successInfo" : "Undangan berhasil dikirim", "login.email.label" : "Alamat email", "login.headline" : "Masuk", - "login.invalidCredentials" : "Email atau sandi salah", + "login.invalidCredentials" : "Email atau kata sandi tidak valid", "login.link.password" : "Setel ulang sandi", "login.link.signup" : "Buat akun gratis", "login.password.label" : "Sandi", @@ -43,6 +44,7 @@ "login.submit.label" : "Masuk", "login.tokenExpired" : "Sesi Anda telah kedaluwarsa, silakan masuk kembali.", "menu.app.about" : "Tentang Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Sembunyikan", "menu.app.hideOthers" : "Sembunyikan Lainnya", "menu.app.quit" : "Keluar", @@ -70,9 +72,9 @@ "menu.help.support" : "Dukungan", "menu.help.tos" : "Ketentuan Layanan", "menu.services" : "Layanan", - "menu.services.activatePreviousService" : "Activate previous service", + "menu.services.activatePreviousService" : "Aktifkan layanan sebelumnya", "menu.services.addNewService" : "Tambahkan Layanan Baru...", - "menu.services.setNextServiceActive" : "Activate next service", + "menu.services.setNextServiceActive" : "Aktifkan layanan berikutnya", "menu.view" : "Tampilan", "menu.view.enterFullScreen" : "Masuk ke Mode Layar Penuh", "menu.view.exitFullScreen" : "Keluar dari Layar Penuh", @@ -87,6 +89,11 @@ "menu.window" : "Jendela", "menu.window.close" : "Tutup", "menu.window.minimize" : "Minimalkan", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Semua layanan", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Alamat email", "password.headline" : "Setel ulang sandi", "password.link.login" : "Masuk ke akun Anda", @@ -101,7 +108,7 @@ "pricing.support.label" : "Pilih paket dukungan Anda", "service.crashHandler.action" : "Muat Ulang {name}", "service.crashHandler.autoReload" : "Mencoba memulihkan {name} secara otomatis dalam {seconds} detik", - "service.crashHandler.headline" : "Ya Ampun!", + "service.crashHandler.headline" : "Oh tidak!", "service.crashHandler.text" : "{name} menyebabkan kesalahan.", "service.disabledHandler.action" : "Aktifkan {name}", "service.disabledHandler.headline" : "{name} dinonaktifkan", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Oh tidak!", "service.errorHandler.message" : "Kesalahan", "service.errorHandler.text" : "{name} gagal dimuat", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Ayo mulai!", "services.welcome" : "Selamat datang di Franz", "settings.account.account.editButton" : "Edit akun", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Umum", "settings.app.headlineLanguage" : "Bahasa", "settings.app.headlineUpdates" : "Versi Baru", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Perubahan membutuhkan mulai ulang", "settings.app.subheadlineCache" : "Singgahan", "settings.app.translationHelp" : "Bantu kami menerjemahkan Franz ke bahasa Anda.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Keluar", "settings.navigation.settings" : "Pengaturan", "settings.navigation.yourServices" : "Layanan Anda", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Semua layanan", "settings.recipes.dev" : "Pengembangan", "settings.recipes.headline" : "Layanan tersedia", @@ -221,7 +231,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.servicesRequestFailed" : "Tidak dapat memuat layanan Anda", "settings.services.tooltip.isDisabled" : "Layanan dinonaktifkan", "settings.services.tooltip.isMuted" : "Semua suara dibisukan", "settings.services.tooltip.notificationsDisabled" : "Pemberitahuan dinonaktifkan", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Nama Depan", "settings.user.form.lastname" : "Nama Belakang", "settings.user.form.newPassword" : "Sandi baru", + "settings.workspace.add.form.name" : "Nama", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Nama", + "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" : "Coba lagi", + "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" : "Tambahkan layanan baru", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Nonaktifkan pemberitahuan & audio", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Pengaturan", "sidebar.unmuteApp" : "Aktifkan pemberitahuan", "signup.company.label" : "Perusahaan", @@ -277,9 +304,20 @@ "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.oneRequired" : "Setidaknya diperlukan satu", "validation.required" : "{field} wajib diisi", "validation.url" : "{field} bukan URL yang benar", "welcome.loginButton" : "Masuk ke akun Anda", - "welcome.signupButton" : "Buat akun gratis" + "welcome.signupButton" : "Buat akun gratis", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Semua layanan", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 71150483c..7a1b29f15 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -1,21 +1,22 @@ { "app.errorHandler.action" : "Ricarica", "app.errorHandler.headline" : "Qualcosa è andato storto", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Ricevi una Licenza Supporter di Franz", "feature.delayApp.headline" : "Per favore, compra una Licenza Supporter di Franz per saltare l'attesa", "feature.delayApp.text" : "Franz continuerà a funzionare tra {seconds} secondi.", - "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" : "Manda come email", + "feature.shareFranz.action.facebook" : "Condividi su Facebook", + "feature.shareFranz.action.twitter" : "Condividi su Twitter", + "feature.shareFranz.headline" : "Franze è migliore insieme!", + "feature.shareFranz.shareText.email" : "Ho aggiunto {count} nuovi servizi a Franz! Scarica ora l'app gratuita per WhatsApp, Messenger, Slack, Skype e altri all'indirizzo 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 @FranzMessenger", + "feature.shareFranz.text" : "Condividi con i tuoi amici e colleghi quanto Franz è fantastico e aiutaci a diffondere la parola.", "global.api.unhealthy" : "Impossibile connettersi ai servizi online di Franz", "global.notConnectedToTheInternet" : "Non sei connesso a Internet.", "global.spellchecker.useDefault" : "Usa le impostazioni predefinite di sistema ({default})", - "global.spellchecking.autodetect" : "Detect language automatically", - "global.spellchecking.autodetect.short" : "Automatic", + "global.spellchecking.autodetect" : "Rileva automaticamente la lingua", + "global.spellchecking.autodetect.short" : "Automatico", "global.spellchecking.language" : "Lingua per controllo ortografico", "import.headline" : "Importa i servizi di Franz 4", "import.notSupportedHeadline" : "Servizi non ancora supportati in Franz 5", @@ -43,8 +44,9 @@ "login.submit.label" : "Accedi", "login.tokenExpired" : "La tua sessione è scaduta, per favore accedi di nuovo.", "menu.app.about" : "Info su Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Nascondi", - "menu.app.hideOthers" : "Nascondi Altri", + "menu.app.hideOthers" : "Nascondi altri", "menu.app.quit" : "Esci", "menu.app.settings" : "Settings", "menu.app.unhide" : "Mostra", @@ -52,7 +54,7 @@ "menu.edit.copy" : "Copia", "menu.edit.cut" : "Taglia", "menu.edit.delete" : "Elimina", - "menu.edit.emojiSymbols" : "Emoji e Simboli", + "menu.edit.emojiSymbols" : "Emoji e simboli", "menu.edit.paste" : "Incolla", "menu.edit.pasteAndMatchStyle" : "Incolla e Mantieni Stile", "menu.edit.redo" : "Ripeti", @@ -70,9 +72,9 @@ "menu.help.support" : "Supporto", "menu.help.tos" : "Termini di Servizio", "menu.services" : "Servizi", - "menu.services.activatePreviousService" : "Activate previous service", + "menu.services.activatePreviousService" : "Attiva servizio precedente", "menu.services.addNewService" : "Aggiungi Nuovo Servizio...", - "menu.services.setNextServiceActive" : "Activate next service", + "menu.services.setNextServiceActive" : "Attiva servizio seguente", "menu.view" : "Visualizza", "menu.view.enterFullScreen" : "Visualizza a Schermo Intero", "menu.view.exitFullScreen" : "Esci da Schermo Intero", @@ -87,6 +89,11 @@ "menu.window" : "Finestra", "menu.window.close" : "Chiudi", "menu.window.minimize" : "Minimizza", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Tutti i servizi", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Indirizzo email", "password.headline" : "Reimposta password", "password.link.login" : "Accedi al tuo account", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Oh no!", "service.errorHandler.message" : "Errore", "service.errorHandler.text" : "{name} non si è caricato correttamente.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Iniziamo", "services.welcome" : "Benvenuto su Franz", "settings.account.account.editButton" : "Modifica account", @@ -131,7 +139,7 @@ "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.tryReloadUserInfoRequest" : "Riprova", "settings.account.userInfoRequestFailed" : "Impossibile caricare le informazioni dell'utente.", "settings.app.buttonClearAllCache" : "Svuota la cache", "settings.app.buttonInstallUpdate" : "Riavvia e installa l'aggiornamento", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Generale", "settings.app.headlineLanguage" : "Lingua", "settings.app.headlineUpdates" : "Aggiornamenti", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Le modifiche richiedono un riavvio", "settings.app.subheadlineCache" : "Cache", "settings.app.translationHelp" : "Aiutaci a tradurre Franz nella tua lingua.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Esci", "settings.navigation.settings" : "Impostazioni", "settings.navigation.yourServices" : "I tuoi servizi", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Tutti i servizi", "settings.recipes.dev" : "Sviluppo", "settings.recipes.headline" : "Servizi disponibili", @@ -221,7 +231,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.servicesRequestFailed" : "Impossibile caricare il servizio", "settings.services.tooltip.isDisabled" : "Il servizio è disattivato", "settings.services.tooltip.isMuted" : "Tutti i suoni sono disattivati", "settings.services.tooltip.notificationsDisabled" : "Le notifiche sono disattivate", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Nome", "settings.user.form.lastname" : "Cognome", "settings.user.form.newPassword" : "Nuova password", + "settings.workspace.add.form.name" : "Nome", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Nome", + "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" : "Le tue modifiche sono state salvate", + "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" : "Aggiungi un nuovo servizio", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Disattiva notifiche e audio", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Impostazioni", "sidebar.unmuteApp" : "Attiva notifiche e audio", "signup.company.label" : "Società", @@ -245,7 +272,7 @@ "signup.firstname.label" : "Nome", "signup.headline" : "Iscriviti", "signup.lastname.label" : "Cognome", - "signup.legal.info" : "Creando un account di Franz accetti l' ", + "signup.legal.info" : "Creando un account di Franz stai accettando il ", "signup.legal.privacy" : "Informativa sulla Privacy", "signup.legal.terms" : "Termini di Servizio", "signup.link.login" : "Hai già un account, vuoi accedere?", @@ -277,9 +304,20 @@ "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.oneRequired" : "Almeno un campo è richiesto", "validation.required" : "{field} è necessario", "validation.url" : "{field} non è un URL valido", "welcome.loginButton" : "Accedi al tuo account", - "welcome.signupButton" : "Crea un account gratuito" + "welcome.signupButton" : "Crea un account gratuito", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Tutti i servizi", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index bd1024a34..a71df0dbc 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -1,21 +1,22 @@ { "app.errorHandler.action" : "再読み込み", "app.errorHandler.headline" : "間違えている部分があります", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Franzサポーターライセンスを購入する", "feature.delayApp.headline" : "Franzをすぐに起動するには、Franz サポーターライセンスを購入してください。", "feature.delayApp.text" : "Franzはあと{seconds}秒後に起動します。", - "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" : "メールで送信", + "feature.shareFranz.action.facebook" : "Facebookでシェア", + "feature.shareFranz.action.twitter" : "Twitterでシェア", + "feature.shareFranz.headline" : "Franzはあなたとともに", + "feature.shareFranz.shareText.email" : "Franzで{count}個のサービスを使っています!あなたもGmail, Messenger, Slack, SkypeなどのサービスをFranzで一元管理しましょう! 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 @FranzMessenger", + "feature.shareFranz.text" : "あなたのお友達にFranzを教えてあげましょう。", "global.api.unhealthy" : "Franzのオンラインサービスに接続できません。", "global.notConnectedToTheInternet" : "インターネットに接続されていません。", "global.spellchecker.useDefault" : " {default}を初期設定で使用してください", - "global.spellchecking.autodetect" : "Detect language automatically", - "global.spellchecking.autodetect.short" : "Automatic", + "global.spellchecking.autodetect" : "言語を自動的に検出する", + "global.spellchecking.autodetect.short" : "自動", "global.spellchecking.language" : "スペルチェックする言語", "import.headline" : "Franz 4のサービスをインポートして下さい", "import.notSupportedHeadline" : "Franz 5ではこのサービスにまだ対応していません", @@ -43,6 +44,7 @@ "login.submit.label" : "サインイン", "login.tokenExpired" : "セッションの期限が切れました。ログインし直して下さい。", "menu.app.about" : "バージョン情報", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "隠す", "menu.app.hideOthers" : "他を隠す", "menu.app.quit" : "終了", @@ -70,9 +72,9 @@ "menu.help.support" : "サポート", "menu.help.tos" : "サービス利用規約", "menu.services" : "サービス", - "menu.services.activatePreviousService" : "Activate previous service", + "menu.services.activatePreviousService" : "前のサービスを有効にする", "menu.services.addNewService" : "サービスを追加", - "menu.services.setNextServiceActive" : "Activate next service", + "menu.services.setNextServiceActive" : "次のサービスを有効にする", "menu.view" : "表示", "menu.view.enterFullScreen" : "全画面表示", "menu.view.exitFullScreen" : "全画面表示を終了する", @@ -87,6 +89,11 @@ "menu.window" : "ウィンドウ", "menu.window.close" : "閉じる", "menu.window.minimize" : "最小化", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "すべてのサービス", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "メールアドレス", "password.headline" : "パスワードのリセット", "password.link.login" : "サインイン", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "しまった!", "service.errorHandler.message" : "エラー", "service.errorHandler.text" : "{name} はロードに失敗しました", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "はじめる", "services.welcome" : "Franzにようこそ", "settings.account.account.editButton" : "アカウントの編集", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "一般", "settings.app.headlineLanguage" : "言語", "settings.app.headlineUpdates" : "更新", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "変更には再起動が必要です", "settings.app.subheadlineCache" : "キャッシュ", "settings.app.translationHelp" : "Franzの翻訳作業にご協力をお願いします。", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "ログアウト", "settings.navigation.settings" : "設定", "settings.navigation.yourServices" : "利用中のサービス", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "すべてのサービス", "settings.recipes.dev" : "開発版", "settings.recipes.headline" : "利用可能なサービス", @@ -221,7 +231,7 @@ "settings.services.discoverServices" : "サービスを探す", "settings.services.headline" : "利用中のサービス", "settings.services.noServicesAdded" : "まだ、どのサービスも追加されていません。", - "settings.services.servicesRequestFailed" : "Could not load your services", + "settings.services.servicesRequestFailed" : "サービスを読み込むことができませんでした", "settings.services.tooltip.isDisabled" : "サービスが無効です", "settings.services.tooltip.isMuted" : "無音となっています", "settings.services.tooltip.notificationsDisabled" : "通知は無効です", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "名", "settings.user.form.lastname" : "姓", "settings.user.form.newPassword" : "新しいパスワード", + "settings.workspace.add.form.name" : "Name", + "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" : "もう一度試す", + "settings.workspaces.updatedInfo" : "変更内容が保存されました", + "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" : "サービスを追加", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "通知とオーディオを無効化", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "設定", "sidebar.unmuteApp" : "通知とオーディオを有効化", "signup.company.label" : "法人", @@ -277,9 +304,20 @@ "tabs.item.reload" : "再読み込み", "validation.email" : "{field}は正しくありません", "validation.minLength" : "{field}は少なくとも{length}文字以上でなければなりません", - "validation.oneRequired" : "At least one is required", + "validation.oneRequired" : "少なくとも1つは必要です", "validation.required" : "{field}は必須です", "validation.url" : "{field}は正しいURLではありません", "welcome.loginButton" : "アカウントにログイン", - "welcome.signupButton" : "無料アカウントを作成" + "welcome.signupButton" : "無料アカウントを作成", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "すべてのサービス", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/ka.json b/src/i18n/locales/ka.json index 4796cbe9f..097e559b3 100644 --- a/src/i18n/locales/ka.json +++ b/src/i18n/locales/ka.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "ჩატვირთვა", "app.errorHandler.headline" : "Something went wrong", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Get a Franz Supporter License", "feature.delayApp.headline" : "Please purchase a Franz Supporter License to skip waiting", "feature.delayApp.text" : "Franz will continue in {seconds} seconds.", @@ -9,7 +10,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" : "Franz-ის ონლაინ სერვისთან დაკავშირება ვერ მოხერხდა", "global.notConnectedToTheInternet" : "თქვენ არ ხართ ინტერნეტთან დაკავშირებული.", @@ -43,6 +44,7 @@ "login.submit.label" : "შესვლა", "login.tokenExpired" : "თქვენს სესიას ვადა გაუვიდა, შედით ანგარიშში ხელახლა.", "menu.app.about" : "Franz-ის შესახებ", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Hide", "menu.app.hideOthers" : "სხვების დამალვა", "menu.app.quit" : "გამოსვლა", @@ -87,6 +89,11 @@ "menu.window" : "Window", "menu.window.close" : "Close", "menu.window.minimize" : "Minimize", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "ყველა სერვისი", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "მეილი", "password.headline" : "პაროლის აღდგენა", "password.link.login" : "შედით თქვენს ანგარიშში", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Oh no!", "service.errorHandler.message" : "შეცდომა", "service.errorHandler.text" : "{name} has failed to load.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "დაწყება", "services.welcome" : "მოგესალმებით Franz-ზე", "settings.account.account.editButton" : "ანგარიშის მართვა", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "მთავარი", "settings.app.headlineLanguage" : "ენა", "settings.app.headlineUpdates" : "განახლებები", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Changes require restart", "settings.app.subheadlineCache" : "Cache", "settings.app.translationHelp" : "Help us to translate Franz into your language.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "გასვლა", "settings.navigation.settings" : "პარამეტრები", "settings.navigation.yourServices" : "თქვენი სერვისები", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "ყველა სერვისი", "settings.recipes.dev" : "განვითარება", "settings.recipes.headline" : "ხელმისაწვდომი სერვისები", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "First Name", "settings.user.form.lastname" : "Last Name", "settings.user.form.newPassword" : "ახალი პაროლი", + "settings.workspace.add.form.name" : "Name", + "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" : "სცადეთ ხელახლა", + "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", "sidebar.muteApp" : "Disable notifications & audio", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "პარამეტრები", "sidebar.unmuteApp" : "Enable notifications & audio", "signup.company.label" : "კომპანია", @@ -281,5 +308,16 @@ "validation.required" : "{field} is required", "validation.url" : "{field} is not a valid URL", "welcome.loginButton" : "შედით თქვენს ანგარიშში", - "welcome.signupButton" : "შექმენი ანგარიში, ეს უფასოა" + "welcome.signupButton" : "შექმენი ანგარიში, ეს უფასოა", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "ყველა სერვისი", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/nl-BE.json b/src/i18n/locales/nl-BE.json index 00d7ddd06..82e2b5d72 100644 --- a/src/i18n/locales/nl-BE.json +++ b/src/i18n/locales/nl-BE.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Herladen", "app.errorHandler.headline" : "Er ging iets mis", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Neem een Franz Supporter Licentie ", "feature.delayApp.headline" : "Neem een Franz Supporter Licentie om niet meer te hoeven wachten", "feature.delayApp.text" : "Franz gaat over {seconds} seconden verder.", @@ -9,7 +10,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" : "Kan geen verbinding maken met de Franz services", "global.notConnectedToTheInternet" : "Je hebt geen internet verbinding.", @@ -43,6 +44,7 @@ "login.submit.label" : "Inloggen", "login.tokenExpired" : "De sessie is verlopen, log opnieuw in alsjeblieft.", "menu.app.about" : "Over Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Verbergen", "menu.app.hideOthers" : "Andere Verbergen", "menu.app.quit" : "Afsluiten", @@ -87,6 +89,11 @@ "menu.window" : "Venster", "menu.window.close" : "Sluiten", "menu.window.minimize" : "Minimaliseren", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Alle services", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "E-mailadres", "password.headline" : "Wachtwoord resetten", "password.link.login" : "Log in op je account", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Oh nee!", "service.errorHandler.message" : "Fout", "service.errorHandler.text" : "{name} kon niet geladen worden.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Beginnen", "services.welcome" : "Welkom bij Franz", "settings.account.account.editButton" : "Account bewerken", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Algemeen", "settings.app.headlineLanguage" : "Taal", "settings.app.headlineUpdates" : "Updates", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Deze wijziging heeft een herstart nodig", "settings.app.subheadlineCache" : "Cache", "settings.app.translationHelp" : "Help ons om Franz te vertalen naar uw taal.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Uitloggen", "settings.navigation.settings" : "Instellingen", "settings.navigation.yourServices" : "Jouw services", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Alle services", "settings.recipes.dev" : "Ontwikkeling", "settings.recipes.headline" : "Beschikbare services", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Voornaam", "settings.user.form.lastname" : "Achternaam", "settings.user.form.newPassword" : "Nieuw wachtwoord", + "settings.workspace.add.form.name" : "Naam", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Naam", + "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" : "Probeer opnieuw", + "settings.workspaces.updatedInfo" : "Je wijzigingen zijn opgeslagen", + "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" : "Nieuw service toevoegen", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Berichten & geluid uitschakelen", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Instellingen", "sidebar.unmuteApp" : "Berichten & geluid inschakelen", "signup.company.label" : "Bedrijf", @@ -281,5 +308,16 @@ "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.signupButton" : "Maak een gratis account aan", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Alle services", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/nl.json b/src/i18n/locales/nl.json index 782c29a6c..64dbcff4a 100644 --- a/src/i18n/locales/nl.json +++ b/src/i18n/locales/nl.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Herladen", "app.errorHandler.headline" : "Er ging iets mis", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Sponsor Franz", "feature.delayApp.headline" : "Sponsor Franz om wachten over te slaan", "feature.delayApp.text" : "Franz gaat over {seconds} seconden verder.", @@ -9,7 +10,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" : "Kan geen verbinding maken met de Franz-services", "global.notConnectedToTheInternet" : "U bent niet verbonden met het internet.", @@ -43,6 +44,7 @@ "login.submit.label" : "Inloggen", "login.tokenExpired" : "De sessie is verlopen, log opnieuw in alsjeblieft.", "menu.app.about" : "Over Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Verbergen", "menu.app.hideOthers" : "Andere verbergen", "menu.app.quit" : "Afsluiten", @@ -87,6 +89,11 @@ "menu.window" : "Venster", "menu.window.close" : "Sluiten", "menu.window.minimize" : "Minimaliseren", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Alle services", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "E-mailadres", "password.headline" : "Wachtwoord vergeten", "password.link.login" : "Log in op je account", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Oh nee!", "service.errorHandler.message" : "Fout", "service.errorHandler.text" : "{name} kon niet geladen worden.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Begin", "services.welcome" : "Welkom bij Franz", "settings.account.account.editButton" : "Bewerk account", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Algemeen", "settings.app.headlineLanguage" : "Taal", "settings.app.headlineUpdates" : "Updates", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Deze wijziging heeft een herstart nodig", "settings.app.subheadlineCache" : "Cache", "settings.app.translationHelp" : "Help ons om Franz te vertalen naar uw taal.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Uitloggen", "settings.navigation.settings" : "Instellingen", "settings.navigation.yourServices" : "Jouw services", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Alle services", "settings.recipes.dev" : "Ontwikkeling", "settings.recipes.headline" : "Beschikbare services", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Voornaam", "settings.user.form.lastname" : "Achternaam", "settings.user.form.newPassword" : "Nieuw wachtwoord", + "settings.workspace.add.form.name" : "Naam", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Naam", + "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" : "Probeer opnieuw", + "settings.workspaces.updatedInfo" : "Je wijzigingen zijn opgeslagen", + "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" : "Voeg service toe", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Schakel berichten & geluid uit", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Instellingen", "sidebar.unmuteApp" : "Berichten & geluid inschakelen", "signup.company.label" : "Bedrijf", @@ -281,5 +308,16 @@ "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.signupButton" : "Maak een gratis account", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Alle services", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/pl.json b/src/i18n/locales/pl.json index dd70f25f7..2e446bb2b 100644 --- a/src/i18n/locales/pl.json +++ b/src/i18n/locales/pl.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Przeładuj", "app.errorHandler.headline" : "Coś poszło nie tak", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Uzyskaj licencję Franz Supporter", "feature.delayApp.headline" : "Aby nie czekać kup licencję Franz Supporter", "feature.delayApp.text" : "Franz będzie kontynuował za {seconds} sekund.", @@ -9,7 +10,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" : "Nie można połączyć się z usługami Franz online", "global.notConnectedToTheInternet" : "Nie masz połączenia z Internetem.", @@ -43,6 +44,7 @@ "login.submit.label" : "Zaloguj się", "login.tokenExpired" : "Twoja sesja wygasła, zaloguj się ponownie.", "menu.app.about" : "O Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Ukryj", "menu.app.hideOthers" : "Ukryj pozostałe", "menu.app.quit" : "Zakończ", @@ -87,6 +89,11 @@ "menu.window" : "Okno", "menu.window.close" : "Zamknij", "menu.window.minimize" : "Zminimalizuj", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Wszystkie usługi", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Adres email", "password.headline" : "Przypomnij hasło", "password.link.login" : "Zaloguj się na swoje konto", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "O nie!", "service.errorHandler.message" : "Błąd", "service.errorHandler.text" : "Nie udało się załadować {name}.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Zacznij", "services.welcome" : "Witaj w programie Franz", "settings.account.account.editButton" : "Modyfikuj konta", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Ogólne", "settings.app.headlineLanguage" : "Język", "settings.app.headlineUpdates" : "Aktualizacje", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Zmiany. wymagają ponownego uruchomienia", "settings.app.subheadlineCache" : "Pamięć podręczna", "settings.app.translationHelp" : "Pomóż nam tłumaczyć Franz na Twój język.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Wyloguj", "settings.navigation.settings" : "Ustawienia", "settings.navigation.yourServices" : "Twoje usługi", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Wszystkie usługi", "settings.recipes.dev" : "Rozwojowe", "settings.recipes.headline" : "Dostępne usługi", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Imię", "settings.user.form.lastname" : "Nazwisko", "settings.user.form.newPassword" : "Nowe hasło", + "settings.workspace.add.form.name" : "Name", + "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" : "Spróbuj ponownie", + "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" : "Dodaj kolejną usługę", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Wyłącz powiadomienia i dźwięki", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Ustawienia", "sidebar.unmuteApp" : "Włącz powiadomienia i dźwięki", "signup.company.label" : "Firma", @@ -281,5 +308,16 @@ "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.signupButton" : "Stwórz darmowe konto", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Wszystkie usługi", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/pt-BR.json b/src/i18n/locales/pt-BR.json index 490771c39..01a994ddf 100644 --- a/src/i18n/locales/pt-BR.json +++ b/src/i18n/locales/pt-BR.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Recarregar", "app.errorHandler.headline" : "Alguma coisa deu errado", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "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.", @@ -9,7 +10,7 @@ "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.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" : "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", @@ -43,6 +44,7 @@ "login.submit.label" : "Entrar", "login.tokenExpired" : "Sua sessão expirou, faça o login novamente.", "menu.app.about" : "Sobre Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Ocultar", "menu.app.hideOthers" : "Ocultar Outros", "menu.app.quit" : "Sair", @@ -70,9 +72,9 @@ "menu.help.support" : "Suporte", "menu.help.tos" : "Termos de Serviço", "menu.services" : "Serviços", - "menu.services.activatePreviousService" : "Activate previous service", + "menu.services.activatePreviousService" : "Pular para serviço anterior", "menu.services.addNewService" : "Adicionar Novo Serviço", - "menu.services.setNextServiceActive" : "Activate next service", + "menu.services.setNextServiceActive" : "Pular para próximo serviço", "menu.view" : "Visualizar ", "menu.view.enterFullScreen" : "Modo Tela Cheia", "menu.view.exitFullScreen" : "Sair da Tela Cheia", @@ -87,6 +89,11 @@ "menu.window" : "Modo Janela", "menu.window.close" : "Fechar", "menu.window.minimize" : "Minimizar", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Todos os serviços", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "E-mail", "password.headline" : "Trocar senha", "password.link.login" : "Fazer login na sua conta", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Ah, não!", "service.errorHandler.message" : "Erro", "service.errorHandler.text" : "{name} não pôde ser carregado.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Iniciar", "services.welcome" : "Bem-vindo ao Franz!", "settings.account.account.editButton" : "Editar conta", @@ -131,7 +139,7 @@ "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.tryReloadUserInfoRequest" : "Tentar novamente", "settings.account.userInfoRequestFailed" : "Não foi possível carregar as informações do usuário", "settings.app.buttonClearAllCache" : "Limpar cache", "settings.app.buttonInstallUpdate" : "Reiniciar e instalar atualização", @@ -156,8 +164,9 @@ "settings.app.headlineGeneral" : "Geral", "settings.app.headlineLanguage" : "Idioma", "settings.app.headlineUpdates" : "Atualizações", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "As atualizações exigem reiniciar o sistema", - "settings.app.subheadlineCache" : "Cachê", + "settings.app.subheadlineCache" : "Cache", "settings.app.translationHelp" : "Ajude-nos a traduzir o Franz para seu idioma.", "settings.app.updateStatusAvailable" : "Atualização disponível, baixando...", "settings.app.updateStatusSearching" : "Buscando atualizações", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Sair", "settings.navigation.settings" : "Ajustes", "settings.navigation.yourServices" : "Seus serviços", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Todos os serviços", "settings.recipes.dev" : "Desenvolvimento", "settings.recipes.headline" : "Serviços disponíveis", @@ -221,7 +231,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.servicesRequestFailed" : "Não foi possível carregar os seus serviços", "settings.services.tooltip.isDisabled" : "O serviço está desativado", "settings.services.tooltip.isMuted" : "Sem som", "settings.services.tooltip.notificationsDisabled" : "Notificações desativadas", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Nome", "settings.user.form.lastname" : "Sobrenome", "settings.user.form.newPassword" : "Nova senha", + "settings.workspace.add.form.name" : "Nome", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Nome", + "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.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" : "Adicionar novo serviço", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Desativar notificações e áudio", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Ajustes", "sidebar.unmuteApp" : "Ativar notificações e áudio", "signup.company.label" : "Empresa", @@ -277,9 +304,20 @@ "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.oneRequired" : "Necessário pelo menos um", "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.signupButton" : "Criar uma conta grátis", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Todos os serviços", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 7e23aa0ba..b88c664d1 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -1,15 +1,16 @@ { "app.errorHandler.action" : "Recarregar", "app.errorHandler.headline" : "Alguma coisa correu mal", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Faz parte do grupo de apoio do Franz", "feature.delayApp.headline" : "Por favor compre uma licença Franz Supporter para saltar a fila de espera", "feature.delayApp.text" : "Franz irá 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.action.email" : "Enviar por e-mail", + "feature.shareFranz.action.facebook" : "Compartilahr no Facebook", + "feature.shareFranz.action.twitter" : "Compartilhar no 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" : "Não foi possível estabelecer ligação aos serviços do Franz", "global.notConnectedToTheInternet" : "Não estás ligado à Internet", @@ -43,6 +44,7 @@ "login.submit.label" : "Iniciar sessão", "login.tokenExpired" : "A sua sessão expirou, inicie sessão novamente.", "menu.app.about" : "Sobre o Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Ocultar", "menu.app.hideOthers" : "Ocultar Outros", "menu.app.quit" : "Sair", @@ -87,6 +89,11 @@ "menu.window" : "Janela", "menu.window.close" : "Fechar", "menu.window.minimize" : "Minimizar", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Todos os serviços", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Endereço de e-mail", "password.headline" : "Repor a minha palavra-passe", "password.link.login" : "Iniciar sessão", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Oh não!", "service.errorHandler.message" : "Erro", "service.errorHandler.text" : "{name} falhou o carregamento", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Vamos começar", "services.welcome" : "Bem-vindo ao Franz", "settings.account.account.editButton" : "Editar conta", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Geral", "settings.app.headlineLanguage" : "Idioma", "settings.app.headlineUpdates" : "Atualizações", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Alterações requerem reinício", "settings.app.subheadlineCache" : "Cache", "settings.app.translationHelp" : "Ajude-nos a traduzir a Franz para a sua língua.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Terminar sessão", "settings.navigation.settings" : "Definições", "settings.navigation.yourServices" : "Os seus serviços", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Todos os serviços", "settings.recipes.dev" : "Desenvolvimento", "settings.recipes.headline" : "Serviços disponíveis", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Primeiro Nome", "settings.user.form.lastname" : "Último Nome", "settings.user.form.newPassword" : "Nova palavra-passe", + "settings.workspace.add.form.name" : "Nome", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Nome", + "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" : "Tentar novamente", + "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" : "Adicionar um novo serviço", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Desativar notificações e áudio", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Definições", "sidebar.unmuteApp" : "Ativar notificações e áudio", "signup.company.label" : "Empresa", @@ -281,5 +308,16 @@ "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.signupButton" : "Criar uma conta gratuita", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Todos os serviços", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index d8e02b7f3..0ddd7c1e4 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -1,20 +1,21 @@ { "app.errorHandler.action" : "Перезагрузить", "app.errorHandler.headline" : "Что-то пошло не так", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Получите лицензию Franz Supporter", "feature.delayApp.headline" : "Пожалуйста приобретите лицензию Franz Supporter чтобы отменить ожидание", "feature.delayApp.text" : "Franz продолжит работу через {seconds} секунд.", - "feature.shareFranz.action.email" : "Send as email", - "feature.shareFranz.action.facebook" : "Share on Facebook", + "feature.shareFranz.action.email" : "Отправить email", + "feature.shareFranz.action.facebook" : "Поделиться на 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.headline" : "Сделаем Franz лучше вместе!", + "feature.shareFranz.shareText.email" : "Я добавил {count} сервисов во Franz! Теперь доступны такие мессенджеры как WhatsApp, Messenger, Slack, Skype и другие. Полый список вы найдете на 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 @FranzMessenger", + "feature.shareFranz.text" : "Расскажи своим друзьям и коллегам насколько прелестен Franz и помоги нам развиться", "global.api.unhealthy" : "Невозможно подключиться к онлайн-сервисам Franz", "global.notConnectedToTheInternet" : "Вы не подключены к сети Интернет", "global.spellchecker.useDefault" : "Использовать системные параметры по умолчанию ({default})", - "global.spellchecking.autodetect" : "Detect language automatically", + "global.spellchecking.autodetect" : "Найти язык автоматически", "global.spellchecking.autodetect.short" : "Automatic", "global.spellchecking.language" : "Проверка правописания", "import.headline" : "Импортировать ваши сервисы из Franz 4", @@ -43,6 +44,7 @@ "login.submit.label" : "Вход", "login.tokenExpired" : "Сессия устарела, пожалуйста, войдите снова.", "menu.app.about" : "О Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Скрыть", "menu.app.hideOthers" : "Скрыть остальные", "menu.app.quit" : "Выйти", @@ -70,9 +72,9 @@ "menu.help.support" : "Поддержка", "menu.help.tos" : "Условия использования", "menu.services" : "Сервис", - "menu.services.activatePreviousService" : "Activate previous service", + "menu.services.activatePreviousService" : "Активировать предыдущий сервич", "menu.services.addNewService" : "Добавить новый сервис...", - "menu.services.setNextServiceActive" : "Activate next service", + "menu.services.setNextServiceActive" : "Активировать следующий сервис", "menu.view" : "Вид", "menu.view.enterFullScreen" : "На весь экран", "menu.view.exitFullScreen" : "В окне", @@ -87,6 +89,11 @@ "menu.window" : "Окно", "menu.window.close" : "Закрыть", "menu.window.minimize" : "Свернуть", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Все сервисы", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Адрес электронной почты", "password.headline" : "Сбросить пароль", "password.link.login" : "Вход", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "О, нет!", "service.errorHandler.message" : "Ошибка", "service.errorHandler.text" : "{name} не смог загрузиться.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Начать работу", "services.welcome" : "Добро пожаловать во Franz", "settings.account.account.editButton" : "Редактировать аккаунт", @@ -121,7 +129,7 @@ "settings.account.deleteInfo" : "Если вам больше не нужна ваша учетная запись в Franz, вы можете удалить аккаунт и всю связанную с ней информацию.", "settings.account.headline" : "Аккаунт", "settings.account.headlineAccount" : "Информация аккаунта", - "settings.account.headlineDangerZone" : "Опасная Зона", + "settings.account.headlineDangerZone" : "Запретная Зона", "settings.account.headlineInvoices" : "Счета", "settings.account.headlinePassword" : "Сменить пароль", "settings.account.headlineProfile" : "Обновить профиль", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Общие", "settings.app.headlineLanguage" : "Язык", "settings.app.headlineUpdates" : "Обновления", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Изменения требуют перезагрузки приложения", "settings.app.subheadlineCache" : "Кэш", "settings.app.translationHelp" : "Помогите нам перевести Franz на ваш язык.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Выход", "settings.navigation.settings" : "Настройки", "settings.navigation.yourServices" : "Ваши сервисы", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Все сервисы", "settings.recipes.dev" : "Разработка", "settings.recipes.headline" : "Доступные сервисы", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Имя", "settings.user.form.lastname" : "Фамилия", "settings.user.form.newPassword" : "Новый пароль", + "settings.workspace.add.form.name" : "Name", + "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" : "Попробовать снова", + "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" : "Добавить новый сервис", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Отключить уведомления и звук", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Настройки", "sidebar.unmuteApp" : "Включить уведомления и звук", "signup.company.label" : "Организация", @@ -281,5 +308,16 @@ "validation.required" : "{field} обязательно", "validation.url" : "{field} является недействительной ссылкой", "welcome.loginButton" : "Вход", - "welcome.signupButton" : "Создать бесплатный аккаунт" + "welcome.signupButton" : "Создать бесплатный аккаунт", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Все сервисы", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/sk.json b/src/i18n/locales/sk.json index 688490b58..f3582d986 100644 --- a/src/i18n/locales/sk.json +++ b/src/i18n/locales/sk.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Obnoviť", "app.errorHandler.headline" : "Something went wrong", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Get a Franz Supporter License", "feature.delayApp.headline" : "Please purchase a Franz Supporter License to skip waiting", "feature.delayApp.text" : "Franz will continue in {seconds} seconds.", @@ -9,7 +10,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" : "Nedá sa pripojiť k online službám Franz", "global.notConnectedToTheInternet" : "Nie ste pripojení k internetu.", @@ -43,6 +44,7 @@ "login.submit.label" : "Prihlásiť sa", "login.tokenExpired" : "Vaša relácia vypršala, prihláste sa prosím znovu.", "menu.app.about" : "O aplikácii", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Skryť", "menu.app.hideOthers" : "Skryť ostatné", "menu.app.quit" : "Ukončiť", @@ -87,6 +89,11 @@ "menu.window" : "Okno", "menu.window.close" : "Zatvoriť", "menu.window.minimize" : "Minimalizovať", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Všetky služby", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "E-mailová adresa", "password.headline" : "Obnoviť heslo", "password.link.login" : "Prihlásiť sa do vášho účtu", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Ale nie!", "service.errorHandler.message" : "Chyba", "service.errorHandler.text" : "{name} has failed to load.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Začíname", "services.welcome" : "Vítajte v aplikácii Franz", "settings.account.account.editButton" : "Upraviť účet", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Všeobecné", "settings.app.headlineLanguage" : "Jazyk", "settings.app.headlineUpdates" : "Aktualizácie", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Zmeny vyžadujú reštart", "settings.app.subheadlineCache" : "Vyrovnávacia pamäť", "settings.app.translationHelp" : "Pomôžte nám preložiť Franz do svojho jazyka.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Odhlásiť sa", "settings.navigation.settings" : "Nastavenia", "settings.navigation.yourServices" : "Vaše služby", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Všetky služby", "settings.recipes.dev" : "Vývoj", "settings.recipes.headline" : "Dostupné služby", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Krstné meno", "settings.user.form.lastname" : "Priezvisko", "settings.user.form.newPassword" : "Nové heslo", + "settings.workspace.add.form.name" : "Meno", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Meno", + "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" : "Skúsiť znova", + "settings.workspaces.updatedInfo" : "Vaše zmeny boli uložené", + "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" : "Pridať novú službu", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Vypnúť upozornenia a zvuky", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Nastavenia", "sidebar.unmuteApp" : "Povoliť oznámenia a zvuky", "signup.company.label" : "Spoločnosť", @@ -281,5 +308,16 @@ "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.signupButton" : "Vytvoriť účet zdarma", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Všetky služby", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/sr.json b/src/i18n/locales/sr.json index a3a80925d..00b1ad594 100644 --- a/src/i18n/locales/sr.json +++ b/src/i18n/locales/sr.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Ponovno učitavanje", "app.errorHandler.headline" : "Something went wrong", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Get a Franz Supporter License", "feature.delayApp.headline" : "Please purchase a Franz Supporter License to skip waiting", "feature.delayApp.text" : "Franz will continue in {seconds} seconds.", @@ -9,7 +10,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" : "Nije moguće pristupiti Franz-ovim on-line servisima. ", "global.notConnectedToTheInternet" : "Niste povezani sa serverom.", @@ -43,6 +44,7 @@ "login.submit.label" : "Prijavite se", "login.tokenExpired" : "Vaša sesija je istekla, prijavite se ponovo.", "menu.app.about" : "O Francu", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Sakrij", "menu.app.hideOthers" : "Sakrij ostale", "menu.app.quit" : "Izađi", @@ -87,6 +89,11 @@ "menu.window" : "У прозору", "menu.window.close" : "Затвори", "menu.window.minimize" : "Умањи", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Sve usluge", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Vaša e-adresa", "password.headline" : "Stvorite novu zaporku", "password.link.login" : "Prijavite se na Vaš račun", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "O, ne! ", "service.errorHandler.message" : "Greška ", "service.errorHandler.text" : "{name} has failed to load.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Započnimo! ", "services.welcome" : "Dobrodošli u Franz", "settings.account.account.editButton" : "Uredi račun", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Općenito", "settings.app.headlineLanguage" : "Jezik", "settings.app.headlineUpdates" : "Nadogradnje", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Promjene postavki zahtijevaju ponovni pogon", "settings.app.subheadlineCache" : "Кеш", "settings.app.translationHelp" : "Pomozite nam prevesti aplikaciju na Vaš jezik. ", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Odjava", "settings.navigation.settings" : "Postavke", "settings.navigation.yourServices" : "Vaše usluge", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Sve usluge", "settings.recipes.dev" : "Razvoj", "settings.recipes.headline" : "Dostupne usluge", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Ime", "settings.user.form.lastname" : "Prezime", "settings.user.form.newPassword" : "Nova lozinka", + "settings.workspace.add.form.name" : "Ime", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.name" : "Ime", + "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" : "Pokušajte ponovno", + "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" : "Dodajte novu uslugu", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Онемогући обавештења и звукове", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Postavke", "sidebar.unmuteApp" : "Искључи обавештења и звукове", "signup.company.label" : "Tvrtka", @@ -281,5 +308,16 @@ "validation.required" : "{поље} је неопходно", "validation.url" : "{field} није валидан УРЛ", "welcome.loginButton" : "Prijavite se na račun", - "welcome.signupButton" : "Stvorite novi korisnički račun" + "welcome.signupButton" : "Stvorite novi korisnički račun", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Sve usluge", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/tr.json b/src/i18n/locales/tr.json index 9f8313c2e..a122cd1cf 100644 --- a/src/i18n/locales/tr.json +++ b/src/i18n/locales/tr.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Tekrar Yükle", "app.errorHandler.headline" : "Bir terslik çıktı", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "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.", @@ -9,7 +10,7 @@ "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.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" : "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.", @@ -43,6 +44,7 @@ "login.submit.label" : "Oturum Aç", "login.tokenExpired" : "Oturum zaman aşımına uğradı, lütfen tekrar giriş yapın.", "menu.app.about" : "Franz Hakkında", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Gizle", "menu.app.hideOthers" : "Diğerlerini Gizle", "menu.app.quit" : "Çıkış", @@ -87,6 +89,11 @@ "menu.window" : "Pencere", "menu.window.close" : "Kapat", "menu.window.minimize" : "Simge Durumuna Küçült", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Tüm servisler", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "E-posta adresi", "password.headline" : "Parola sıfırla", "password.link.login" : "Hesabına giriş yap", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "Hayııırrr!", "service.errorHandler.message" : "Hata", "service.errorHandler.text" : "{name} yüklenemedi.", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Haydi başlayalım", "services.welcome" : "Franz'a Hoşgeldiniz", "settings.account.account.editButton" : "Hesabı düzenle", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Genel", "settings.app.headlineLanguage" : "Dil", "settings.app.headlineUpdates" : "Güncellemeler", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Değişiklikler yeniden başlatmayı gerektiriyor", "settings.app.subheadlineCache" : "Önbellek", "settings.app.translationHelp" : "Franz'ı senin diline tercüme etmemiz için yardım et.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Çıkış", "settings.navigation.settings" : "Ayarlar", "settings.navigation.yourServices" : "Servislerin", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Tüm servisler", "settings.recipes.dev" : "Geliştirme", "settings.recipes.headline" : "Mevcut servisler", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Ad", "settings.user.form.lastname" : "Soyad", "settings.user.form.newPassword" : "Yeni şifre", + "settings.workspace.add.form.name" : "Name", + "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" : "Tekrar deneyin", + "settings.workspaces.updatedInfo" : "Değişikliklerin kaydedildi", + "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" : "Yeni servis ekle", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Bildirimleri ve sesli uyarıları kapat", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Ayarlar", "sidebar.unmuteApp" : "Bildirimleri ve sesli uyarıları etkinleştir", "signup.company.label" : "Kurum", @@ -281,5 +308,16 @@ "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.signupButton" : "Ücretsiz hesap oluştur", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Tüm servisler", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json index 56dda09d5..a45468556 100644 --- a/src/i18n/locales/uk.json +++ b/src/i18n/locales/uk.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "Перезавантажити", "app.errorHandler.headline" : "Щось пішло не так", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "Отримати ліцензію Franz Supporter ", "feature.delayApp.headline" : "Будь ласка, придбайте ліцензію Franz Supporter аби пропустити очікування", "feature.delayApp.text" : "Franz відновить роботу за {seconds} секунд", @@ -9,7 +10,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" : "Не можливо підключитись до онлайн сервісів Franz", "global.notConnectedToTheInternet" : "Ви не підключені до Інтернету.", @@ -43,6 +44,7 @@ "login.submit.label" : "Увійти", "login.tokenExpired" : "Ваша сесія закінчилась, будь ласка, увійдіть знову.", "menu.app.about" : "Про Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "Приховати", "menu.app.hideOthers" : "Приховати інші", "menu.app.quit" : "Вийти", @@ -87,6 +89,11 @@ "menu.window" : "Вікно", "menu.window.close" : "Закрити", "menu.window.minimize" : "Згорнути", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "Всі сервіси", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "Email адреса", "password.headline" : "Скинути пароль", "password.link.login" : "Увійти до вашого акаунту", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "О, ні!", "service.errorHandler.message" : "Помилка", "service.errorHandler.text" : "{name} не завантажено", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "Почати", "services.welcome" : "Ласкаво просимо в Franz", "settings.account.account.editButton" : "Редагувати акаунт", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "Загальні", "settings.app.headlineLanguage" : "Мова", "settings.app.headlineUpdates" : "Оновлення", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "Зміни потребують перезапуску", "settings.app.subheadlineCache" : "Кеш", "settings.app.translationHelp" : "Допоможіть перекласти Franz на Вашу мову.", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "Вийти", "settings.navigation.settings" : "Налаштування", "settings.navigation.yourServices" : "Ваші сервіси", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "Всі сервіси", "settings.recipes.dev" : "Розробка", "settings.recipes.headline" : "Доступні сервіси", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "Ім`я", "settings.user.form.lastname" : "Прізвище", "settings.user.form.newPassword" : "Новий пароль", + "settings.workspace.add.form.name" : "Ім'я", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.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" : "Спробуйте ще раз", + "settings.workspaces.updatedInfo" : "Ваші зміни були збережені", + "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" : "Додати новий сервіс", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "Вимкнути сповіщення та звуки", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "Налаштування", "sidebar.unmuteApp" : "Увімкнути сповіщення та звуки", "signup.company.label" : "Компанія", @@ -281,5 +308,16 @@ "validation.required" : "{field} обов'язвоке", "validation.url" : "{field} не валідний URL", "welcome.loginButton" : "Увійдіть до свого акаунту", - "welcome.signupButton" : "Створити безплатний акаунт" + "welcome.signupButton" : "Створити безплатний акаунт", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "Всі сервіси", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json index 54245ba57..e099319da 100644 --- a/src/i18n/locales/zh-TW.json +++ b/src/i18n/locales/zh-TW.json @@ -1,6 +1,7 @@ { "app.errorHandler.action" : "重新載入", "app.errorHandler.headline" : "有些東西出錯了", + "feature.announcements.changelog.headline" : "Changes in Franz {version}", "feature.delayApp.action" : "取得 Franz 支援授權", "feature.delayApp.headline" : "請購買 Franz 支援授權以跳過等候", "feature.delayApp.text" : "Franz 會在 {seconds} 秒後繼續。", @@ -9,7 +10,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" : "無法連線至 Franz 的伺服器", "global.notConnectedToTheInternet" : "你沒有連上網路。", @@ -43,6 +44,7 @@ "login.submit.label" : "登入", "login.tokenExpired" : "您的登入已過期,請重新登入。", "menu.app.about" : "關於 Franz", + "menu.app.announcement" : "What's new?", "menu.app.hide" : "隱藏", "menu.app.hideOthers" : "隱藏其他", "menu.app.quit" : "結束", @@ -87,6 +89,11 @@ "menu.window" : "視窗", "menu.window.close" : "關閉", "menu.window.minimize" : "最小化", + "menu.workspaces" : "Workspaces", + "menu.workspaces.addNewWorkspace" : "Add New Workspace...", + "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.defaultWorkspace" : "所有服務", + "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", "password.email.label" : "電子郵件地址", "password.headline" : "重設密碼", "password.link.login" : "登入您的帳號", @@ -110,6 +117,7 @@ "service.errorHandler.headline" : "噢不!", "service.errorHandler.message" : "錯誤", "service.errorHandler.text" : "{name} 載入失敗。", + "service.webviewLoader.loading" : "Loading", "services.getStarted" : "開始", "services.welcome" : "歡迎使用 Franz", "settings.account.account.editButton" : "編輯帳號", @@ -156,6 +164,7 @@ "settings.app.headlineGeneral" : "一般", "settings.app.headlineLanguage" : "語言", "settings.app.headlineUpdates" : "更新", + "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", "settings.app.restartRequired" : "需要重啟以更變", "settings.app.subheadlineCache" : "快取", "settings.app.translationHelp" : "幫助我們將 Franz 翻譯成您的語言。", @@ -169,6 +178,7 @@ "settings.navigation.logout" : "登出", "settings.navigation.settings" : "設定", "settings.navigation.yourServices" : "您的服務", + "settings.navigation.yourWorkspaces" : "Your workspaces", "settings.recipes.all" : "所有服務", "settings.recipes.dev" : "開發", "settings.recipes.headline" : "可使用的服務", @@ -235,8 +245,25 @@ "settings.user.form.firstname" : "名", "settings.user.form.lastname" : "姓", "settings.user.form.newPassword" : "新密碼", + "settings.workspace.add.form.name" : "名稱", + "settings.workspace.add.form.submitButton" : "Create workspace", + "settings.workspace.form.buttonDelete" : "Delete workspace", + "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.form.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" : "再試一次", + "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" : "新增新的服務", + "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", "sidebar.muteApp" : "關閉通知和通知音效", + "sidebar.openWorkspaceDrawer" : "Open workspace drawer", "sidebar.settings" : "設定", "sidebar.unmuteApp" : "開啟通知和通知音效", "signup.company.label" : "公司", @@ -281,5 +308,16 @@ "validation.required" : "{field}為必填", "validation.url" : "{field}不是個有效的網址", "welcome.loginButton" : "登入您的帳戶", - "welcome.signupButton" : "建立免費帳號" + "welcome.signupButton" : "建立免費帳號", + "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.allServices" : "所有服務", + "workspaceDrawer.headline" : "Workspaces", + "workspaceDrawer.item.contextMenuEdit" : "edit", + "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.<\/p>

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.<\/p>", + "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", + "workspaces.switchingIndicator.switchingTo" : "Switching to" } -- cgit v1.2.3-70-g09d2 From 6725c1e1b3102374b691fb5d398eb4c34425795b Mon Sep 17 00:00:00 2001 From: FranzBot Date: Fri, 12 Apr 2019 18:32:23 +0000 Subject: Automatic i18n update (i18n.meetfranz.com) --- src/i18n/locales/de.json | 60 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index a96ddd03d..3b0e6acdb 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -1,7 +1,7 @@ { "app.errorHandler.action" : "Neu laden", "app.errorHandler.headline" : "Es ist ein Fehler aufgetreten", - "feature.announcements.changelog.headline" : "Changes in Franz {version}", + "feature.announcements.changelog.headline" : "Was ist neu in Franz {version}", "feature.delayApp.action" : "Hol dir Franz Premium!", "feature.delayApp.headline" : "Erspare dir das Warten mit Franz Premium!", "feature.delayApp.text" : "In {seconds} Sekunden geht's weiter!", @@ -10,7 +10,7 @@ "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" : "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.shareText.twitter" : "Ich habe {count} Services zu Franz hinzugefügt! Hol dir die kostenlose App für WhatsApp, Messenger, Slack, Skype und viele mehr auf www.meetfranz.com \/cc @FranzMessenger", "feature.shareFranz.text" : "Bitte erzähle deinen Freunden und Kolleginnen, warum du Franz toll findest.", "global.api.unhealthy" : "Verbindung zum Franz Online Service fehlgeschlagen", "global.notConnectedToTheInternet" : "Du bist nicht mit dem Internet verbunden.", @@ -44,7 +44,7 @@ "login.submit.label" : "Anmelden", "login.tokenExpired" : "Deine Sitzung ist abgelaufen, bitte melde Dich erneut an.", "menu.app.about" : "Über Franz", - "menu.app.announcement" : "What's new?", + "menu.app.announcement" : "Was ist neu?", "menu.app.hide" : "Ausblenden", "menu.app.hideOthers" : "Andere ausblenden", "menu.app.quit" : "Beenden", @@ -90,10 +90,10 @@ "menu.window.close" : "Schließen", "menu.window.minimize" : "Minimieren", "menu.workspaces" : "Workspaces", - "menu.workspaces.addNewWorkspace" : "Add New Workspace...", - "menu.workspaces.closeWorkspaceDrawer" : "Close workspace drawer", + "menu.workspaces.addNewWorkspace" : "Neuen Workspace hinzufügen", + "menu.workspaces.closeWorkspaceDrawer" : "Workspaces öffnen", "menu.workspaces.defaultWorkspace" : "Alle Dienste", - "menu.workspaces.openWorkspaceDrawer" : "Open workspace drawer", + "menu.workspaces.openWorkspaceDrawer" : "Workspaces schließen", "password.email.label" : "E-Mail-Adresse", "password.headline" : "Passwort zurücksetzen", "password.link.login" : "Mit deinem Konto anmelden", @@ -117,7 +117,7 @@ "service.errorHandler.headline" : "Oh nein!", "service.errorHandler.message" : "Fehler", "service.errorHandler.text" : "{name} konnte nicht geladen werden.", - "service.webviewLoader.loading" : "Loading", + "service.webviewLoader.loading" : "Lade", "services.getStarted" : "Los geht's!", "services.welcome" : "Willkommen bei Franz!", "settings.account.account.editButton" : "Konto bearbeiten", @@ -164,7 +164,7 @@ "settings.app.headlineGeneral" : "Allgemeines", "settings.app.headlineLanguage" : "Sprache", "settings.app.headlineUpdates" : "Updates", - "settings.app.languageDisclaimer" : "Official translations are English & German. All other languages are community based translations.", + "settings.app.languageDisclaimer" : "Offizielle Übersetzungen: Englisch & Deutsch. Alle anderen Sprachen sind Übersetzungen der Franz Community.", "settings.app.restartRequired" : "Änderungen werden erst nach einem Neustart wirksam.", "settings.app.subheadlineCache" : "Cache", "settings.app.translationHelp" : "Hilf uns, Franz in Deine Sprache zu übersetzen.", @@ -178,7 +178,7 @@ "settings.navigation.logout" : "Abmelden", "settings.navigation.settings" : "Einstellungen", "settings.navigation.yourServices" : "Deine Dienste", - "settings.navigation.yourWorkspaces" : "Your workspaces", + "settings.navigation.yourWorkspaces" : "Deine Workspaces", "settings.recipes.all" : "Alle Dienste", "settings.recipes.dev" : "Entwicklung", "settings.recipes.headline" : "Verfügbare Dienste", @@ -246,24 +246,24 @@ "settings.user.form.lastname" : "Nachname", "settings.user.form.newPassword" : "Neues Passwort", "settings.workspace.add.form.name" : "Name", - "settings.workspace.add.form.submitButton" : "Create workspace", - "settings.workspace.form.buttonDelete" : "Delete workspace", - "settings.workspace.form.buttonSave" : "Save workspace", + "settings.workspace.add.form.submitButton" : "Workspace erstellen", + "settings.workspace.form.buttonDelete" : "Workspace löschen", + "settings.workspace.form.buttonSave" : "Workspace speichern", "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.workspace.form.servicesInWorkspaceHeadline" : "Services in diesem Workspace", + "settings.workspace.form.yourWorkspaces" : "Deine Workspaces", + "settings.workspaces.deletedInfo" : "Workspace wurde gelöscht", + "settings.workspaces.headline" : "Deine Workspaces", + "settings.workspaces.noWorkspacesAdded" : "Du hast noch keine Workspaces hinzugefügt", "settings.workspaces.tryReloadWorkspaces" : "Erneut versuchen", "settings.workspaces.updatedInfo" : "Deine Änderungen wurden gespeichert", - "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", + "settings.workspaces.workspaceFeatureHeadline" : "Weniger ist mehr: Franz Workspaces", + "settings.workspaces.workspaceFeatureInfo" : "Mit Franz Workspaces hast du alles im Blick was gerade wichtig ist - und nur das. Erstelle unterschiedliche Sets von Services, und wechsle jederzeit zwischen ihnen hin und her. Du entscheidest welche Services du wann und wo brauchst, um ungestört arbeiten zu können - oder zu Hause besser abschalten.", + "settings.workspaces.workspacesRequestFailed" : "Workspaces konnte nicht geladen werden", "sidebar.addNewService" : "Neuen Dienst hinzufügen", - "sidebar.closeWorkspaceDrawer" : "Close workspace drawer", + "sidebar.closeWorkspaceDrawer" : "Workspaces schließen", "sidebar.muteApp" : "Benachrichtigungen & Audio deaktivieren", - "sidebar.openWorkspaceDrawer" : "Open workspace drawer", + "sidebar.openWorkspaceDrawer" : "Workspaces öffnen", "sidebar.settings" : "Einstellungen", "sidebar.unmuteApp" : "Benachrichtigungen & Audio aktivieren", "signup.company.label" : "Firma", @@ -309,15 +309,15 @@ "validation.url" : "{field} ist keine gültige URL", "welcome.loginButton" : "Bei Franz einloggen", "welcome.signupButton" : "Kostenloses Konto erstellen", - "workspaceDrawer.addNewWorkspaceLabel" : "Add new workspace", + "workspaceDrawer.addNewWorkspaceLabel" : "Neuen Workspace hinzufügen", "workspaceDrawer.allServices" : "Alle Dienste", "workspaceDrawer.headline" : "Workspaces", - "workspaceDrawer.item.contextMenuEdit" : "edit", - "workspaceDrawer.item.noServicesAddedYet" : "No services added yet", - "workspaceDrawer.premiumCtaButtonLabel" : "Create your first workspace", - "workspaceDrawer.proFeatureBadge" : "Premium feature", - "workspaceDrawer.reactivatePremiumAccountLabel" : "Reactivate premium account", + "workspaceDrawer.item.contextMenuEdit" : "Bearbeiten", + "workspaceDrawer.item.noServicesAddedYet" : "Noch keine Services hinzugefügt", + "workspaceDrawer.premiumCtaButtonLabel" : "Erstelle deinen ersten Workspace", + "workspaceDrawer.proFeatureBadge" : "Premium Feature", + "workspaceDrawer.reactivatePremiumAccountLabel" : "Premium Account aktivieren", "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.<\/p>

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.<\/p>", - "workspaceDrawer.workspacesSettingsTooltip" : "Edit workspaces settings", - "workspaces.switchingIndicator.switchingTo" : "Switching to" + "workspaceDrawer.workspacesSettingsTooltip" : "Workspaces bearbeiten", + "workspaces.switchingIndicator.switchingTo" : "Wechsle zu" } -- cgit v1.2.3-70-g09d2 From f7b0b76e7720a1b055f381d35237218fe276faf5 Mon Sep 17 00:00:00 2001 From: Dominik Guzei Date: Fri, 12 Apr 2019 20:38:45 +0200 Subject: only show announcements for current version --- src/features/announcements/store.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/features/announcements/store.js b/src/features/announcements/store.js index 0bebf29fd..87cf08544 100644 --- a/src/features/announcements/store.js +++ b/src/features/announcements/store.js @@ -123,6 +123,11 @@ export class AnnouncementsStore extends FeatureStore { const targetVersion = this.targetVersion || this.currentVersion; if (!targetVersion) return; getChangelogRequest.execute(targetVersion); - getAnnouncementRequest.execute(targetVersion); + // We only fetch announcements for current / older versions + if (targetVersion <= this.currentVersion) { + getAnnouncementRequest.execute(targetVersion); + } else { + getAnnouncementRequest.reset(); + } } } -- cgit v1.2.3-70-g09d2 From 89988f591d342bcb101efea40371f26fc5c2c7ad Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Sat, 13 Apr 2019 12:43:59 +0200 Subject: Polish team screen --- src/components/settings/team/TeamDashboard.js | 51 +++++++++++++++++++++------ 1 file changed, 41 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js index 3eb464d49..63381c4ed 100644 --- a/src/components/settings/team/TeamDashboard.js +++ b/src/components/settings/team/TeamDashboard.js @@ -39,8 +39,36 @@ const messages = defineMessages({ const styles = { cta: { - marginTop: 40, + margin: [40, 'auto'], }, + container: { + display: 'flex', + flexDirection: 'column', + height: 'auto', + + ['@media(min-width: 800px)']: { + flexDirection: 'row', + }, + }, + content: { + height: 'auto', + order: 1, + + ['@media(min-width: 800px)']: { + order: 0, + }, + }, + image: { + display: 'block', + height: 150, + order: 0, + margin: [0, 'auto', 40, 'auto'], + + ['@media(min-width: 800px)']: { + marginLeft: 40, + order: 1, + }, + } }; @@ -100,15 +128,18 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon <>

{intl.formatMessage(messages.contentHeadline)}

-

{intl.formatMessage(messages.intro)}

-

{intl.formatMessage(messages.copy)}

- {user.isSubscriptionOwner && ( -