diff --git a/src/app/features/settings/settings-addons/settings-addons.component.ts b/src/app/features/settings/settings-addons/settings-addons.component.ts index da34cd0fc..da2a68440 100644 --- a/src/app/features/settings/settings-addons/settings-addons.component.ts +++ b/src/app/features/settings/settings-addons/settings-addons.component.ts @@ -161,11 +161,13 @@ export class SettingsAddonsComponent { readonly filteredAddonCards = computed(() => { const searchValue = this.searchValue().toLowerCase(); - return this.currentAddonsState().filter( + const filteredAddons = this.currentAddonsState().filter( (card) => card.externalServiceName.toLowerCase().includes(searchValue) || card.displayName.toLowerCase().includes(searchValue) ); + + return sortAddonCardsAlphabetically(filteredAddons); }); onCategoryChange(value: Primitive): void { diff --git a/src/app/shared/components/addons/addon-card/addon-card.component.ts b/src/app/shared/components/addons/addon-card/addon-card.component.ts index 44aaf058c..7c1ef612d 100644 --- a/src/app/shared/components/addons/addon-card/addon-card.component.ts +++ b/src/app/shared/components/addons/addon-card/addon-card.component.ts @@ -57,7 +57,17 @@ export class AddonCardComponent { if (!isConfigured) return true; - return hasAdmin; + const addon = this.card(); + if (!addon) return true; + + let isOwner = false; + if ('configuredAddon' in addon && addon.configuredAddon) { + isOwner = addon.configuredAddon.currentUserIsOwner; + } else if ('currentUserIsOwner' in addon) { + isOwner = addon.currentUserIsOwner; + } + + return hasAdmin || isOwner; }); readonly buttonLabel = computed(() => { diff --git a/src/app/shared/enums/operation-names.enum.ts b/src/app/shared/enums/operation-names.enum.ts index db58bb61b..ab725cfc8 100644 --- a/src/app/shared/enums/operation-names.enum.ts +++ b/src/app/shared/enums/operation-names.enum.ts @@ -1,6 +1,8 @@ export enum OperationNames { LIST_ROOT_ITEMS = 'list_root_items', LIST_CHILD_ITEMS = 'list_child_items', + LIST_ROOT_COLLECTIONS = 'list_root_collections', + LIST_COLLECTION_ITEMS = 'list_collection_items', GET_ITEM_INFO = 'get_item_info', HAS_REVISIONS = 'has_revisions', } diff --git a/src/app/shared/services/addons/addon-form.service.ts b/src/app/shared/services/addons/addon-form.service.ts index 33a534f1c..9f164b626 100644 --- a/src/app/shared/services/addons/addon-form.service.ts +++ b/src/app/shared/services/addons/addon-form.service.ts @@ -113,6 +113,12 @@ export class AddonFormService { : (addon as AddonModel).id; } + private getOperationNames(addonTypeString: string): string[] { + return addonTypeString === AddonType.CITATION + ? ['list_collection_items', 'list_root_collections', 'get_item_info'] + : ['list_child_items', 'list_root_items', 'get_item_info']; + } + generateConfiguredAddonCreatePayload( addon: AddonModel | AuthorizedAccountModel, selectedAccount: AuthorizedAccountModel, @@ -132,7 +138,7 @@ export class AddonFormService { display_name: displayName, ...(addonTypeString !== AddonType.LINK && { root_folder: selectedStorageItemId }), connected_capabilities: ['UPDATE', 'ACCESS'], - connected_operation_names: ['list_child_items', 'list_root_items', 'get_item_info'], + connected_operation_names: this.getOperationNames(addonTypeString), external_service_name: addon.externalServiceName, ...(resourceType && { resource_type: resourceType }), ...(addonTypeString === AddonType.LINK && { target_id: selectedStorageItemId }), @@ -180,7 +186,7 @@ export class AddonFormService { authorized_resource_uri: resourceUri, display_name: displayName, connected_capabilities: ['UPDATE', 'ACCESS'], - connected_operation_names: ['list_child_items', 'list_root_items', 'get_item_info'], + connected_operation_names: this.getOperationNames(addonTypeString), external_service_name: addon.externalServiceName, ...(resourceType && { resource_type: resourceType }), ...(addonTypeString !== AddonType.LINK && { root_folder: selectedStorageItemId }), diff --git a/src/app/shared/services/addons/addon-operation-invocation.service.ts b/src/app/shared/services/addons/addon-operation-invocation.service.ts index c2fc0bec9..15526dce9 100644 --- a/src/app/shared/services/addons/addon-operation-invocation.service.ts +++ b/src/app/shared/services/addons/addon-operation-invocation.service.ts @@ -1,25 +1,43 @@ import { Injectable } from '@angular/core'; import { OperationNames } from '@osf/shared/enums'; +import { isCitationAddon } from '@osf/shared/helpers'; import { AuthorizedAccountModel, ConfiguredAddonModel, OperationInvocationRequestJsonApi } from '@shared/models'; @Injectable({ providedIn: 'root', }) export class AddonOperationInvocationService { + private getAddonSpecificOperationName( + operationName: OperationNames, + addon: AuthorizedAccountModel | ConfiguredAddonModel + ): OperationNames { + if (!isCitationAddon(addon)) { + return operationName; + } + + const operationMap: Record = { + [OperationNames.LIST_ROOT_ITEMS]: OperationNames.LIST_ROOT_COLLECTIONS, + [OperationNames.LIST_CHILD_ITEMS]: OperationNames.LIST_COLLECTION_ITEMS, + }; + + return operationMap[operationName] ?? operationName; + } + createInitialOperationInvocationPayload( operationName: OperationNames, selectedAccount: AuthorizedAccountModel, itemId?: string ): OperationInvocationRequestJsonApi { - const operationKwargs = this.getOperationKwargs(operationName, itemId); + const addonSpecificOperationName = this.getAddonSpecificOperationName(operationName, selectedAccount); + const operationKwargs = this.getOperationKwargs(addonSpecificOperationName, itemId); return { data: { type: 'addon-operation-invocations', attributes: { invocation_status: null, - operation_name: operationName, + operation_name: addonSpecificOperationName, operation_kwargs: operationKwargs, operation_result: {}, created: null, @@ -42,14 +60,15 @@ export class AddonOperationInvocationService { operationName: OperationNames, itemId: string ): OperationInvocationRequestJsonApi { - const operationKwargs = this.getOperationKwargs(operationName, itemId); + const addonSpecificOperationName = this.getAddonSpecificOperationName(operationName, addon); + const operationKwargs = this.getOperationKwargs(addonSpecificOperationName, itemId); return { data: { type: 'addon-operation-invocations', attributes: { invocation_status: null, - operation_name: operationName, + operation_name: addonSpecificOperationName, operation_kwargs: operationKwargs, operation_result: {}, created: null, @@ -68,13 +87,19 @@ export class AddonOperationInvocationService { } private getOperationKwargs(operationName: OperationNames, itemId?: string): Record { - if (!itemId || operationName === OperationNames.LIST_ROOT_ITEMS) { + const isRootOperation = + operationName === OperationNames.LIST_ROOT_ITEMS || operationName === OperationNames.LIST_ROOT_COLLECTIONS; + + if (!itemId || isRootOperation) { return {}; } + const isChildOperation = + operationName === OperationNames.LIST_CHILD_ITEMS || operationName === OperationNames.LIST_COLLECTION_ITEMS; + return { item_id: itemId, - ...(operationName === OperationNames.LIST_CHILD_ITEMS && { item_type: 'FOLDER' }), + ...(isChildOperation && { item_type: 'FOLDER' }), }; } }