@finos/legend-application-marketplace
Version:
Legend Marketplace application core
328 lines • 14.6 kB
JavaScript
/**
* Copyright (c) 2026-present, Goldman Sachs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { action, computed, flow, makeObservable, observable } from 'mobx';
import { ActionState, assertErrorThrown, isString, } from '@finos/legend-shared';
import { ServiceOwnershipType, DeploymentOwnershipDetail, UserListOwnershipDetail, } from '@finos/legend-graph';
import { LegendMarketplaceTelemetryHelper } from '../../__lib__/LegendMarketplaceTelemetryHelper.js';
export var LegendServiceSort;
(function (LegendServiceSort) {
LegendServiceSort["DEFAULT"] = "Default";
LegendServiceSort["NAME_ALPHABETICAL"] = "Name A-Z";
LegendServiceSort["NAME_REVERSE_ALPHABETICAL"] = "Name Z-A";
})(LegendServiceSort || (LegendServiceSort = {}));
export var ServicesViewMode;
(function (ServicesViewMode) {
ServicesViewMode["LIST"] = "list";
ServicesViewMode["TILE"] = "tile";
ServicesViewMode["GRID"] = "grid";
})(ServicesViewMode || (ServicesViewMode = {}));
export class LegendServiceCardState {
service;
constructor(service) {
this.service = service;
}
get title() {
if (this.service.title) {
return this.service.title;
}
else if (this.service.name) {
return this.service.name;
}
else {
const parts = this.patternPath.split('/');
return parts[parts.length - 1] ?? this.service.pattern;
}
}
get patternPath() {
return this.service.pattern.replace(/^\//u, '');
}
get description() {
return this.service.documentation || '';
}
get owners() {
const ownership = this.service.ownership;
if (ownership instanceof UserListOwnershipDetail &&
ownership.users.length > 0) {
return ownership.users;
}
if (ownership instanceof DeploymentOwnershipDetail) {
return [ownership.identifier];
}
return [];
}
get ownershipType() {
const ownership = this.service.ownership;
if (ownership instanceof DeploymentOwnershipDetail) {
return ServiceOwnershipType.DEPLOYMENT_OWNERSHIP;
}
if (ownership instanceof UserListOwnershipDetail) {
return ServiceOwnershipType.USER_LIST_OWNERSHIP;
}
return undefined;
}
get guid() {
return this.service.pattern;
}
static hashString(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = Math.trunc(hash * 31 + (str.codePointAt(i) ?? 0));
}
return Math.abs(hash);
}
get displayImage() {
const GENERIC_IMAGE_COUNT = 20;
const index = LegendServiceCardState.hashString(this.guid) % GENERIC_IMAGE_COUNT;
return `/assets/images${index + 1}.jpg`;
}
}
const LEGEND_MARKETPLACE_SETTING_KEY_OWNER_FILTERS = 'marketplace.data-apis.ownerFilters';
const LEGEND_MARKETPLACE_SETTING_KEY_DEPLOYMENT_ID_FILTERS = 'marketplace.data-apis.deploymentIdFilters';
const LEGEND_MARKETPLACE_SETTING_KEY_SERVICES_VIEW_MODE = 'marketplace.data-apis.viewMode';
const LEGEND_MARKETPLACE_SETTING_KEY_SHOW_OWN_SERVICES = 'marketplace.data-apis.showOwnServicesOnly';
const LEGEND_MARKETPLACE_SETTING_KEY_FAVORITES = 'marketplace.data-apis.favorites';
const LEGEND_MARKETPLACE_SETTING_KEY_ITEMS_PER_PAGE = 'marketplace.data-apis.itemsPerPage';
export class LegendMarketplaceDataAPIsStore {
marketplaceBaseStore;
searchQuery = '';
sort = LegendServiceSort.DEFAULT;
viewMode;
showOwnServicesOnly;
showFavoritesOnly = false;
favoritePatterns;
serviceCardStates = [];
page = 1;
itemsPerPage;
ownerFilters = [];
deploymentIdFilters = [];
favorites = new Set();
fetchingServicesState = ActionState.create();
constructor(marketplaceBaseStore) {
this.marketplaceBaseStore = marketplaceBaseStore;
this.ownerFilters =
this.marketplaceBaseStore.applicationStore.settingService.getObjectValue(LEGEND_MARKETPLACE_SETTING_KEY_OWNER_FILTERS) ?? [];
this.deploymentIdFilters =
this.marketplaceBaseStore.applicationStore.settingService.getObjectValue(LEGEND_MARKETPLACE_SETTING_KEY_DEPLOYMENT_ID_FILTERS) ?? [];
const persistedViewMode = this.marketplaceBaseStore.applicationStore.settingService.getStringValue(LEGEND_MARKETPLACE_SETTING_KEY_SERVICES_VIEW_MODE);
this.viewMode = Object.values(ServicesViewMode).includes(persistedViewMode)
? persistedViewMode
: ServicesViewMode.TILE;
const persistedShowOwn = this.marketplaceBaseStore.applicationStore.settingService.getBooleanValue(LEGEND_MARKETPLACE_SETTING_KEY_SHOW_OWN_SERVICES);
this.showOwnServicesOnly = persistedShowOwn ?? false;
const persistedFavorites = this.marketplaceBaseStore.applicationStore.settingService.getObjectValue(LEGEND_MARKETPLACE_SETTING_KEY_FAVORITES) ?? [];
this.favoritePatterns = new Set(persistedFavorites.filter(isString));
const persistedItemsPerPage = this.marketplaceBaseStore.applicationStore.settingService.getNumericValue(LEGEND_MARKETPLACE_SETTING_KEY_ITEMS_PER_PAGE);
this.itemsPerPage = persistedItemsPerPage ?? 12;
makeObservable(this, {
searchQuery: observable,
sort: observable,
viewMode: observable,
showOwnServicesOnly: observable,
showFavoritesOnly: observable,
favoritePatterns: observable.shallow,
serviceCardStates: observable,
page: observable,
itemsPerPage: observable,
ownerFilters: observable,
deploymentIdFilters: observable,
favorites: observable,
setSearchQuery: action,
setSort: action,
setViewMode: action,
setShowOwnServicesOnly: action,
setShowFavoritesOnly: action,
toggleFavorite: action,
setPage: action,
setItemsPerPage: action,
addOwnerFilter: action,
removeOwnerFilter: action,
addDeploymentIdFilter: action,
removeDeploymentIdFilter: action,
clearAllFilters: action,
filteredSortedServices: computed,
paginatedServices: computed,
totalFilteredCount: computed,
hasActiveFilters: computed,
isLoading: computed,
fetchAllServices: flow,
});
}
setSearchQuery(query) {
this.searchQuery = query;
this.page = 1;
}
setSort(sort) {
this.sort = sort;
}
setViewMode(mode) {
this.viewMode = mode;
this.marketplaceBaseStore.applicationStore.settingService.persistValue(LEGEND_MARKETPLACE_SETTING_KEY_SERVICES_VIEW_MODE, mode);
}
setShowOwnServicesOnly(value) {
this.showOwnServicesOnly = value;
this.page = 1;
this.marketplaceBaseStore.applicationStore.settingService.persistValue(LEGEND_MARKETPLACE_SETTING_KEY_SHOW_OWN_SERVICES, value);
}
setShowFavoritesOnly(value) {
this.showFavoritesOnly = value;
this.page = 1;
}
isFavorite(pattern) {
return this.favoritePatterns.has(pattern);
}
toggleFavorite(pattern) {
if (this.favoritePatterns.has(pattern)) {
this.favoritePatterns.delete(pattern);
}
else {
this.favoritePatterns.add(pattern);
}
this.marketplaceBaseStore.applicationStore.settingService.persistValue(LEGEND_MARKETPLACE_SETTING_KEY_FAVORITES, Array.from(this.favoritePatterns));
}
setPage(value) {
this.page = value;
}
setItemsPerPage(value) {
this.itemsPerPage = value;
this.marketplaceBaseStore.applicationStore.settingService.persistValue(LEGEND_MARKETPLACE_SETTING_KEY_ITEMS_PER_PAGE, value);
}
persistOwnerFilters() {
this.marketplaceBaseStore.applicationStore.settingService.persistValue(LEGEND_MARKETPLACE_SETTING_KEY_OWNER_FILTERS, this.ownerFilters);
}
persistDeploymentIdFilters() {
this.marketplaceBaseStore.applicationStore.settingService.persistValue(LEGEND_MARKETPLACE_SETTING_KEY_DEPLOYMENT_ID_FILTERS, this.deploymentIdFilters);
}
addOwnerFilter(value) {
const trimmed = value.trim();
if (trimmed && !this.ownerFilters.includes(trimmed)) {
this.ownerFilters.push(trimmed);
this.page = 1;
this.persistOwnerFilters();
LegendMarketplaceTelemetryHelper.logEvent_FilterServices(this.marketplaceBaseStore.applicationStore.telemetryService, 'owner', trimmed, 'add');
}
}
removeOwnerFilter(value) {
this.ownerFilters = this.ownerFilters.filter((v) => v !== value);
this.page = 1;
this.persistOwnerFilters();
LegendMarketplaceTelemetryHelper.logEvent_FilterServices(this.marketplaceBaseStore.applicationStore.telemetryService, 'owner', value, 'remove');
}
addDeploymentIdFilter(value) {
const trimmed = value.trim();
if (trimmed && !this.deploymentIdFilters.includes(trimmed)) {
this.deploymentIdFilters.push(trimmed);
this.page = 1;
this.persistDeploymentIdFilters();
LegendMarketplaceTelemetryHelper.logEvent_FilterServices(this.marketplaceBaseStore.applicationStore.telemetryService, 'deploymentId', trimmed, 'add');
}
}
removeDeploymentIdFilter(value) {
this.deploymentIdFilters = this.deploymentIdFilters.filter((v) => v !== value);
this.page = 1;
this.persistDeploymentIdFilters();
LegendMarketplaceTelemetryHelper.logEvent_FilterServices(this.marketplaceBaseStore.applicationStore.telemetryService, 'deploymentId', value, 'remove');
}
clearAllFilters() {
this.ownerFilters = [];
this.deploymentIdFilters = [];
this.page = 1;
this.persistOwnerFilters();
this.persistDeploymentIdFilters();
LegendMarketplaceTelemetryHelper.logEvent_FilterServices(this.marketplaceBaseStore.applicationStore.telemetryService, 'all', '', 'clear');
}
get hasActiveFilters() {
return this.ownerFilters.length > 0 || this.deploymentIdFilters.length > 0;
}
get filteredSortedServices() {
let results = this.serviceCardStates;
if (this.showFavoritesOnly) {
results = results.filter((card) => this.favoritePatterns.has(card.service.pattern));
}
if (this.showOwnServicesOnly) {
const currentUser = this.marketplaceBaseStore.applicationStore.identityService.currentUser;
if (currentUser) {
const userId = currentUser.toLowerCase();
results = results.filter((card) => card.owners.some((owner) => owner.toLowerCase() === userId));
}
}
if (this.searchQuery) {
const query = this.searchQuery.replace(/^\//u, '').toLowerCase();
results = results.filter((card) => card.title.toLowerCase().includes(query) ||
card.patternPath.toLowerCase().includes(query) ||
card.description.toLowerCase().includes(query));
}
const hasOwnerFilters = this.ownerFilters.length > 0;
const hasDeploymentFilters = this.deploymentIdFilters.length > 0;
if (hasOwnerFilters || hasDeploymentFilters) {
const ownerQueries = this.ownerFilters.map((q) => q.toLowerCase());
const deploymentQueries = this.deploymentIdFilters.map((q) => q.toLowerCase());
results = results.filter((card) => {
const matchesOwners = hasOwnerFilters &&
card.ownershipType !== ServiceOwnershipType.DEPLOYMENT_OWNERSHIP &&
ownerQueries.every((q) => card.owners.some((owner) => owner.toLowerCase().includes(q)));
const matchesDeployment = hasDeploymentFilters &&
(() => {
const ownership = card.service.ownership;
if (ownership instanceof DeploymentOwnershipDetail) {
return deploymentQueries.every((q) => ownership.identifier.toLowerCase().includes(q));
}
return false;
})();
return matchesOwners || matchesDeployment;
});
}
return results.slice().sort((a, b) => {
switch (this.sort) {
case LegendServiceSort.NAME_ALPHABETICAL:
return a.title.localeCompare(b.title);
case LegendServiceSort.NAME_REVERSE_ALPHABETICAL:
return b.title.localeCompare(a.title);
case LegendServiceSort.DEFAULT:
default:
return a.patternPath.localeCompare(b.patternPath);
}
});
}
get paginatedServices() {
const start = (this.page - 1) * this.itemsPerPage;
return this.filteredSortedServices.slice(start, start + this.itemsPerPage);
}
get totalFilteredCount() {
return this.filteredSortedServices.length;
}
get isLoading() {
return this.fetchingServicesState.isInProgress;
}
*fetchAllServices() {
this.fetchingServicesState.inProgress();
try {
const engineClient = this.marketplaceBaseStore.engineServerClient;
const services = (yield engineClient.getServicesInfo());
const serviceCards = [];
for (const svc of services) {
serviceCards.push(new LegendServiceCardState(svc));
}
this.serviceCardStates = serviceCards;
this.fetchingServicesState.complete();
}
catch (error) {
assertErrorThrown(error);
this.marketplaceBaseStore.applicationStore.notificationService.notifyError(`Error fetching services: ${error.message}`);
this.fetchingServicesState.fail();
}
}
}
//# sourceMappingURL=LegendMarketplaceDataAPIsStore.js.map