diff options
author | Stefan Malzner <stefan@adlk.io> | 2019-05-02 11:27:23 +0200 |
---|---|---|
committer | Stefan Malzner <stefan@adlk.io> | 2019-05-02 11:27:23 +0200 |
commit | fbff4ed90b0137088b1bb92e95f32fc1bfa7bb3e (patch) | |
tree | dfa0a6c32ce62c605bcdbf5538d9dc03725d1f88 | |
parent | Update CHANGELOG.md (diff) | |
download | ferdium-app-fbff4ed90b0137088b1bb92e95f32fc1bfa7bb3e.tar.gz ferdium-app-fbff4ed90b0137088b1bb92e95f32fc1bfa7bb3e.tar.zst ferdium-app-fbff4ed90b0137088b1bb92e95f32fc1bfa7bb3e.zip |
Add custom recipe limitation
-rw-r--r-- | packages/ui/src/badge/ProBadge.tsx | 5 | ||||
-rw-r--r-- | src/components/settings/recipes/RecipeItem.js | 2 | ||||
-rw-r--r-- | src/components/settings/recipes/RecipesDashboard.js | 194 | ||||
-rw-r--r-- | src/config.js | 1 | ||||
-rw-r--r-- | src/containers/settings/RecipesScreen.js | 40 | ||||
-rw-r--r-- | src/features/communityRecipes/index.js | 28 | ||||
-rw-r--r-- | src/features/communityRecipes/store.js | 31 | ||||
-rw-r--r-- | src/i18n/locales/defaultMessages.json | 178 | ||||
-rw-r--r-- | src/i18n/locales/en-US.json | 8 | ||||
-rw-r--r-- | src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json | 116 | ||||
-rw-r--r-- | src/stores/FeaturesStore.js | 2 | ||||
-rw-r--r-- | src/stores/index.js | 2 | ||||
-rw-r--r-- | src/styles/recipes.scss | 2 |
13 files changed, 526 insertions, 83 deletions
diff --git a/packages/ui/src/badge/ProBadge.tsx b/packages/ui/src/badge/ProBadge.tsx index 612e23210..2dad7ef49 100644 --- a/packages/ui/src/badge/ProBadge.tsx +++ b/packages/ui/src/badge/ProBadge.tsx | |||
@@ -3,13 +3,14 @@ import classnames from 'classnames'; | |||
3 | import React, { Component } from 'react'; | 3 | import React, { Component } from 'react'; |
4 | import injectStyle from 'react-jss'; | 4 | import injectStyle from 'react-jss'; |
5 | 5 | ||
6 | import { Icon, Badge } from '../'; | 6 | import { Badge, Icon } from '../'; |
7 | import { IWithStyle } from '../typings/generic'; | 7 | import { IWithStyle } from '../typings/generic'; |
8 | 8 | ||
9 | interface IProps extends IWithStyle { | 9 | interface IProps extends IWithStyle { |
10 | badgeClasses?: string; | 10 | badgeClasses?: string; |
11 | iconClasses?: string; | 11 | iconClasses?: string; |
12 | inverted?: boolean; | 12 | inverted?: boolean; |
13 | className?: string; | ||
13 | } | 14 | } |
14 | 15 | ||
15 | const styles = (theme: Theme) => ({ | 16 | const styles = (theme: Theme) => ({ |
@@ -37,6 +38,7 @@ class ProBadgeComponent extends Component<IProps> { | |||
37 | badgeClasses, | 38 | badgeClasses, |
38 | iconClasses, | 39 | iconClasses, |
39 | inverted, | 40 | inverted, |
41 | className, | ||
40 | } = this.props; | 42 | } = this.props; |
41 | 43 | ||
42 | return ( | 44 | return ( |
@@ -46,6 +48,7 @@ class ProBadgeComponent extends Component<IProps> { | |||
46 | classes.badge, | 48 | classes.badge, |
47 | inverted && classes.invertedBadge, | 49 | inverted && classes.invertedBadge, |
48 | badgeClasses, | 50 | badgeClasses, |
51 | className, | ||
49 | ])} | 52 | ])} |
50 | > | 53 | > |
51 | <Icon | 54 | <Icon |
diff --git a/src/components/settings/recipes/RecipeItem.js b/src/components/settings/recipes/RecipeItem.js index 3bb0852b2..12e3775f6 100644 --- a/src/components/settings/recipes/RecipeItem.js +++ b/src/components/settings/recipes/RecipeItem.js | |||
@@ -19,7 +19,7 @@ export default @observer class RecipeItem extends Component { | |||
19 | className="recipe-teaser" | 19 | className="recipe-teaser" |
20 | onClick={onClick} | 20 | onClick={onClick} |
21 | > | 21 | > |
22 | {recipe.local && ( | 22 | {recipe.isDevRecipe && ( |
23 | <span className="recipe-teaser__dev-badge">dev</span> | 23 | <span className="recipe-teaser__dev-badge">dev</span> |
24 | )} | 24 | )} |
25 | <img | 25 | <img |
diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js index 00cd725cf..e2e8121e5 100644 --- a/src/components/settings/recipes/RecipesDashboard.js +++ b/src/components/settings/recipes/RecipesDashboard.js | |||
@@ -4,12 +4,16 @@ import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | |||
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import { Link } from 'react-router'; | 5 | import { Link } from 'react-router'; |
6 | 6 | ||
7 | import { Button, Input } from '@meetfranz/forms'; | ||
8 | import injectSheet from 'react-jss'; | ||
9 | import { H3, H2, ProBadge } from '@meetfranz/ui'; | ||
7 | import SearchInput from '../../ui/SearchInput'; | 10 | import SearchInput from '../../ui/SearchInput'; |
8 | import Infobox from '../../ui/Infobox'; | 11 | import Infobox from '../../ui/Infobox'; |
9 | import RecipeItem from './RecipeItem'; | 12 | import RecipeItem from './RecipeItem'; |
10 | import Loader from '../../ui/Loader'; | 13 | import Loader from '../../ui/Loader'; |
11 | import Appear from '../../ui/effects/Appear'; | 14 | import Appear from '../../ui/effects/Appear'; |
12 | import { FRANZ_SERVICE_REQUEST } from '../../../config'; | 15 | import { FRANZ_SERVICE_REQUEST } from '../../../config'; |
16 | import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; | ||
13 | 17 | ||
14 | const messages = defineMessages({ | 18 | const messages = defineMessages({ |
15 | headline: { | 19 | headline: { |
@@ -28,9 +32,9 @@ const messages = defineMessages({ | |||
28 | id: 'settings.recipes.all', | 32 | id: 'settings.recipes.all', |
29 | defaultMessage: '!!!All services', | 33 | defaultMessage: '!!!All services', |
30 | }, | 34 | }, |
31 | devRecipes: { | 35 | customRecipes: { |
32 | id: 'settings.recipes.dev', | 36 | id: 'settings.recipes.custom', |
33 | defaultMessage: '!!!Development', | 37 | defaultMessage: '!!!Custom Services', |
34 | }, | 38 | }, |
35 | nothingFound: { | 39 | nothingFound: { |
36 | id: 'settings.recipes.nothingFound', | 40 | id: 'settings.recipes.nothingFound', |
@@ -44,9 +48,61 @@ const messages = defineMessages({ | |||
44 | id: 'settings.recipes.missingService', | 48 | id: 'settings.recipes.missingService', |
45 | defaultMessage: '!!!Missing a service?', | 49 | defaultMessage: '!!!Missing a service?', |
46 | }, | 50 | }, |
51 | customRecipeIntro: { | ||
52 | id: 'settings.recipes.customService.intro', | ||
53 | defaultMessage: '!!!To add a custom service, copy the recipe folder into:', | ||
54 | }, | ||
55 | openFolder: { | ||
56 | id: 'settings.recipes.customService.openFolder', | ||
57 | defaultMessage: '!!!Open directory', | ||
58 | }, | ||
59 | openDevDocs: { | ||
60 | id: 'settings.recipes.customService.openDevDocs', | ||
61 | defaultMessage: '!!!Developer Documentation', | ||
62 | }, | ||
63 | headlineCustomRecipes: { | ||
64 | id: 'settings.recipes.customService.headline.customRecipes', | ||
65 | defaultMessage: '!!!Custom Service Recipes', | ||
66 | }, | ||
67 | headlineCommunityRecipes: { | ||
68 | id: 'settings.recipes.customService.headline.communityRecipes', | ||
69 | defaultMessage: '!!!Community Services', | ||
70 | }, | ||
71 | headlineDevRecipes: { | ||
72 | id: 'settings.recipes.customService.headline.devRecipes', | ||
73 | defaultMessage: '!!!Your Development Service Recipes', | ||
74 | }, | ||
47 | }); | 75 | }); |
48 | 76 | ||
49 | export default @observer class RecipesDashboard extends Component { | 77 | const styles = { |
78 | devRecipeIntroContainer: { | ||
79 | textAlign: 'center', | ||
80 | width: '100%', | ||
81 | height: 'auto', | ||
82 | margin: [40, 0], | ||
83 | }, | ||
84 | path: { | ||
85 | marginTop: 20, | ||
86 | |||
87 | '& > div': { | ||
88 | fontFamily: 'SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace', | ||
89 | }, | ||
90 | }, | ||
91 | actionContainer: { | ||
92 | '& button': { | ||
93 | margin: [0, 10], | ||
94 | }, | ||
95 | }, | ||
96 | devRecipeList: { | ||
97 | marginTop: 20, | ||
98 | height: 'auto', | ||
99 | }, | ||
100 | proBadge: { | ||
101 | marginLeft: '10px !important', | ||
102 | }, | ||
103 | }; | ||
104 | |||
105 | export default @injectSheet(styles) @observer class RecipesDashboard extends Component { | ||
50 | static propTypes = { | 106 | static propTypes = { |
51 | recipes: MobxPropTypes.arrayOrObservableArray.isRequired, | 107 | recipes: MobxPropTypes.arrayOrObservableArray.isRequired, |
52 | isLoading: PropTypes.bool.isRequired, | 108 | isLoading: PropTypes.bool.isRequired, |
@@ -55,12 +111,19 @@ export default @observer class RecipesDashboard extends Component { | |||
55 | searchRecipes: PropTypes.func.isRequired, | 111 | searchRecipes: PropTypes.func.isRequired, |
56 | resetSearch: PropTypes.func.isRequired, | 112 | resetSearch: PropTypes.func.isRequired, |
57 | serviceStatus: MobxPropTypes.arrayOrObservableArray.isRequired, | 113 | serviceStatus: MobxPropTypes.arrayOrObservableArray.isRequired, |
58 | devRecipesCount: PropTypes.number.isRequired, | ||
59 | searchNeedle: PropTypes.string, | 114 | searchNeedle: PropTypes.string, |
115 | recipeFilter: PropTypes.string, | ||
116 | recipeDirectory: PropTypes.string.isRequired, | ||
117 | openRecipeDirectory: PropTypes.func.isRequired, | ||
118 | openDevDocs: PropTypes.func.isRequired, | ||
119 | classes: PropTypes.object.isRequired, | ||
120 | isCommunityRecipesPremiumFeature: PropTypes.bool.isRequired, | ||
121 | isUserPremiumUser: PropTypes.bool.isRequired, | ||
60 | }; | 122 | }; |
61 | 123 | ||
62 | static defaultProps = { | 124 | static defaultProps = { |
63 | searchNeedle: '', | 125 | searchNeedle: '', |
126 | recipeFilter: 'all', | ||
64 | } | 127 | } |
65 | 128 | ||
66 | static contextTypes = { | 129 | static contextTypes = { |
@@ -76,11 +139,21 @@ export default @observer class RecipesDashboard extends Component { | |||
76 | searchRecipes, | 139 | searchRecipes, |
77 | resetSearch, | 140 | resetSearch, |
78 | serviceStatus, | 141 | serviceStatus, |
79 | devRecipesCount, | ||
80 | searchNeedle, | 142 | searchNeedle, |
143 | recipeFilter, | ||
144 | recipeDirectory, | ||
145 | openRecipeDirectory, | ||
146 | openDevDocs, | ||
147 | classes, | ||
148 | isCommunityRecipesPremiumFeature, | ||
149 | isUserPremiumUser, | ||
81 | } = this.props; | 150 | } = this.props; |
82 | const { intl } = this.context; | 151 | const { intl } = this.context; |
83 | 152 | ||
153 | |||
154 | const communityRecipes = recipes.filter(r => !r.isDevRecipe); | ||
155 | const devRecipes = recipes.filter(r => r.isDevRecipe); | ||
156 | |||
84 | return ( | 157 | return ( |
85 | <div className="settings__main"> | 158 | <div className="settings__main"> |
86 | <div className="settings__header"> | 159 | <div className="settings__header"> |
@@ -122,20 +195,14 @@ export default @observer class RecipesDashboard extends Component { | |||
122 | > | 195 | > |
123 | {intl.formatMessage(messages.allRecipes)} | 196 | {intl.formatMessage(messages.allRecipes)} |
124 | </Link> | 197 | </Link> |
125 | {devRecipesCount > 0 && ( | 198 | <Link |
126 | <Link | 199 | to="/settings/recipes/dev" |
127 | to="/settings/recipes/dev" | 200 | className="badge" |
128 | className="badge" | 201 | activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`} |
129 | activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`} | 202 | onClick={() => resetSearch()} |
130 | onClick={() => resetSearch()} | 203 | > |
131 | > | 204 | {intl.formatMessage(messages.customRecipes)} |
132 | {intl.formatMessage(messages.devRecipes)} | 205 | </Link> |
133 | {' '} | ||
134 | ( | ||
135 | {devRecipesCount} | ||
136 | ) | ||
137 | </Link> | ||
138 | )} | ||
139 | <a href={FRANZ_SERVICE_REQUEST} target="_blank" className="link recipes__service-request"> | 206 | <a href={FRANZ_SERVICE_REQUEST} target="_blank" className="link recipes__service-request"> |
140 | {intl.formatMessage(messages.missingService)} | 207 | {intl.formatMessage(messages.missingService)} |
141 | {' '} | 208 | {' '} |
@@ -146,23 +213,78 @@ export default @observer class RecipesDashboard extends Component { | |||
146 | {isLoading ? ( | 213 | {isLoading ? ( |
147 | <Loader /> | 214 | <Loader /> |
148 | ) : ( | 215 | ) : ( |
149 | <div className="recipes__list"> | 216 | <> |
150 | {hasLoadedRecipes && recipes.length === 0 && ( | 217 | {recipeFilter === 'dev' && ( |
151 | <p className="align-middle settings__empty-state"> | 218 | <> |
152 | <span className="emoji"> | 219 | <H2> |
153 | <img src="./assets/images/emoji/dontknow.png" alt="" /> | 220 | {intl.formatMessage(messages.headlineCustomRecipes)} |
154 | </span> | 221 | {!isUserPremiumUser && ( |
155 | {intl.formatMessage(messages.nothingFound)} | 222 | <ProBadge className={classes.proBadge} /> |
156 | </p> | 223 | )} |
224 | </H2> | ||
225 | <div className={classes.devRecipeIntroContainer}> | ||
226 | <p> | ||
227 | {intl.formatMessage(messages.customRecipeIntro)} | ||
228 | </p> | ||
229 | <Input | ||
230 | value={recipeDirectory} | ||
231 | className={classes.path} | ||
232 | showLabel={false} | ||
233 | /> | ||
234 | <div className={classes.actionContainer}> | ||
235 | <Button | ||
236 | onClick={openRecipeDirectory} | ||
237 | buttonType="secondary" | ||
238 | label={intl.formatMessage(messages.openFolder)} | ||
239 | /> | ||
240 | <Button | ||
241 | onClick={openDevDocs} | ||
242 | buttonType="secondary" | ||
243 | label={intl.formatMessage(messages.openDevDocs)} | ||
244 | /> | ||
245 | </div> | ||
246 | </div> | ||
247 | </> | ||
248 | )} | ||
249 | <PremiumFeatureContainer | ||
250 | condition={(recipeFilter === 'dev' && communityRecipes.length > 0) && isCommunityRecipesPremiumFeature} | ||
251 | > | ||
252 | {recipeFilter === 'dev' && communityRecipes.length > 0 && ( | ||
253 | <H3>{intl.formatMessage(messages.headlineCommunityRecipes)}</H3> | ||
254 | )} | ||
255 | <div className="recipes__list"> | ||
256 | {hasLoadedRecipes && recipes.length === 0 && recipeFilter !== 'dev'( | ||
257 | <p className="align-middle settings__empty-state"> | ||
258 | <span className="emoji"> | ||
259 | <img src="./assets/images/emoji/dontknow.png" alt="" /> | ||
260 | </span> | ||
261 | {intl.formatMessage(messages.nothingFound)} | ||
262 | </p>, | ||
263 | )} | ||
264 | {communityRecipes.map(recipe => ( | ||
265 | <RecipeItem | ||
266 | key={recipe.id} | ||
267 | recipe={recipe} | ||
268 | onClick={() => showAddServiceInterface({ recipeId: recipe.id })} | ||
269 | /> | ||
270 | ))} | ||
271 | </div> | ||
272 | </PremiumFeatureContainer> | ||
273 | {recipeFilter === 'dev' && devRecipes.length > 0 && ( | ||
274 | <div className={classes.devRecipeList}> | ||
275 | <H3>{intl.formatMessage(messages.headlineDevRecipes)}</H3> | ||
276 | <div className="recipes__list"> | ||
277 | {devRecipes.map(recipe => ( | ||
278 | <RecipeItem | ||
279 | key={recipe.id} | ||
280 | recipe={recipe} | ||
281 | onClick={() => showAddServiceInterface({ recipeId: recipe.id })} | ||
282 | /> | ||
283 | ))} | ||
284 | </div> | ||
285 | </div> | ||
157 | )} | 286 | )} |
158 | {recipes.map(recipe => ( | 287 | </> |
159 | <RecipeItem | ||
160 | key={recipe.id} | ||
161 | recipe={recipe} | ||
162 | onClick={() => showAddServiceInterface({ recipeId: recipe.id })} | ||
163 | /> | ||
164 | ))} | ||
165 | </div> | ||
166 | )} | 288 | )} |
167 | </div> | 289 | </div> |
168 | </div> | 290 | </div> |
diff --git a/src/config.js b/src/config.js index 5bc318545..544f94fde 100644 --- a/src/config.js +++ b/src/config.js | |||
@@ -67,6 +67,7 @@ export const DEFAULT_WINDOW_OPTIONS = { | |||
67 | 67 | ||
68 | export const FRANZ_SERVICE_REQUEST = 'https://bit.ly/franz-plugin-docs'; | 68 | export const FRANZ_SERVICE_REQUEST = 'https://bit.ly/franz-plugin-docs'; |
69 | export const FRANZ_TRANSLATION = 'https://bit.ly/franz-translate'; | 69 | export const FRANZ_TRANSLATION = 'https://bit.ly/franz-translate'; |
70 | export const FRANZ_DEV_DOCS = 'http://bit.ly/franz-dev-hub'; | ||
70 | 71 | ||
71 | export const FILE_SYSTEM_SETTINGS_TYPES = [ | 72 | export const FILE_SYSTEM_SETTINGS_TYPES = [ |
72 | 'app', | 73 | 'app', |
diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.js index eda5ae54c..57e879f42 100644 --- a/src/containers/settings/RecipesScreen.js +++ b/src/containers/settings/RecipesScreen.js | |||
@@ -1,7 +1,9 @@ | |||
1 | import { remote, shell } from 'electron'; | ||
1 | import React, { Component } from 'react'; | 2 | import React, { Component } from 'react'; |
2 | import PropTypes from 'prop-types'; | 3 | import PropTypes from 'prop-types'; |
3 | import { autorun } from 'mobx'; | 4 | import { autorun } from 'mobx'; |
4 | import { inject, observer } from 'mobx-react'; | 5 | import { inject, observer } from 'mobx-react'; |
6 | import path from 'path'; | ||
5 | 7 | ||
6 | import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; | 8 | import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; |
7 | import RecipeStore from '../../stores/RecipesStore'; | 9 | import RecipeStore from '../../stores/RecipesStore'; |
@@ -10,6 +12,11 @@ import UserStore from '../../stores/UserStore'; | |||
10 | 12 | ||
11 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; | 13 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; |
12 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 14 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
15 | import { FRANZ_DEV_DOCS } from '../../config'; | ||
16 | import { gaEvent } from '../../lib/analytics'; | ||
17 | import { communityRecipesStore } from '../../features/communityRecipes'; | ||
18 | |||
19 | const { app } = remote; | ||
13 | 20 | ||
14 | export default @inject('stores', 'actions') @observer class RecipesScreen extends Component { | 21 | export default @inject('stores', 'actions') @observer class RecipesScreen extends Component { |
15 | static propTypes = { | 22 | static propTypes = { |
@@ -67,9 +74,16 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
67 | 74 | ||
68 | render() { | 75 | render() { |
69 | const { | 76 | const { |
70 | recipePreviews, recipes, services, user, | 77 | recipePreviews, |
78 | recipes, | ||
79 | services, | ||
80 | user, | ||
71 | } = this.props.stores; | 81 | } = this.props.stores; |
72 | const { showAddServiceInterface } = this.props.actions.service; | 82 | |
83 | const { | ||
84 | app: appActions, | ||
85 | service: serviceActions, | ||
86 | } = this.props.actions; | ||
73 | 87 | ||
74 | const { filter } = this.props.params; | 88 | const { filter } = this.props.params; |
75 | let recipeFilter; | 89 | let recipeFilter; |
@@ -77,7 +91,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
77 | if (filter === 'all') { | 91 | if (filter === 'all') { |
78 | recipeFilter = recipePreviews.all; | 92 | recipeFilter = recipePreviews.all; |
79 | } else if (filter === 'dev') { | 93 | } else if (filter === 'dev') { |
80 | recipeFilter = recipePreviews.dev; | 94 | recipeFilter = communityRecipesStore.communityRecipes; |
81 | } else { | 95 | } else { |
82 | recipeFilter = recipePreviews.featured; | 96 | recipeFilter = recipePreviews.featured; |
83 | } | 97 | } |
@@ -89,6 +103,8 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
89 | || recipes.installRecipeRequest.isExecuting | 103 | || recipes.installRecipeRequest.isExecuting |
90 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; | 104 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; |
91 | 105 | ||
106 | const recipeDirectory = path.join(app.getPath('userData'), 'recipes', 'dev'); | ||
107 | |||
92 | return ( | 108 | return ( |
93 | <ErrorBoundary> | 109 | <ErrorBoundary> |
94 | <RecipesDashboard | 110 | <RecipesDashboard |
@@ -97,12 +113,23 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
97 | addedServiceCount={services.all.length} | 113 | addedServiceCount={services.all.length} |
98 | isPremium={user.data.isPremium} | 114 | isPremium={user.data.isPremium} |
99 | hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted} | 115 | hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted} |
100 | showAddServiceInterface={showAddServiceInterface} | 116 | showAddServiceInterface={serviceActions.showAddServiceInterface} |
101 | searchRecipes={e => this.searchRecipes(e)} | 117 | searchRecipes={e => this.searchRecipes(e)} |
102 | resetSearch={() => this.resetSearch()} | 118 | resetSearch={() => this.resetSearch()} |
103 | searchNeedle={this.state.needle} | 119 | searchNeedle={this.state.needle} |
104 | serviceStatus={services.actionStatus} | 120 | serviceStatus={services.actionStatus} |
105 | devRecipesCount={recipePreviews.dev.length} | 121 | recipeFilter={filter} |
122 | recipeDirectory={recipeDirectory} | ||
123 | openRecipeDirectory={() => { | ||
124 | shell.openItem(recipeDirectory); | ||
125 | gaEvent('Recipe', 'open-recipe-folder', 'Open Folder'); | ||
126 | }} | ||
127 | openDevDocs={() => { | ||
128 | appActions.openExternalUrl({ url: FRANZ_DEV_DOCS }); | ||
129 | gaEvent('Recipe', 'open-dev-docs', 'Developer Documentation'); | ||
130 | }} | ||
131 | isCommunityRecipesPremiumFeature={communityRecipesStore.isCommunityRecipesPremiumFeature} | ||
132 | isUserPremiumUser={user.isPremium} | ||
106 | /> | 133 | /> |
107 | </ErrorBoundary> | 134 | </ErrorBoundary> |
108 | ); | 135 | ); |
@@ -117,6 +144,9 @@ RecipesScreen.wrappedComponent.propTypes = { | |||
117 | user: PropTypes.instanceOf(UserStore).isRequired, | 144 | user: PropTypes.instanceOf(UserStore).isRequired, |
118 | }).isRequired, | 145 | }).isRequired, |
119 | actions: PropTypes.shape({ | 146 | actions: PropTypes.shape({ |
147 | app: PropTypes.shape({ | ||
148 | openExternalUrl: PropTypes.func.isRequired, | ||
149 | }).isRequired, | ||
120 | service: PropTypes.shape({ | 150 | service: PropTypes.shape({ |
121 | showAddServiceInterface: PropTypes.func.isRequired, | 151 | showAddServiceInterface: PropTypes.func.isRequired, |
122 | }).isRequired, | 152 | }).isRequired, |
diff --git a/src/features/communityRecipes/index.js b/src/features/communityRecipes/index.js new file mode 100644 index 000000000..78e87855e --- /dev/null +++ b/src/features/communityRecipes/index.js | |||
@@ -0,0 +1,28 @@ | |||
1 | import { reaction } from 'mobx'; | ||
2 | import { CommunityRecipesStore } from './store'; | ||
3 | |||
4 | const debug = require('debug')('Franz:feature:communityRecipes'); | ||
5 | |||
6 | export const DEFAULT_SERVICE_LIMIT = 3; | ||
7 | |||
8 | export const communityRecipesStore = new CommunityRecipesStore(); | ||
9 | |||
10 | export default function initCommunityRecipes(stores, actions) { | ||
11 | const { features } = stores; | ||
12 | |||
13 | communityRecipesStore.start(stores, actions); | ||
14 | |||
15 | // Toggle communityRecipe premium status | ||
16 | reaction( | ||
17 | () => ( | ||
18 | features.features.isCommunityRecipesPremiumFeature | ||
19 | ), | ||
20 | (isPremiumFeature) => { | ||
21 | debug('Community recipes is premium feature: ', isPremiumFeature); | ||
22 | communityRecipesStore.isCommunityRecipesPremiumFeature = isPremiumFeature; | ||
23 | }, | ||
24 | { | ||
25 | fireImmediately: true, | ||
26 | }, | ||
27 | ); | ||
28 | } | ||
diff --git a/src/features/communityRecipes/store.js b/src/features/communityRecipes/store.js new file mode 100644 index 000000000..165b753e8 --- /dev/null +++ b/src/features/communityRecipes/store.js | |||
@@ -0,0 +1,31 @@ | |||
1 | import { computed, observable } from 'mobx'; | ||
2 | import { FeatureStore } from '../utils/FeatureStore'; | ||
3 | |||
4 | const debug = require('debug')('Franz:feature:communityRecipes:store'); | ||
5 | |||
6 | export class CommunityRecipesStore extends FeatureStore { | ||
7 | @observable isCommunityRecipesPremiumFeature = false; | ||
8 | |||
9 | start(stores, actions) { | ||
10 | debug('start'); | ||
11 | this.stores = stores; | ||
12 | this.actions = actions; | ||
13 | } | ||
14 | |||
15 | stop() { | ||
16 | debug('stop'); | ||
17 | super.stop(); | ||
18 | } | ||
19 | |||
20 | @computed get communityRecipes() { | ||
21 | if (!this.stores) return []; | ||
22 | |||
23 | return this.stores.recipePreviews.dev.map((r) => { | ||
24 | r.isDevRecipe = !!r.author.find(a => a.email === this.stores.user.data.email); | ||
25 | |||
26 | return r; | ||
27 | }); | ||
28 | } | ||
29 | } | ||
30 | |||
31 | export default CommunityRecipesStore; | ||
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 632eb38fd..9be12d369 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json | |||
@@ -1411,104 +1411,182 @@ | |||
1411 | "defaultMessage": "!!!Available Services", | 1411 | "defaultMessage": "!!!Available Services", |
1412 | "end": { | 1412 | "end": { |
1413 | "column": 3, | 1413 | "column": 3, |
1414 | "line": 18 | 1414 | "line": 22 |
1415 | }, | 1415 | }, |
1416 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1416 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1417 | "id": "settings.recipes.headline", | 1417 | "id": "settings.recipes.headline", |
1418 | "start": { | 1418 | "start": { |
1419 | "column": 12, | 1419 | "column": 12, |
1420 | "line": 15 | 1420 | "line": 19 |
1421 | } | 1421 | } |
1422 | }, | 1422 | }, |
1423 | { | 1423 | { |
1424 | "defaultMessage": "!!!Search service", | 1424 | "defaultMessage": "!!!Search service", |
1425 | "end": { | 1425 | "end": { |
1426 | "column": 3, | 1426 | "column": 3, |
1427 | "line": 22 | 1427 | "line": 26 |
1428 | }, | 1428 | }, |
1429 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1429 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1430 | "id": "settings.searchService", | 1430 | "id": "settings.searchService", |
1431 | "start": { | 1431 | "start": { |
1432 | "column": 17, | 1432 | "column": 17, |
1433 | "line": 19 | 1433 | "line": 23 |
1434 | } | 1434 | } |
1435 | }, | 1435 | }, |
1436 | { | 1436 | { |
1437 | "defaultMessage": "!!!Most popular", | 1437 | "defaultMessage": "!!!Most popular", |
1438 | "end": { | 1438 | "end": { |
1439 | "column": 3, | 1439 | "column": 3, |
1440 | "line": 26 | 1440 | "line": 30 |
1441 | }, | 1441 | }, |
1442 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1442 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1443 | "id": "settings.recipes.mostPopular", | 1443 | "id": "settings.recipes.mostPopular", |
1444 | "start": { | 1444 | "start": { |
1445 | "column": 22, | 1445 | "column": 22, |
1446 | "line": 23 | 1446 | "line": 27 |
1447 | } | 1447 | } |
1448 | }, | 1448 | }, |
1449 | { | 1449 | { |
1450 | "defaultMessage": "!!!All services", | 1450 | "defaultMessage": "!!!All services", |
1451 | "end": { | 1451 | "end": { |
1452 | "column": 3, | 1452 | "column": 3, |
1453 | "line": 30 | 1453 | "line": 34 |
1454 | }, | 1454 | }, |
1455 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1455 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1456 | "id": "settings.recipes.all", | 1456 | "id": "settings.recipes.all", |
1457 | "start": { | 1457 | "start": { |
1458 | "column": 14, | 1458 | "column": 14, |
1459 | "line": 27 | 1459 | "line": 31 |
1460 | } | 1460 | } |
1461 | }, | 1461 | }, |
1462 | { | 1462 | { |
1463 | "defaultMessage": "!!!Development", | 1463 | "defaultMessage": "!!!Custom Services", |
1464 | "end": { | 1464 | "end": { |
1465 | "column": 3, | 1465 | "column": 3, |
1466 | "line": 34 | 1466 | "line": 38 |
1467 | }, | 1467 | }, |
1468 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1468 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1469 | "id": "settings.recipes.dev", | 1469 | "id": "settings.recipes.custom", |
1470 | "start": { | 1470 | "start": { |
1471 | "column": 14, | 1471 | "column": 17, |
1472 | "line": 31 | 1472 | "line": 35 |
1473 | } | 1473 | } |
1474 | }, | 1474 | }, |
1475 | { | 1475 | { |
1476 | "defaultMessage": "!!!Sorry, but no service matched your search term.", | 1476 | "defaultMessage": "!!!Sorry, but no service matched your search term.", |
1477 | "end": { | 1477 | "end": { |
1478 | "column": 3, | 1478 | "column": 3, |
1479 | "line": 38 | 1479 | "line": 42 |
1480 | }, | 1480 | }, |
1481 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1481 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1482 | "id": "settings.recipes.nothingFound", | 1482 | "id": "settings.recipes.nothingFound", |
1483 | "start": { | 1483 | "start": { |
1484 | "column": 16, | 1484 | "column": 16, |
1485 | "line": 35 | 1485 | "line": 39 |
1486 | } | 1486 | } |
1487 | }, | 1487 | }, |
1488 | { | 1488 | { |
1489 | "defaultMessage": "!!!Service successfully added", | 1489 | "defaultMessage": "!!!Service successfully added", |
1490 | "end": { | 1490 | "end": { |
1491 | "column": 3, | 1491 | "column": 3, |
1492 | "line": 42 | 1492 | "line": 46 |
1493 | }, | 1493 | }, |
1494 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1494 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1495 | "id": "settings.recipes.servicesSuccessfulAddedInfo", | 1495 | "id": "settings.recipes.servicesSuccessfulAddedInfo", |
1496 | "start": { | 1496 | "start": { |
1497 | "column": 31, | 1497 | "column": 31, |
1498 | "line": 39 | 1498 | "line": 43 |
1499 | } | 1499 | } |
1500 | }, | 1500 | }, |
1501 | { | 1501 | { |
1502 | "defaultMessage": "!!!Missing a service?", | 1502 | "defaultMessage": "!!!Missing a service?", |
1503 | "end": { | 1503 | "end": { |
1504 | "column": 3, | 1504 | "column": 3, |
1505 | "line": 46 | 1505 | "line": 50 |
1506 | }, | 1506 | }, |
1507 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 1507 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
1508 | "id": "settings.recipes.missingService", | 1508 | "id": "settings.recipes.missingService", |
1509 | "start": { | 1509 | "start": { |
1510 | "column": 18, | 1510 | "column": 18, |
1511 | "line": 43 | 1511 | "line": 47 |
1512 | } | ||
1513 | }, | ||
1514 | { | ||
1515 | "defaultMessage": "!!!To add a custom service, copy the recipe folder into:", | ||
1516 | "end": { | ||
1517 | "column": 3, | ||
1518 | "line": 54 | ||
1519 | }, | ||
1520 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1521 | "id": "settings.recipes.customService.intro", | ||
1522 | "start": { | ||
1523 | "column": 21, | ||
1524 | "line": 51 | ||
1525 | } | ||
1526 | }, | ||
1527 | { | ||
1528 | "defaultMessage": "!!!Open directory", | ||
1529 | "end": { | ||
1530 | "column": 3, | ||
1531 | "line": 58 | ||
1532 | }, | ||
1533 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1534 | "id": "settings.recipes.customService.openFolder", | ||
1535 | "start": { | ||
1536 | "column": 14, | ||
1537 | "line": 55 | ||
1538 | } | ||
1539 | }, | ||
1540 | { | ||
1541 | "defaultMessage": "!!!Developer Documentation", | ||
1542 | "end": { | ||
1543 | "column": 3, | ||
1544 | "line": 62 | ||
1545 | }, | ||
1546 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1547 | "id": "settings.recipes.customService.openDevDocs", | ||
1548 | "start": { | ||
1549 | "column": 15, | ||
1550 | "line": 59 | ||
1551 | } | ||
1552 | }, | ||
1553 | { | ||
1554 | "defaultMessage": "!!!Custom Service Recipes", | ||
1555 | "end": { | ||
1556 | "column": 3, | ||
1557 | "line": 66 | ||
1558 | }, | ||
1559 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1560 | "id": "settings.recipes.customService.headline.customRecipes", | ||
1561 | "start": { | ||
1562 | "column": 25, | ||
1563 | "line": 63 | ||
1564 | } | ||
1565 | }, | ||
1566 | { | ||
1567 | "defaultMessage": "!!!Community Services", | ||
1568 | "end": { | ||
1569 | "column": 3, | ||
1570 | "line": 70 | ||
1571 | }, | ||
1572 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1573 | "id": "settings.recipes.customService.headline.communityRecipes", | ||
1574 | "start": { | ||
1575 | "column": 28, | ||
1576 | "line": 67 | ||
1577 | } | ||
1578 | }, | ||
1579 | { | ||
1580 | "defaultMessage": "!!!Your Development Service Recipes", | ||
1581 | "end": { | ||
1582 | "column": 3, | ||
1583 | "line": 74 | ||
1584 | }, | ||
1585 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
1586 | "id": "settings.recipes.customService.headline.devRecipes", | ||
1587 | "start": { | ||
1588 | "column": 22, | ||
1589 | "line": 71 | ||
1512 | } | 1590 | } |
1513 | } | 1591 | } |
1514 | ], | 1592 | ], |
@@ -3222,6 +3300,37 @@ | |||
3222 | { | 3300 | { |
3223 | "descriptors": [ | 3301 | "descriptors": [ |
3224 | { | 3302 | { |
3303 | "defaultMessage": "!!!You have added {amount} of {limit} services. Please upgrade your account to add more services.", | ||
3304 | "end": { | ||
3305 | "column": 3, | ||
3306 | "line": 14 | ||
3307 | }, | ||
3308 | "file": "src/features/communityRecipes/components/LimitReachedInfobox.js", | ||
3309 | "id": "feature.serviceLimit.limitReached", | ||
3310 | "start": { | ||
3311 | "column": 16, | ||
3312 | "line": 11 | ||
3313 | } | ||
3314 | }, | ||
3315 | { | ||
3316 | "defaultMessage": "!!!Upgrade account", | ||
3317 | "end": { | ||
3318 | "column": 3, | ||
3319 | "line": 18 | ||
3320 | }, | ||
3321 | "file": "src/features/communityRecipes/components/LimitReachedInfobox.js", | ||
3322 | "id": "premiumFeature.button.upgradeAccount", | ||
3323 | "start": { | ||
3324 | "column": 10, | ||
3325 | "line": 15 | ||
3326 | } | ||
3327 | } | ||
3328 | ], | ||
3329 | "path": "src/features/communityRecipes/components/LimitReachedInfobox.json" | ||
3330 | }, | ||
3331 | { | ||
3332 | "descriptors": [ | ||
3333 | { | ||
3225 | "defaultMessage": "!!!Please purchase license to skip waiting", | 3334 | "defaultMessage": "!!!Please purchase license to skip waiting", |
3226 | "end": { | 3335 | "end": { |
3227 | "column": 3, | 3336 | "column": 3, |
@@ -3362,6 +3471,37 @@ | |||
3362 | { | 3471 | { |
3363 | "descriptors": [ | 3472 | "descriptors": [ |
3364 | { | 3473 | { |
3474 | "defaultMessage": "!!!You have added {amount} of {limit} services. Please upgrade your account to add more services.", | ||
3475 | "end": { | ||
3476 | "column": 3, | ||
3477 | "line": 14 | ||
3478 | }, | ||
3479 | "file": "src/features/unofficialRecipes/components/LimitReachedInfobox.js", | ||
3480 | "id": "feature.serviceLimit.limitReached", | ||
3481 | "start": { | ||
3482 | "column": 16, | ||
3483 | "line": 11 | ||
3484 | } | ||
3485 | }, | ||
3486 | { | ||
3487 | "defaultMessage": "!!!Upgrade account", | ||
3488 | "end": { | ||
3489 | "column": 3, | ||
3490 | "line": 18 | ||
3491 | }, | ||
3492 | "file": "src/features/unofficialRecipes/components/LimitReachedInfobox.js", | ||
3493 | "id": "premiumFeature.button.upgradeAccount", | ||
3494 | "start": { | ||
3495 | "column": 10, | ||
3496 | "line": 15 | ||
3497 | } | ||
3498 | } | ||
3499 | ], | ||
3500 | "path": "src/features/unofficialRecipes/components/LimitReachedInfobox.json" | ||
3501 | }, | ||
3502 | { | ||
3503 | "descriptors": [ | ||
3504 | { | ||
3365 | "defaultMessage": "!!!Create workspace", | 3505 | "defaultMessage": "!!!Create workspace", |
3366 | "end": { | 3506 | "end": { |
3367 | "column": 3, | 3507 | "column": 3, |
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 6c2759dcc..8bffea63c 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -181,7 +181,13 @@ | |||
181 | "settings.navigation.yourServices": "Your services", | 181 | "settings.navigation.yourServices": "Your services", |
182 | "settings.navigation.yourWorkspaces": "Your workspaces", | 182 | "settings.navigation.yourWorkspaces": "Your workspaces", |
183 | "settings.recipes.all": "All services", | 183 | "settings.recipes.all": "All services", |
184 | "settings.recipes.dev": "Development", | 184 | "settings.recipes.custom": "Custom Services", |
185 | "settings.recipes.customService.headline.communityRecipes": "Community Services", | ||
186 | "settings.recipes.customService.headline.customRecipes": "Custom Service Recipes", | ||
187 | "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes", | ||
188 | "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:", | ||
189 | "settings.recipes.customService.openDevDocs": "Developer Documentation", | ||
190 | "settings.recipes.customService.openFolder": "Open folder", | ||
185 | "settings.recipes.headline": "Available services", | 191 | "settings.recipes.headline": "Available services", |
186 | "settings.recipes.missingService": "Missing a service?", | 192 | "settings.recipes.missingService": "Missing a service?", |
187 | "settings.recipes.mostPopular": "Most popular", | 193 | "settings.recipes.mostPopular": "Most popular", |
diff --git a/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json b/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json index 7d9ed3283..26dcd3da5 100644 --- a/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json +++ b/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Available Services", | 4 | "defaultMessage": "!!!Available Services", |
5 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 5 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 15, | 7 | "line": 19, |
8 | "column": 12 | 8 | "column": 12 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 18, | 11 | "line": 22, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!Search service", | 17 | "defaultMessage": "!!!Search service", |
18 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 18 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 19, | 20 | "line": 23, |
21 | "column": 17 | 21 | "column": 17 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 22, | 24 | "line": 26, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,11 +30,11 @@ | |||
30 | "defaultMessage": "!!!Most popular", | 30 | "defaultMessage": "!!!Most popular", |
31 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 31 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 23, | 33 | "line": 27, |
34 | "column": 22 | 34 | "column": 22 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 26, | 37 | "line": 30, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,24 +43,24 @@ | |||
43 | "defaultMessage": "!!!All services", | 43 | "defaultMessage": "!!!All services", |
44 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 44 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 27, | 46 | "line": 31, |
47 | "column": 14 | 47 | "column": 14 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 30, | 50 | "line": 34, |
51 | "column": 3 | 51 | "column": 3 |
52 | } | 52 | } |
53 | }, | 53 | }, |
54 | { | 54 | { |
55 | "id": "settings.recipes.dev", | 55 | "id": "settings.recipes.custom", |
56 | "defaultMessage": "!!!Development", | 56 | "defaultMessage": "!!!Custom Services", |
57 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 57 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
58 | "start": { | 58 | "start": { |
59 | "line": 31, | 59 | "line": 35, |
60 | "column": 14 | 60 | "column": 17 |
61 | }, | 61 | }, |
62 | "end": { | 62 | "end": { |
63 | "line": 34, | 63 | "line": 38, |
64 | "column": 3 | 64 | "column": 3 |
65 | } | 65 | } |
66 | }, | 66 | }, |
@@ -69,11 +69,11 @@ | |||
69 | "defaultMessage": "!!!Sorry, but no service matched your search term.", | 69 | "defaultMessage": "!!!Sorry, but no service matched your search term.", |
70 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 70 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
71 | "start": { | 71 | "start": { |
72 | "line": 35, | 72 | "line": 39, |
73 | "column": 16 | 73 | "column": 16 |
74 | }, | 74 | }, |
75 | "end": { | 75 | "end": { |
76 | "line": 38, | 76 | "line": 42, |
77 | "column": 3 | 77 | "column": 3 |
78 | } | 78 | } |
79 | }, | 79 | }, |
@@ -82,11 +82,11 @@ | |||
82 | "defaultMessage": "!!!Service successfully added", | 82 | "defaultMessage": "!!!Service successfully added", |
83 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 83 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
84 | "start": { | 84 | "start": { |
85 | "line": 39, | 85 | "line": 43, |
86 | "column": 31 | 86 | "column": 31 |
87 | }, | 87 | }, |
88 | "end": { | 88 | "end": { |
89 | "line": 42, | 89 | "line": 46, |
90 | "column": 3 | 90 | "column": 3 |
91 | } | 91 | } |
92 | }, | 92 | }, |
@@ -95,11 +95,89 @@ | |||
95 | "defaultMessage": "!!!Missing a service?", | 95 | "defaultMessage": "!!!Missing a service?", |
96 | "file": "src/components/settings/recipes/RecipesDashboard.js", | 96 | "file": "src/components/settings/recipes/RecipesDashboard.js", |
97 | "start": { | 97 | "start": { |
98 | "line": 43, | 98 | "line": 47, |
99 | "column": 18 | 99 | "column": 18 |
100 | }, | 100 | }, |
101 | "end": { | 101 | "end": { |
102 | "line": 46, | 102 | "line": 50, |
103 | "column": 3 | ||
104 | } | ||
105 | }, | ||
106 | { | ||
107 | "id": "settings.recipes.customService.intro", | ||
108 | "defaultMessage": "!!!To add a custom service, copy the recipe folder into:", | ||
109 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
110 | "start": { | ||
111 | "line": 51, | ||
112 | "column": 21 | ||
113 | }, | ||
114 | "end": { | ||
115 | "line": 54, | ||
116 | "column": 3 | ||
117 | } | ||
118 | }, | ||
119 | { | ||
120 | "id": "settings.recipes.customService.openFolder", | ||
121 | "defaultMessage": "!!!Open directory", | ||
122 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
123 | "start": { | ||
124 | "line": 55, | ||
125 | "column": 14 | ||
126 | }, | ||
127 | "end": { | ||
128 | "line": 58, | ||
129 | "column": 3 | ||
130 | } | ||
131 | }, | ||
132 | { | ||
133 | "id": "settings.recipes.customService.openDevDocs", | ||
134 | "defaultMessage": "!!!Developer Documentation", | ||
135 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
136 | "start": { | ||
137 | "line": 59, | ||
138 | "column": 15 | ||
139 | }, | ||
140 | "end": { | ||
141 | "line": 62, | ||
142 | "column": 3 | ||
143 | } | ||
144 | }, | ||
145 | { | ||
146 | "id": "settings.recipes.customService.headline.customRecipes", | ||
147 | "defaultMessage": "!!!Custom Service Recipes", | ||
148 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
149 | "start": { | ||
150 | "line": 63, | ||
151 | "column": 25 | ||
152 | }, | ||
153 | "end": { | ||
154 | "line": 66, | ||
155 | "column": 3 | ||
156 | } | ||
157 | }, | ||
158 | { | ||
159 | "id": "settings.recipes.customService.headline.communityRecipes", | ||
160 | "defaultMessage": "!!!Community Services", | ||
161 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
162 | "start": { | ||
163 | "line": 67, | ||
164 | "column": 28 | ||
165 | }, | ||
166 | "end": { | ||
167 | "line": 70, | ||
168 | "column": 3 | ||
169 | } | ||
170 | }, | ||
171 | { | ||
172 | "id": "settings.recipes.customService.headline.devRecipes", | ||
173 | "defaultMessage": "!!!Your Development Service Recipes", | ||
174 | "file": "src/components/settings/recipes/RecipesDashboard.js", | ||
175 | "start": { | ||
176 | "line": 71, | ||
177 | "column": 22 | ||
178 | }, | ||
179 | "end": { | ||
180 | "line": 74, | ||
103 | "column": 3 | 181 | "column": 3 |
104 | } | 182 | } |
105 | } | 183 | } |
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index e7832088b..0f54a50af 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -16,6 +16,7 @@ import workspaces from '../features/workspaces'; | |||
16 | import shareFranz from '../features/shareFranz'; | 16 | import shareFranz from '../features/shareFranz'; |
17 | import announcements from '../features/announcements'; | 17 | import announcements from '../features/announcements'; |
18 | import settingsWS from '../features/settingsWS'; | 18 | import settingsWS from '../features/settingsWS'; |
19 | import communityRecipes from '../features/communityRecipes'; | ||
19 | 20 | ||
20 | import { DEFAULT_FEATURES_CONFIG } from '../config'; | 21 | import { DEFAULT_FEATURES_CONFIG } from '../config'; |
21 | 22 | ||
@@ -75,5 +76,6 @@ export default class FeaturesStore extends Store { | |||
75 | shareFranz(this.stores, this.actions); | 76 | shareFranz(this.stores, this.actions); |
76 | announcements(this.stores, this.actions); | 77 | announcements(this.stores, this.actions); |
77 | settingsWS(this.stores, this.actions); | 78 | settingsWS(this.stores, this.actions); |
79 | communityRecipes(this.stores, this.actions); | ||
78 | } | 80 | } |
79 | } | 81 | } |
diff --git a/src/stores/index.js b/src/stores/index.js index 1912418a2..7f89bf1fb 100644 --- a/src/stores/index.js +++ b/src/stores/index.js | |||
@@ -12,6 +12,7 @@ import RequestStore from './RequestStore'; | |||
12 | import GlobalErrorStore from './GlobalErrorStore'; | 12 | import GlobalErrorStore from './GlobalErrorStore'; |
13 | import { workspaceStore } from '../features/workspaces'; | 13 | import { workspaceStore } from '../features/workspaces'; |
14 | import { announcementsStore } from '../features/announcements'; | 14 | import { announcementsStore } from '../features/announcements'; |
15 | import { communityRecipesStore } from '../features/communityRecipes'; | ||
15 | 16 | ||
16 | export default (api, actions, router) => { | 17 | export default (api, actions, router) => { |
17 | const stores = {}; | 18 | const stores = {}; |
@@ -31,6 +32,7 @@ export default (api, actions, router) => { | |||
31 | globalError: new GlobalErrorStore(stores, api, actions), | 32 | globalError: new GlobalErrorStore(stores, api, actions), |
32 | workspaces: workspaceStore, | 33 | workspaces: workspaceStore, |
33 | announcements: announcementsStore, | 34 | announcements: announcementsStore, |
35 | communityRecipes: communityRecipesStore, | ||
34 | }); | 36 | }); |
35 | // Initialize all stores | 37 | // Initialize all stores |
36 | Object.keys(stores).forEach((name) => { | 38 | Object.keys(stores).forEach((name) => { |
diff --git a/src/styles/recipes.scss b/src/styles/recipes.scss index 84222e1fe..56a248e98 100644 --- a/src/styles/recipes.scss +++ b/src/styles/recipes.scss | |||
@@ -12,7 +12,7 @@ | |||
12 | display: flex; | 12 | display: flex; |
13 | flex-flow: row wrap; | 13 | flex-flow: row wrap; |
14 | height: auto; | 14 | height: auto; |
15 | min-height: 70%; | 15 | // min-height: 70%; |
16 | 16 | ||
17 | &.recipes__list--disabled { | 17 | &.recipes__list--disabled { |
18 | filter: grayscale(100%); | 18 | filter: grayscale(100%); |