diff --git a/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.html b/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.html
index 729b0f781d5..a74f314a7cc 100644
--- a/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.html
+++ b/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.html
@@ -76,9 +76,21 @@
-
+
+
+
diff --git a/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.spec.ts b/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.spec.ts
index 0cc824bdd8b..1da35adf950 100644
--- a/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.spec.ts
+++ b/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.spec.ts
@@ -1,4 +1,5 @@
import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
import { ClarinLicenseTableComponent } from './clarin-license-table.component';
import { NotificationsServiceStub } from '../../shared/testing/notifications-service.stub';
import { ClarinLicenseDataService } from '../../core/data/clarin/clarin-license-data.service';
@@ -14,7 +15,7 @@ import { PaginationServiceStub } from '../../shared/testing/pagination-service.s
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { defaultPagination } from '../clarin-license-table-pagination';
import { ClarinLicenseLabelDataService } from '../../core/data/clarin/clarin-license-label-data.service';
-import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+import { NgbActiveModal, NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
import { HostWindowService } from '../../shared/host-window.service';
import { HostWindowServiceStub } from '../../shared/testing/host-window-service.stub';
import {
@@ -25,7 +26,7 @@ import {
mockNonExtendedLicenseLabel, successfulResponse
} from '../../shared/testing/clarin-license-mock';
import {GroupDataService} from '../../core/eperson/group-data.service';
-import {createSuccessfulRemoteDataObject$} from '../../shared/remote-data.utils';
+import { createNoContentRemoteDataObject$, createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
import {createPaginatedList} from '../../shared/testing/utils.test';
import {LinkHeadService} from '../../core/services/link-head.service';
import {ConfigurationDataService} from '../../core/data/configuration-data.service';
@@ -51,6 +52,7 @@ describe('ClarinLicenseTableComponent', () => {
findAll: mockLicenseRD$,
create: createdLicenseRD$,
put: createdLicenseRD$,
+ delete: createNoContentRemoteDataObject$(),
searchBy: mockLicenseRD$,
getLinkPath: observableOf('')
});
@@ -181,4 +183,53 @@ describe('ClarinLicenseTableComponent', () => {
expect((component as any).clarinLicenseService.searchBy).toHaveBeenCalled();
expect((component as ClarinLicenseTableComponent).licensesRD$).not.toBeNull();
});
+
+ describe('license delete button', () => {
+ const getDeleteControls = () => {
+ const actionsRow = fixture.debugElement.query(By.css('.mt-2'));
+ const deleteWrapper = actionsRow.query(By.css('.btn-group.pr-1:last-child span'));
+ const deleteButton = deleteWrapper.query(By.css('button.btn-danger'));
+ return { deleteWrapper, deleteButton };
+ };
+
+ beforeEach(() => {
+ (clarinLicenseDataService.delete as jasmine.Spy).calls.reset();
+ });
+
+ it('should disable delete button and expose tooltip when selected license has bitstreams', () => {
+ component.selectedLicense = Object.assign({}, mockLicense, { bitstreams: 2 });
+ fixture.detectChanges();
+
+ const { deleteWrapper, deleteButton } = getDeleteControls();
+ const deleteTooltip = deleteWrapper.injector.get(NgbTooltip);
+
+ expect(deleteButton.attributes['aria-disabled']).toBe('true');
+ expect(deleteButton.nativeElement.classList.contains('disabled')).toBeTrue();
+ expect((deleteWrapper.nativeElement as HTMLElement).getAttribute('tabindex')).toBe('0');
+ expect(deleteTooltip.ngbTooltip as string).toContain('clarin-license.button.delete-l');
+ });
+
+ it('should not call delete when clicking disabled delete button', () => {
+ component.selectedLicense = Object.assign({}, mockLicense, { bitstreams: 1 });
+ fixture.detectChanges();
+
+ const { deleteButton } = getDeleteControls();
+ deleteButton.nativeElement.click();
+
+ expect((clarinLicenseDataService.delete as jasmine.Spy)).not.toHaveBeenCalled();
+ });
+
+ it('should enable delete button and call delete when selected license has no bitstreams', () => {
+ component.selectedLicense = Object.assign({}, mockLicense, { bitstreams: 0 });
+ fixture.detectChanges();
+
+ const { deleteWrapper, deleteButton } = getDeleteControls();
+ deleteButton.nativeElement.click();
+
+ expect(deleteButton.attributes['aria-disabled']).toBe('false');
+ expect(deleteButton.nativeElement.classList.contains('disabled')).toBeFalse();
+ expect((deleteWrapper.nativeElement as HTMLElement).getAttribute('tabindex')).toBeNull();
+ expect((clarinLicenseDataService.delete as jasmine.Spy)).toHaveBeenCalledWith(String(mockLicense.id));
+ });
+ });
});
diff --git a/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.ts b/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.ts
index 143f991aab1..d60411c7ae3 100644
--- a/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.ts
+++ b/src/app/clarin-licenses/clarin-license-table/clarin-license-table.component.ts
@@ -15,7 +15,7 @@ import { DefineLicenseLabelFormComponent } from './modal/define-license-label-fo
import { ClarinLicenseConfirmationSerializer } from '../../core/shared/clarin/clarin-license-confirmation-serializer';
import { NotificationsService } from '../../shared/notifications/notifications.service';
import { TranslateService } from '@ngx-translate/core';
-import { isNull } from '../../shared/empty.util';
+import { hasNoValue, isNull } from '../../shared/empty.util';
import { ClarinLicenseLabel } from '../../core/shared/clarin/clarin-license-label.model';
import { ClarinLicenseLabelDataService } from '../../core/data/clarin/clarin-license-label-data.service';
import { ClarinLicenseLabelExtendedSerializer } from '../../core/shared/clarin/clarin-license-label-extended-serializer';
@@ -274,7 +274,7 @@ export class ClarinLicenseTableComponent implements OnInit {
* Delete selected license. If none license is selected do nothing.
*/
deleteLicense() {
- if (isNull(this.selectedLicense?.id)) {
+ if (hasNoValue(this.selectedLicense?.id) || this.isSelectedLicenseInUse()) {
return;
}
this.clarinLicenseService.delete(String(this.selectedLicense.id))
@@ -287,6 +287,13 @@ export class ClarinLicenseTableComponent implements OnInit {
});
}
+ /**
+ * Returns whether selected license has attached bitstreams.
+ */
+ isSelectedLicenseInUse(): boolean {
+ return this.selectedLicense?.bitstreams > 0;
+ }
+
/**
* Pop up the notification about the request success. Messages are loaded from the `en.json5`.
* @param operationResponse current response
diff --git a/src/assets/i18n/cs.json5 b/src/assets/i18n/cs.json5
index ac5476fd0db..b287088939a 100644
--- a/src/assets/i18n/cs.json5
+++ b/src/assets/i18n/cs.json5
@@ -9423,6 +9423,9 @@
// "clarin-license.button.delete-license": "Delete License",
"clarin-license.button.delete-license": "Odstranit licenci",
+ // "clarin-license.button.delete-license.disabled-tooltip": "License \"{{name}}\" cannot be deleted because it is attached to one or more bitstreams.",
+ "clarin-license.button.delete-license.disabled-tooltip": "Licenci \"{{name}}\" nelze smazat, protože jsou k ní připojeny jeden nebo více bitstreamů.",
+
// "clarin-license.button.search": "Search",
"clarin-license.button.search": "Hledat",
diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5
index 472f95c978e..e0ded51faf7 100644
--- a/src/assets/i18n/en.json5
+++ b/src/assets/i18n/en.json5
@@ -6245,6 +6245,8 @@
"clarin-license.button.delete-license": "Delete License",
+ "clarin-license.button.delete-license.disabled-tooltip": "License \"{{name}}\" cannot be deleted because it is attached to one or more bitstreams.",
+
"clarin-license.button.search": "Search",
"clarin-license.button.search.placeholder": "Search by the license name ...",