aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/api/server/ServerApi.ts3
-rw-r--r--src/components/settings/recipes/RecipesDashboard.js4
-rw-r--r--src/containers/auth/WelcomeScreen.js2
-rw-r--r--src/containers/settings/RecipesScreen.js15
-rw-r--r--src/i18n/locales/fa.json23
-rw-r--r--src/internal-server/app/Controllers/Http/StaticController.js195
-rw-r--r--src/internal-server/start/routes.js2
-rw-r--r--src/stores/RecipePreviewsStore.js11
8 files changed, 221 insertions, 34 deletions
diff --git a/src/api/server/ServerApi.ts b/src/api/server/ServerApi.ts
index 2fd1a8d0d..0144a1069 100644
--- a/src/api/server/ServerApi.ts
+++ b/src/api/server/ServerApi.ts
@@ -368,11 +368,12 @@ export default class ServerApi {
368 } 368 }
369 369
370 async getFeaturedRecipePreviews() { 370 async getFeaturedRecipePreviews() {
371 // TODO: If we are hitting the internal-server, we need to return an empty list, else we can hit the remote server and get the data
372 const request = await sendAuthRequest(`${apiBase()}/recipes/popular`); 371 const request = await sendAuthRequest(`${apiBase()}/recipes/popular`);
373 if (!request.ok) throw new Error(request.statusText); 372 if (!request.ok) throw new Error(request.statusText);
374 373
375 const data = await request.json(); 374 const data = await request.json();
375 // data = this._addLocalRecipesToPreviews(data);
376
376 const recipePreviews = this._mapRecipePreviewModel(data); 377 const recipePreviews = this._mapRecipePreviewModel(data);
377 debug('ServerApi::getFeaturedRecipes resolves', recipePreviews); 378 debug('ServerApi::getFeaturedRecipes resolves', recipePreviews);
378 return recipePreviews; 379 return recipePreviews;
diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js
index 2d0d83376..96207445c 100644
--- a/src/components/settings/recipes/RecipesDashboard.js
+++ b/src/components/settings/recipes/RecipesDashboard.js
@@ -114,6 +114,7 @@ class RecipesDashboard extends Component {
114 recipes: MobxPropTypes.arrayOrObservableArray.isRequired, 114 recipes: MobxPropTypes.arrayOrObservableArray.isRequired,
115 customWebsiteRecipe: PropTypes.instanceOf(RecipePreview).isRequired, 115 customWebsiteRecipe: PropTypes.instanceOf(RecipePreview).isRequired,
116 isLoading: PropTypes.bool.isRequired, 116 isLoading: PropTypes.bool.isRequired,
117 hasLoadedRecipes: PropTypes.bool.isRequired,
117 showAddServiceInterface: PropTypes.func.isRequired, 118 showAddServiceInterface: PropTypes.func.isRequired,
118 searchRecipes: PropTypes.func.isRequired, 119 searchRecipes: PropTypes.func.isRequired,
119 resetSearch: PropTypes.func.isRequired, 120 resetSearch: PropTypes.func.isRequired,
@@ -136,6 +137,7 @@ class RecipesDashboard extends Component {
136 recipes, 137 recipes,
137 customWebsiteRecipe, 138 customWebsiteRecipe,
138 isLoading, 139 isLoading,
140 hasLoadedRecipes,
139 showAddServiceInterface, 141 showAddServiceInterface,
140 searchRecipes, 142 searchRecipes,
141 resetSearch, 143 resetSearch,
@@ -255,7 +257,7 @@ class RecipesDashboard extends Component {
255 /> 257 />
256 ))} 258 ))}
257 </div> 259 </div>
258 {recipes.length === 0 && recipeFilter !== 'dev' && ( 260 {hasLoadedRecipes && recipes.length === 0 && recipeFilter !== 'dev' && (
259 <div className="align-middle settings__empty-state"> 261 <div className="align-middle settings__empty-state">
260 {customWebsiteRecipe && customWebsiteRecipe.id && ( 262 {customWebsiteRecipe && customWebsiteRecipe.id && (
261 <RecipeItem 263 <RecipeItem
diff --git a/src/containers/auth/WelcomeScreen.js b/src/containers/auth/WelcomeScreen.js
index c6de3729f..7e1a7a83e 100644
--- a/src/containers/auth/WelcomeScreen.js
+++ b/src/containers/auth/WelcomeScreen.js
@@ -15,7 +15,7 @@ class WelcomeScreen extends Component {
15 loginRoute={user.loginRoute} 15 loginRoute={user.loginRoute}
16 signupRoute={user.signupRoute} 16 signupRoute={user.signupRoute}
17 changeServerRoute={user.changeServerRoute} 17 changeServerRoute={user.changeServerRoute}
18 recipes={recipePreviews.all} 18 recipes={recipePreviews.featured}
19 /> 19 />
20 ); 20 );
21 } 21 }
diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.js
index b81336c12..e8f0a7282 100644
--- a/src/containers/settings/RecipesScreen.js
+++ b/src/containers/settings/RecipesScreen.js
@@ -54,6 +54,8 @@ class RecipesScreen extends Component {
54 54
55 if (filter === 'all' && currentFilter !== 'all') { 55 if (filter === 'all' && currentFilter !== 'all') {
56 this.setState({ currentFilter: 'all' }); 56 this.setState({ currentFilter: 'all' });
57 } else if (filter === 'featured' && currentFilter !== 'featured') {
58 this.setState({ currentFilter: 'featured' });
57 } else if (filter === 'dev' && currentFilter !== 'dev') { 59 } else if (filter === 'dev' && currentFilter !== 'dev') {
58 this.setState({ currentFilter: 'dev' }); 60 this.setState({ currentFilter: 'dev' });
59 } 61 }
@@ -113,7 +115,7 @@ class RecipesScreen extends Component {
113 115
114 const { app: appActions, service: serviceActions } = this.props.actions; 116 const { app: appActions, service: serviceActions } = this.props.actions;
115 117
116 const { filter } = { filter: 'all', ...this.props.params }; 118 const { filter } = this.props.params;
117 let recipeFilter; 119 let recipeFilter;
118 120
119 if (filter === 'all') { 121 if (filter === 'all') {
@@ -123,6 +125,8 @@ class RecipesScreen extends Component {
123 ]); 125 ]);
124 } else if (filter === 'dev') { 126 } else if (filter === 'dev') {
125 recipeFilter = communityRecipesStore.communityRecipes; 127 recipeFilter = communityRecipesStore.communityRecipes;
128 } else {
129 recipeFilter = recipePreviews.featured;
126 } 130 }
127 recipeFilter = recipeFilter.sort(this._sortByName); 131 recipeFilter = recipeFilter.sort(this._sortByName);
128 132
@@ -149,10 +153,10 @@ class RecipesScreen extends Component {
149 service => service.id === CUSTOM_WEBSITE_RECIPE_ID, 153 service => service.id === CUSTOM_WEBSITE_RECIPE_ID,
150 ); 154 );
151 155
152 const isLoading = 156 const isLoading = recipePreviews.featuredRecipePreviewsRequest.isExecuting
153 recipePreviews.allRecipePreviewsRequest.isExecuting || 157 || recipePreviews.allRecipePreviewsRequest.isExecuting
154 recipes.installRecipeRequest.isExecuting || 158 || recipes.installRecipeRequest.isExecuting
155 recipePreviews.searchRecipePreviewsRequest.isExecuting; 159 || recipePreviews.searchRecipePreviewsRequest.isExecuting;
156 160
157 const recipeDirectory = userDataRecipesPath('dev'); 161 const recipeDirectory = userDataRecipesPath('dev');
158 162
@@ -163,6 +167,7 @@ class RecipesScreen extends Component {
163 customWebsiteRecipe={customWebsiteRecipe} 167 customWebsiteRecipe={customWebsiteRecipe}
164 isLoading={isLoading} 168 isLoading={isLoading}
165 addedServiceCount={services.all.length} 169 addedServiceCount={services.all.length}
170 hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted}
166 showAddServiceInterface={serviceActions.showAddServiceInterface} 171 showAddServiceInterface={serviceActions.showAddServiceInterface}
167 searchRecipes={e => this.searchRecipes(e)} 172 searchRecipes={e => this.searchRecipes(e)}
168 resetSearch={() => this.resetSearch()} 173 resetSearch={() => this.resetSearch()}
diff --git a/src/i18n/locales/fa.json b/src/i18n/locales/fa.json
index 1e72905d7..cb0a521e0 100644
--- a/src/i18n/locales/fa.json
+++ b/src/i18n/locales/fa.json
@@ -284,9 +284,9 @@
284 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe folder inside:", 284 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe folder inside:",
285 "settings.recipes.customService.openDevDocs": "Developer Documentation", 285 "settings.recipes.customService.openDevDocs": "Developer Documentation",
286 "settings.recipes.customService.openFolder": "Open folder", 286 "settings.recipes.customService.openFolder": "Open folder",
287<<<<<<< HEAD
288 "settings.recipes.headline": "Available services", 287 "settings.recipes.headline": "Available services",
289 "settings.recipes.missingService": "Missing a service?", 288 "settings.recipes.missingService": "Missing a service?",
289 "settings.recipes.mostPopular": "Most popular",
290 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 290 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
291 "settings.recipes.servicesSuccessfulAddedInfo": "Service successfully added", 291 "settings.recipes.servicesSuccessfulAddedInfo": "Service successfully added",
292 "settings.searchService": "Search service", 292 "settings.searchService": "Search service",
@@ -305,27 +305,6 @@
305 "settings.service.form.enableAudio": "Enable audio", 305 "settings.service.form.enableAudio": "Enable audio",
306 "settings.service.form.enableBadge": "Show unread message badges", 306 "settings.service.form.enableBadge": "Show unread message badges",
307 "settings.service.form.enableDarkMode": "Enable Dark Mode", 307 "settings.service.form.enableDarkMode": "Enable Dark Mode",
308=======
309 "settings.recipes.headline": "سرویس های موجود",
310 "settings.recipes.missingService": "سرویسی را نیاز دارید ؟",
311 "settings.recipes.mostPopular": "مشهورترین ها",
312 "settings.recipes.nothingFound": "متاسفیم ، اما هیچ سرویسی با آنچه که جستجو کردید مطابقت نداشت .",
313 "settings.recipes.servicesSuccessfulAddedInfo": "سرویس با موفقیت اضافه شد",
314 "settings.searchService": "جستجوی سرویس ها",
315 "settings.service.error.goBack": "بازگشت به سرویس ها",
316 "settings.service.error.headline": "خطا ",
317 "settings.service.error.message": "دستورالعمل سرویس بارگذاری نشد.",
318 "settings.service.form.addServiceHeadline": "اضافه کردن {نام}",
319 "settings.service.form.availableServices": "سرویس های موجود",
320 "settings.service.form.customUrl": "سرور سفارشی",
321 "settings.service.form.customUrlPremiumInfo": "برای اضافه کردن سرویس هایی که خود دارید ، نیاز به پشتیبانی پیشرفته فرانز را دارید",
322 "settings.service.form.customUrlValidationError": "نتوانستیم سرور {نام} را تایید اعتبار کنیم",
323 "settings.service.form.deleteButton": "حذف سرویس",
324 "settings.service.form.editServiceHeadline": "ویرایش {name}",
325 "settings.service.form.enableAudio": "فعال‌سازی صدا",
326 "settings.service.form.enableBadge": "نماد پیام خوانده نشده را نشان بده ",
327 "settings.service.form.enableDarkMode": "فعالسازی حالت شب",
328>>>>>>> parent of 1c1b3e1f... Removed 'Most Popular' services since it alludes to user-tracking (#1718)
329 "settings.service.form.enableHibernation": "Enable hibernation", 308 "settings.service.form.enableHibernation": "Enable hibernation",
330 "settings.service.form.enableNotification": "Enable notifications", 309 "settings.service.form.enableNotification": "Enable notifications",
331 "settings.service.form.enableService": "Enable service", 310 "settings.service.form.enableService": "Enable service",
diff --git a/src/internal-server/app/Controllers/Http/StaticController.js b/src/internal-server/app/Controllers/Http/StaticController.js
new file mode 100644
index 000000000..ef5764881
--- /dev/null
+++ b/src/internal-server/app/Controllers/Http/StaticController.js
@@ -0,0 +1,195 @@
1/**
2 * Controller for routes with static responses
3 */
4
5class StaticController {
6 // Enable all features
7 features({
8 response,
9 }) {
10 return response.send({
11 isServiceProxyEnabled: true,
12 isWorkspaceEnabled: true,
13 isAnnouncementsEnabled: true,
14 isSettingsWSEnabled: false,
15 isMagicBarEnabled: true,
16 isTodosEnabled: true,
17 subscribeURL: 'https://getferdi.com',
18 hasInlineCheckout: true,
19 });
20 }
21
22 // Return an empty array
23 emptyArray({
24 response,
25 }) {
26 return response.send([]);
27 }
28
29 // Return list of popular recipes (copy of the response Franz's API is returning)
30 popularRecipes({
31 response,
32 }) {
33 return response.send([{
34 // TODO: Why is this list hardcoded?
35 author: 'Stefan Malzner <stefan@adlk.io>',
36 featured: false,
37 id: 'slack',
38 name: 'Slack',
39 version: '1.0.4',
40 icons: {
41 png: 'https://cdn.franzinfra.com/recipes/dist/slack/src/icon.png',
42 svg: 'https://cdn.franzinfra.com/recipes/dist/slack/src/icon.svg',
43 },
44 }, {
45 author: 'Stefan Malzner <stefan@adlk.io>',
46 featured: false,
47 id: 'whatsapp',
48 name: 'WhatsApp',
49 version: '1.0.1',
50 icons: {
51 png: 'https://cdn.franzinfra.com/recipes/dist/whatsapp/src/icon.png',
52 svg: 'https://cdn.franzinfra.com/recipes/dist/whatsapp/src/icon.svg',
53 },
54 }, {
55 author: 'Stefan Malzner <stefan@adlk.io>',
56 featured: false,
57 id: 'messenger',
58 name: 'Messenger',
59 version: '1.0.6',
60 icons: {
61 png: 'https://cdn.franzinfra.com/recipes/dist/messenger/src/icon.png',
62 svg: 'https://cdn.franzinfra.com/recipes/dist/messenger/src/icon.svg',
63 },
64 }, {
65 author: 'Stefan Malzner <stefan@adlk.io>',
66 featured: false,
67 id: 'telegram',
68 name: 'Telegram',
69 version: '1.0.0',
70 icons: {
71 png: 'https://cdn.franzinfra.com/recipes/dist/telegram/src/icon.png',
72 svg: 'https://cdn.franzinfra.com/recipes/dist/telegram/src/icon.svg',
73 },
74 }, {
75 author: 'Stefan Malzner <stefan@adlk.io>',
76 featured: false,
77 id: 'gmail',
78 name: 'Gmail',
79 version: '1.0.0',
80 icons: {
81 png: 'https://cdn.franzinfra.com/recipes/dist/gmail/src/icon.png',
82 svg: 'https://cdn.franzinfra.com/recipes/dist/gmail/src/icon.svg',
83 },
84 }, {
85 author: 'Stefan Malzner <stefan@adlk.io>',
86 featured: false,
87 id: 'skype',
88 name: 'Skype',
89 version: '1.0.0',
90 icons: {
91 png: 'https://cdn.franzinfra.com/recipes/dist/skype/src/icon.png',
92 svg: 'https://cdn.franzinfra.com/recipes/dist/skype/src/icon.svg',
93 },
94 }, {
95 author: 'Stefan Malzner <stefan@adlk.io>',
96 featured: false,
97 id: 'hangouts',
98 name: 'Hangouts',
99 version: '1.0.0',
100 icons: {
101 png: 'https://cdn.franzinfra.com/recipes/dist/hangouts/src/icon.png',
102 svg: 'https://cdn.franzinfra.com/recipes/dist/hangouts/src/icon.svg',
103 },
104 }, {
105 author: 'Stefan Malzner <stefan@adlk.io>',
106 featured: false,
107 id: 'discord',
108 name: 'Discord',
109 version: '1.0.0',
110 icons: {
111 png: 'https://cdn.franzinfra.com/recipes/dist/discord/src/icon.png',
112 svg: 'https://cdn.franzinfra.com/recipes/dist/discord/src/icon.svg',
113 },
114 }, {
115 author: 'Stefan Malzner <stefan@adlk.io>',
116 featured: false,
117 id: 'tweetdeck',
118 name: 'Tweetdeck',
119 version: '1.0.1',
120 icons: {
121 png: 'https://cdn.franzinfra.com/recipes/dist/tweetdeck/src/icon.png',
122 svg: 'https://cdn.franzinfra.com/recipes/dist/tweetdeck/src/icon.svg',
123 },
124 }, {
125 author: 'Stefan Malzner <stefan@adlk.io>',
126 featured: false,
127 id: 'hipchat',
128 name: 'HipChat',
129 version: '1.0.1',
130 icons: {
131 png: 'https://cdn.franzinfra.com/recipes/dist/hipchat/src/icon.png',
132 svg: 'https://cdn.franzinfra.com/recipes/dist/hipchat/src/icon.svg',
133 },
134 }, {
135 author: 'Stefan Malzner <stefan@adlk.io>',
136 featured: false,
137 id: 'rocketchat',
138 name: 'Rocket.Chat',
139 version: '1.0.1',
140 icons: {
141 png: 'https://cdn.franzinfra.com/recipes/dist/rocketchat/src/icon.png',
142 svg: 'https://cdn.franzinfra.com/recipes/dist/rocketchat/src/icon.svg',
143 },
144 }, {
145 author: 'Brian Gilbert <brian@briangilbert.net>',
146 featured: false,
147 id: 'gitter',
148 name: 'Gitter',
149 version: '1.0.0',
150 icons: {
151 png: 'https://cdn.franzinfra.com/recipes/dist/gitter/src/icon.png',
152 svg: 'https://cdn.franzinfra.com/recipes/dist/gitter/src/icon.svg',
153 },
154 }, {
155 author: 'Stefan Malzner <stefan@adlk.io>',
156 featured: false,
157 id: 'mattermost',
158 name: 'Mattermost',
159 version: '1.0.0',
160 icons: {
161 png: 'https://cdn.franzinfra.com/recipes/dist/mattermost/src/icon.png',
162 svg: 'https://cdn.franzinfra.com/recipes/dist/mattermost/src/icon.svg',
163 },
164 }, {
165 author: 'Franz <recipe@meetfranz.com>',
166 featured: false,
167 id: 'toggl',
168 name: 'Toggl',
169 version: '1.0.0',
170 icons: {
171 png: 'https://cdn.franzinfra.com/recipes/dist/toggl/src/icon.png',
172 svg: 'https://cdn.franzinfra.com/recipes/dist/toggl/src/icon.svg',
173 },
174 }, {
175 author: 'Stuart Clark <stuart@realityloop.com>',
176 featured: false,
177 id: 'twist',
178 name: 'Twist',
179 version: '1.0.0',
180 icons: {
181 png: 'https://cdn.franzinfra.com/recipes/dist/twist/src/icon.png',
182 svg: 'https://cdn.franzinfra.com/recipes/dist/twist/src/icon.svg',
183 },
184 }]);
185 }
186
187 // Show announcements
188 announcement({
189 response,
190 }) {
191 return response.send({});
192 }
193}
194
195module.exports = StaticController;
diff --git a/src/internal-server/start/routes.js b/src/internal-server/start/routes.js
index 177035dac..4a63b51f2 100644
--- a/src/internal-server/start/routes.js
+++ b/src/internal-server/start/routes.js
@@ -55,6 +55,8 @@ Route.group(() => {
55 Route.get('recipes', 'RecipeController.list'); 55 Route.get('recipes', 'RecipeController.list');
56 Route.get('recipes/download/:recipe', 'RecipeController.download'); 56 Route.get('recipes/download/:recipe', 'RecipeController.download');
57 Route.get('recipes/search', 'RecipeController.search'); 57 Route.get('recipes/search', 'RecipeController.search');
58 Route.get('recipes/popular', 'StaticController.popularRecipes');
59 Route.get('recipes/update', 'StaticController.emptyArray');
58 60
59 // Workspaces 61 // Workspaces
60 Route.put('workspace/:id', 'WorkspaceController.edit'); 62 Route.put('workspace/:id', 'WorkspaceController.edit');
diff --git a/src/stores/RecipePreviewsStore.js b/src/stores/RecipePreviewsStore.js
index e01e8fc6f..ef0bca430 100644
--- a/src/stores/RecipePreviewsStore.js
+++ b/src/stores/RecipePreviewsStore.js
@@ -10,10 +10,9 @@ export default class RecipePreviewsStore extends Store {
10 'all', 10 'all',
11 ); 11 );
12 12
13 @observable searchRecipePreviewsRequest = new Request( 13 @observable featuredRecipePreviewsRequest = new CachedRequest(this.api.recipePreviews, 'featured');
14 this.api.recipePreviews, 14
15 'search', 15 @observable searchRecipePreviewsRequest = new Request(this.api.recipePreviews, 'search');
16 );
17 16
18 constructor(...args) { 17 constructor(...args) {
19 super(...args); 18 super(...args);
@@ -26,6 +25,10 @@ export default class RecipePreviewsStore extends Store {
26 return this.allRecipePreviewsRequest.execute().result || []; 25 return this.allRecipePreviewsRequest.execute().result || [];
27 } 26 }
28 27
28 @computed get featured() {
29 return this.featuredRecipePreviewsRequest.execute().result || [];
30 }
31
29 @computed get searchResults() { 32 @computed get searchResults() {
30 return this.searchRecipePreviewsRequest.result || []; 33 return this.searchRecipePreviewsRequest.result || [];
31 } 34 }