The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
Rocket.Chat/app/apps/client/admin/apps.js

338 lines
8.5 KiB

import toastr from 'toastr';
import { ReactiveVar } from 'meteor/reactive-var';
import { FlowRouter } from 'meteor/kadira:flow-router';
import { Template } from 'meteor/templating';
import { settings } from '../../../settings';
import { t, APIClient } from '../../../utils';
import { modal } from '../../../ui-utils';
import { AppEvents } from '../communication';
import { Apps } from '../orchestrator';
const ENABLED_STATUS = ['auto_enabled', 'manually_enabled'];
const enabled = ({ status }) => ENABLED_STATUS.includes(status);
const sortByColumn = (array, column, inverted) =>
array.sort((a, b) => {
if (a.latest[column] < b.latest[column] && !inverted) {
return -1;
}
return 1;
});
const tagAlreadyInstalledApps = (installedApps, apps) => {
const installedIds = installedApps.map((app) => app.latest.id);
const tagged = apps.map((app) =>
({
price: app.price,
isPurchased: app.isPurchased,
latest: {
...app.latest,
_installed: installedIds.includes(app.latest.id),
},
})
);
return tagged;
};
const getApps = async(instance) => {
instance.isLoading.set(true);
const data = await APIClient.get('apps?marketplace=true');
const tagged = tagAlreadyInstalledApps(instance.installedApps.get(), data);
if (instance.searchType.get() === 'marketplace') {
instance.apps.set(tagged);
instance.isLoading.set(false);
instance.ready.set(true);
}
};
const getInstalledApps = async(instance) => {
const data = await APIClient.get('apps');
const apps = data.apps.map((app) => ({ latest: app }));
instance.installedApps.set(apps);
if (instance.searchType.get() === 'installed') {
instance.apps.set(apps);
instance.isLoading.set(false);
instance.ready.set(true);
}
};
Template.apps.onCreated(function() {
const instance = this;
this.ready = new ReactiveVar(false);
this.apps = new ReactiveVar([]);
this.installedApps = new ReactiveVar([]);
this.categories = new ReactiveVar([]);
this.searchText = new ReactiveVar('');
this.searchSortBy = new ReactiveVar('name');
this.sortDirection = new ReactiveVar('asc');
this.limit = new ReactiveVar(0);
this.page = new ReactiveVar(0);
this.end = new ReactiveVar(false);
this.isLoading = new ReactiveVar(true);
this.searchType = new ReactiveVar('marketplace');
const queryTab = FlowRouter.getQueryParam('tab');
if (queryTab) {
if (queryTab.toLowerCase() === 'installed') {
this.searchType.set('installed');
}
}
getInstalledApps(instance);
getApps(instance);
APIClient.get('apps?categories=true').then((data) => instance.categories.set(data));
instance.onAppAdded = function _appOnAppAdded() {
// ToDo: fix this formatting data to add an app to installedApps array without to fetch all
// fetch(`${ HOST }/v1/apps/${ appId }`).then((result) => {
// const installedApps = instance.installedApps.get();
// installedApps.push({
// latest: result.app,
// });
// instance.installedApps.set(installedApps);
// });
};
instance.onAppRemoved = function _appOnAppRemoved(appId) {
const apps = instance.apps.get();
let index = -1;
apps.find((item, i) => {
if (item.id === appId) {
index = i;
return true;
}
return false;
});
apps.splice(index, 1);
instance.apps.set(apps);
};
Apps.getWsListener().registerListener(AppEvents.APP_ADDED, instance.onAppAdded);
Apps.getWsListener().registerListener(AppEvents.APP_REMOVED, instance.onAppAdded);
});
Template.apps.onDestroyed(function() {
const instance = this;
Apps.getWsListener().unregisterListener(AppEvents.APP_ADDED, instance.onAppAdded);
Apps.getWsListener().unregisterListener(AppEvents.APP_REMOVED, instance.onAppAdded);
});
Template.apps.helpers({
isReady() {
if (Template.instance().ready != null) {
return Template.instance().ready.get();
}
return false;
},
apps() {
const instance = Template.instance();
const searchText = instance.searchText.get().toLowerCase();
const sortColumn = instance.searchSortBy.get();
const inverted = instance.sortDirection.get() === 'desc';
return sortByColumn(instance.apps.get().filter((app) => app.latest.name.toLowerCase().includes(searchText)), sortColumn, inverted);
},
categories() {
return Template.instance().categories.get();
},
appsDevelopmentMode() {
return settings.get('Apps_Framework_Development_Mode') === true;
},
parseStatus(status) {
return t(`App_status_${ status }`);
},
isActive(status) {
return enabled({ status });
},
sortIcon(key) {
const {
sortDirection,
searchSortBy,
} = Template.instance();
return key === searchSortBy.get() && sortDirection.get() !== 'asc' ? 'sort-up' : 'sort-down';
},
searchSortBy(key) {
return Template.instance().searchSortBy.get() === key;
},
isLoading() {
return Template.instance().isLoading.get();
},
onTableScroll() {
const instance = Template.instance();
if (instance.loading || instance.end.get()) {
return;
}
return function(currentTarget) {
if (currentTarget.offsetHeight + currentTarget.scrollTop >= currentTarget.scrollHeight - 100) {
return instance.page.set(instance.page.get() + 1);
}
};
},
onTableResize() {
const { limit } = Template.instance();
return function() {
limit.set(Math.ceil((this.$('.table-scroll').height() / 40) + 5));
};
},
onTableSort() {
const { end, page, sortDirection, searchSortBy } = Template.instance();
return function(type) {
end.set(false);
page.set(0);
if (searchSortBy.get() === type) {
sortDirection.set(sortDirection.get() === 'asc' ? 'desc' : 'asc');
return;
}
searchSortBy.set(type);
sortDirection.set('asc');
};
},
searchType() {
return Template.instance().searchType.get();
},
renderDownloadButton(latest) {
const isMarketplace = Template.instance().searchType.get() === 'marketplace';
const isDownloaded = latest._installed === false;
return isMarketplace && isDownloaded;
},
formatPrice(price) {
return `$${ Number.parseFloat(price).toFixed(2) }`;
},
formatCategories(categories = []) {
return categories.join(', ');
},
tabsData() {
const instance = Template.instance();
const { searchType } = instance;
return {
tabs: [
{
label: t('Marketplace'),
value: 'marketplace',
condition() {
return true;
},
active: searchType.get() === 'marketplace',
},
{
label: t('Installed'),
value: 'installed',
condition() {
return true;
},
active: searchType.get() === 'installed',
},
],
onChange(value) {
instance.apps.set([]);
searchType.set(value);
instance.isLoading.set(true);
if (value === 'marketplace') {
getApps(instance);
} else {
instance.apps.set(instance.installedApps.get());
instance.isLoading.set(false);
}
},
};
},
});
Template.apps.events({
'click .manage'() {
const rl = this;
if (rl && rl.latest && rl.latest.id) {
FlowRouter.go(`/admin/apps/${ rl.latest.id }?version=${ rl.latest.version }`);
}
},
'click [data-button="install"]'() {
FlowRouter.go('/admin/app/install');
},
'click .js-install'(e, template) {
e.stopPropagation();
const elm = e.currentTarget.parentElement;
elm.classList.add('loading');
APIClient.post('apps/', {
appId: this.latest.id,
marketplace: true,
version: this.latest.version,
})
.then(async() => {
await Promise.all([
getInstalledApps(template),
getApps(template),
]);
elm.classList.remove('loading');
})
.catch((e) => {
toastr.error((e.xhr.responseJSON && e.xhr.responseJSON.error) || e.message);
elm.classList.remove('loading');
});
},
'click .js-purchase'(e, template) {
e.stopPropagation();
const rl = this;
// play animation
const elm = e.currentTarget.parentElement;
APIClient.get(`apps?buildBuyUrl=true&appId=${ rl.latest.id }`)
.then((data) => {
modal.open({
allowOutsideClick: false,
data,
template: 'iframeModal',
}, () => {
elm.classList.add('loading');
APIClient.post('apps/', {
appId: this.latest.id,
marketplace: true,
version: this.latest.version,
})
.then(async() => {
await Promise.all([
getInstalledApps(template),
getApps(template),
]);
elm.classList.remove('loading');
})
.catch((e) => {
toastr.error((e.xhr.responseJSON && e.xhr.responseJSON.error) || e.message);
elm.classList.remove('loading');
});
});
})
.catch((e) => {
toastr.error((e.xhr.responseJSON && e.xhr.responseJSON.error) || e.message);
});
},
'keyup .js-search'(e, t) {
t.searchText.set(e.currentTarget.value);
},
'submit .js-search'(e) {
e.preventDefault();
},
});