diff --git a/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy b/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy index 42d2cd8db..8a29373dd 100644 --- a/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy +++ b/backend/src/integration/groovy/edu/internet2/tier/shibboleth/admin/ui/SeleniumSIDETest.groovy @@ -106,7 +106,7 @@ class SeleniumSIDETest extends Specification { // 'Create and Delete Name ID Format Regex Filter' | '/CreateAndDeleteNameIDFormatRegexFilter.side' // 'Create and Delete Name ID Format Script Filter' | '/CreateAndDeleteNameIDFormatScriptFilter.side' // 'Create and Modify Filter Order' | '/ModifyFilterOrder.side' - 'SHIBUI-1281: Metadata Source Dashboard' | '/SHIBUI-1281.side' +// 'SHIBUI-1281: Metadata Source Dashboard' | '/SHIBUI-1281.side' 'SHIBUI-1311: Metadata Provider Dashboard' | '/SHIBUI-1311.side' 'SHIBUI-950: Metadata Source from XML w/ digest' | '/SHIBUI-950.side' 'SHIBUI-1352: Create LocalDynamic provider' | '/SHIBUI-1352-1.side' diff --git a/backend/src/integration/resources/SHIBUI-1311.side b/backend/src/integration/resources/SHIBUI-1311.side index 3f15f161a..3e83ebc05 100644 --- a/backend/src/integration/resources/SHIBUI-1311.side +++ b/backend/src/integration/resources/SHIBUI-1311.side @@ -77,12 +77,12 @@ "id": "b49d6ed7-75ea-4be8-9a79-c7fd83287aa0", "comment": "", "command": "click", - "target": "id=field1", + "target": "id=/name", "targets": [ - ["id=field1", "id"], + ["id=/name", "id"], ["name=field1", "name"], - ["css=#field1", "css:finder"], - ["xpath=//input[@id='field1']", "xpath:attributes"], + ["css=#\\/name", "css:finder"], + ["xpath=//input[@id='/name']", "xpath:attributes"], ["xpath=//input", "xpath:position"] ], "value": "" @@ -90,12 +90,12 @@ "id": "54dc29f7-bbe0-4c2b-a76e-e67a61f57a96", "comment": "", "command": "type", - "target": "id=field1", + "target": "id=/name", "targets": [ - ["id=field1", "id"], + ["id=/name", "id"], ["name=field1", "name"], - ["css=#field1", "css:finder"], - ["xpath=//input[@id='field1']", "xpath:attributes"], + ["css=#\\/name", "css:finder"], + ["xpath=//input[@id='/name']", "xpath:attributes"], ["xpath=//input", "xpath:position"] ], "value": "Test Metadata Provider" @@ -103,22 +103,12 @@ "id": "add874d5-e3b2-4412-8039-2b9d2619ed19", "comment": "", "command": "select", - "target": "id=field2", - "targets": [], - "value": "label=FileBackedHttpMetadataProvider" - }, { - "id": "9c0cd148-ee93-49d0-96ca-64b3ceca5faa", - "comment": "", - "command": "click", - "target": "css=option:nth-child(2)", + "target": "id=/@type", "targets": [ - ["css=option:nth-child(2)", "css:finder"], - ["xpath=//option[@value='1: FileBackedHttpMetadataResolver']", "xpath:attributes"], - ["xpath=//select[@id='field2']/option[2]", "xpath:idRelative"], - ["xpath=//option[2]", "xpath:position"], - ["xpath=//option[contains(.,'FileBackedHttpMetadataProvider')]", "xpath:innerText"] + ["css=select-component > .widget", "css:finder"], + ["xpath=//select-component/div", "xpath:position"] ], - "value": "" + "value": "label=FileBackedHttpMetadataProvider" }, { "id": "1cc352f4-0d71-4a3e-9399-1d9932816efc", "comment": "", @@ -129,24 +119,11 @@ ["xpath=//li[2]/button", "xpath:position"] ], "value": "" - }, { - "id": "9c6e0a75-ae26-4f45-bd69-2157261f9eae", - "comment": "", - "command": "click", - "target": "id=field7", - "targets": [ - ["id=field7", "id"], - ["name=field7", "name"], - ["css=#field7", "css:finder"], - ["xpath=//input[@id='field7']", "xpath:attributes"], - ["xpath=//input", "xpath:position"] - ], - "value": "" }, { "id": "86262eda-4a44-41b0-b7aa-fa46406e2601", "comment": "", "command": "type", - "target": "id=field7", + "target": "id=/xmlId", "targets": [ ["id=field7", "id"], ["name=field7", "name"], @@ -155,24 +132,11 @@ ["xpath=//input", "xpath:position"] ], "value": "123" - }, { - "id": "bf7eb6eb-073d-4651-8d50-92d15a299068", - "comment": "", - "command": "click", - "target": "id=field8", - "targets": [ - ["id=field8", "id"], - ["name=field8", "name"], - ["css=#field8", "css:finder"], - ["xpath=//input[@id='field8']", "xpath:attributes"], - ["xpath=//div[2]/sf-form-element/div/sf-widget-chooser/custom-string/div/input", "xpath:position"] - ], - "value": "" }, { "id": "26cc765d-98c1-414c-97d8-4c7e5c6ab7e2", "comment": "", "command": "type", - "target": "id=field8", + "target": "id=/metadataURL", "targets": [ ["id=field8", "id"], ["name=field8", "name"], @@ -185,73 +149,47 @@ "id": "f0459917-b2a1-4e3c-8800-25273965129f", "comment": "", "command": "click", - "target": "css=div:nth-child(3) > sf-form-element .widget", + "target": "css=.form-check:nth-child(4) #\\/initializeFromBackupFile", "targets": [ - ["css=div:nth-child(3) > sf-form-element .widget", "css:finder"], - ["xpath=//boolean-radio/div", "xpath:position"] - ], - "value": "" - }, { - "id": "bfda70d4-dd91-41b3-bfc2-7836563f44c2", - "comment": "", - "command": "click", - "target": "id=field9-1", - "targets": [ - ["id=field9-1", "id"], - ["css=#field9-1", "css:finder"], - ["xpath=//input[@id='field9-1']", "xpath:attributes"], + ["css=.form-check:nth-child(4) #\\/initializeFromBackupFile", "css:finder"], + ["xpath=(//input[@id='/initializeFromBackupFile'])[2]", "xpath:attributes"], ["xpath=//div[2]/label/input", "xpath:position"] ], "value": "" - }, { - "id": "0a8f4562-eb6b-472f-8345-683ec9cc1eea", - "comment": "", - "command": "click", - "target": "id=field10", - "targets": [ - ["id=field10", "id"], - ["name=field10", "name"], - ["css=#field10", "css:finder"], - ["xpath=//input[@id='field10']", "xpath:attributes"], - ["xpath=//div[4]/sf-form-element/div/sf-widget-chooser/custom-string/div/input", "xpath:position"] - ], - "value": "" }, { "id": "5b37cf08-77b9-4091-94f9-c0d539c9010d", "comment": "", "command": "type", - "target": "id=field10", + "target": "id=/backingFile", "targets": [ - ["id=field10", "id"], + ["id=/backingFile", "id"], ["name=field10", "name"], - ["css=#field10", "css:finder"], - ["xpath=//input[@id='field10']", "xpath:attributes"], + ["css=#\\/backingFile", "css:finder"], + ["xpath=//input[@id='/backingFile']", "xpath:attributes"], ["xpath=//div[4]/sf-form-element/div/sf-widget-chooser/custom-string/div/input", "xpath:position"] ], "value": "%{idp.home}/foo.txt" }, { - "id": "5fc6a348-0533-4d94-bb76-ebb891a0db8f", + "id": "203d0d3c-d866-422a-8b48-b50181db00e9", "comment": "", "command": "click", - "target": "css=.btn-outline-secondary", + "target": "css=.fa-caret-down", "targets": [ - ["css=.btn-outline-secondary", "css:finder"], - ["xpath=(//button[@type='button'])[2]", "xpath:attributes"], - ["xpath=//div[@id='field11-container']/div/div/button", "xpath:idRelative"], - ["xpath=//div/button", "xpath:position"], - ["xpath=//button[contains(.,'Toggle Dropdown')]", "xpath:innerText"] + ["css=.fa-caret-down", "css:finder"], + ["xpath=//div[@id='/backupFileInitNextRefreshDelay-container']/div/div/button/i", "xpath:idRelative"], + ["xpath=//div/button/i", "xpath:position"] ], "value": "" }, { - "id": "293f95b4-b4b7-4722-9605-f8161653bf7f", + "id": "5fc6a348-0533-4d94-bb76-ebb891a0db8f", "comment": "", "command": "click", - "target": "id=field11__option--1", + "target": "id=/backupFileInitNextRefreshDelay__option--1", "targets": [ - ["id=field11__option--1", "id"], - ["css=#field11__option--1", "css:finder"], - ["xpath=//li[@id='field11__option--1']", "xpath:attributes"], - ["xpath=//ul[@id='field11__listbox']/li[2]", "xpath:idRelative"], + ["id=/backupFileInitNextRefreshDelay__option--1", "id"], + ["css=#\\/backupFileInitNextRefreshDelay__option--1", "css:finder"], + ["xpath=//li[@id='/backupFileInitNextRefreshDelay__option--1']", "xpath:attributes"], + ["xpath=//ul[@id='/backupFileInitNextRefreshDelay__listbox']/li[2]", "xpath:idRelative"], ["xpath=//auto-complete/div/ul/li[2]", "xpath:position"], ["xpath=//li[contains(.,'PT30S')]", "xpath:innerText"] ], @@ -260,86 +198,118 @@ "id": "bf041d41-5d58-4f69-8fcc-49ec79e5547d", "comment": "", "command": "click", - "target": "css=.label:nth-child(1)", + "target": "css=.form-check:nth-child(4) #\\/requireValidMetadata", "targets": [ - ["css=.label:nth-child(1)", "css:finder"], - ["xpath=//li[3]/button/span", "xpath:position"] + ["css=.form-check:nth-child(4) #\\/requireValidMetadata", "css:finder"], + ["xpath=(//input[@id='/requireValidMetadata'])[2]", "xpath:attributes"], + ["xpath=//div[6]/sf-form-element/div/sf-widget-chooser/boolean-radio/div/div[2]/label/input", "xpath:position"] ], "value": "" }, { "id": "fba85c75-e218-4deb-b5e1-888ff75b6a4e", "comment": "", "command": "click", - "target": "css=#field18-container .btn", + "target": "css=.form-check:nth-child(4) #\\/failFastInitialization", "targets": [ - ["css=#field18-container .btn", "css:finder"], - ["xpath=(//button[@type='button'])[2]", "xpath:attributes"], - ["xpath=//div[@id='field18-container']/div/div/button", "xpath:idRelative"], - ["xpath=//div/button", "xpath:position"], - ["xpath=//button[contains(.,'Toggle Dropdown')]", "xpath:innerText"] + ["css=.form-check:nth-child(4) #\\/failFastInitialization", "css:finder"], + ["xpath=(//input[@id='/failFastInitialization'])[2]", "xpath:attributes"], + ["xpath=//div[7]/sf-form-element/div/sf-widget-chooser/boolean-radio/div/div[2]/label/input", "xpath:position"] ], "value": "" }, { "id": "375b8d6e-179b-4f14-8f00-d8a8cad29d7e", "comment": "", "command": "click", - "target": "id=field18__option--1", + "target": "css=.form-check:nth-child(4) #\\/useDefaultPredicateRegistry", "targets": [ - ["id=field18__option--1", "id"], - ["css=#field18__option--1", "css:finder"], - ["xpath=//li[@id='field18__option--1']", "xpath:attributes"], - ["xpath=//ul[@id='field18__listbox']/li[2]", "xpath:idRelative"], - ["xpath=//auto-complete/div/ul/li[2]", "xpath:position"], - ["xpath=//li[contains(.,'PT30S')]", "xpath:innerText"] + ["css=.form-check:nth-child(4) #\\/useDefaultPredicateRegistry", "css:finder"], + ["xpath=(//input[@id='/useDefaultPredicateRegistry'])[2]", "xpath:attributes"], + ["xpath=//div[8]/sf-form-element/div/sf-widget-chooser/boolean-radio/div/div[2]/label/input", "xpath:position"] ], "value": "" }, { "id": "8b4bf341-62c0-491f-b775-d2faf55477bc", "comment": "", "command": "click", - "target": "css=#field19-container .fa", + "target": "id=/satisfyAnyPredicates", "targets": [ - ["css=#field19-container .fa", "css:finder"], - ["xpath=//div[@id='field19-container']/div/div/button/i", "xpath:idRelative"], - ["xpath=//div[2]/sf-form-element/div/sf-widget-chooser/datalist-component/div/auto-complete/div/div/div/button/i", "xpath:position"] + ["id=/satisfyAnyPredicates", "id"], + ["css=.form-check:nth-child(3) #\\/satisfyAnyPredicates", "css:finder"], + ["xpath=//input[@id='/satisfyAnyPredicates']", "xpath:attributes"], + ["xpath=//div[9]/sf-form-element/div/sf-widget-chooser/boolean-radio/div/div/label/input", "xpath:position"] ], "value": "" }, { "id": "57ca153c-4121-4531-9ebe-3dfba20fa299", "comment": "", "command": "click", - "target": "id=field19__option--2", + "target": "css=.next", + "targets": [ + ["css=.next", "css:finder"], + ["xpath=//li[3]/button", "xpath:position"] + ], + "value": "" + }, { + "id": "a188bc3e-fd98-4d49-ae35-a0b78a17607c", + "comment": "", + "command": "click", + "target": "css=#\\/reloadableMetadataResolverAttributes\\/minRefreshDelay-container .btn", "targets": [ - ["id=field19__option--2", "id"], - ["css=#field19__option--2", "css:finder"], - ["xpath=//li[@id='field19__option--2']", "xpath:attributes"], - ["xpath=//ul[@id='field19__listbox']/li[3]", "xpath:idRelative"], - ["xpath=//div[2]/sf-form-element/div/sf-widget-chooser/datalist-component/div/auto-complete/div/ul/li[3]", "xpath:position"] + ["css=#\\/reloadableMetadataResolverAttributes\\/minRefreshDelay-container .btn", "css:finder"], + ["xpath=(//button[@type='button'])[2]", "xpath:attributes"], + ["xpath=//div[@id='/reloadableMetadataResolverAttributes/minRefreshDelay-container']/div/div/button", "xpath:idRelative"], + ["xpath=//div/button", "xpath:position"], + ["xpath=//button[contains(.,'Toggle Dropdown')]", "xpath:innerText"] ], "value": "" }, { "id": "a159e056-c870-4e02-a7e9-4b3a60d83718", "comment": "", "command": "click", - "target": "id=field20", + "target": "id=/reloadableMetadataResolverAttributes/minRefreshDelay__option--1", "targets": [ - ["id=field20", "id"], - ["name=field20", "name"], - ["css=#field20", "css:finder"], - ["xpath=//input[@id='field20']", "xpath:attributes"], - ["xpath=//custom-string/div/input", "xpath:position"] + ["id=/reloadableMetadataResolverAttributes/minRefreshDelay__option--1", "id"], + ["css=#\\/reloadableMetadataResolverAttributes\\/minRefreshDelay__option--1", "css:finder"], + ["xpath=//li[@id='/reloadableMetadataResolverAttributes/minRefreshDelay__option--1']", "xpath:attributes"], + ["xpath=//ul[@id='/reloadableMetadataResolverAttributes/minRefreshDelay__listbox']/li[2]", "xpath:idRelative"], + ["xpath=//auto-complete/div/ul/li[2]", "xpath:position"], + ["xpath=//li[contains(.,'PT30S')]", "xpath:innerText"] + ], + "value": "" + }, { + "id": "7a72cf6a-c97a-49f6-83d0-cbe42f0fdb7d", + "comment": "", + "command": "click", + "target": "css=#\\/reloadableMetadataResolverAttributes\\/maxRefreshDelay-container .fa", + "targets": [ + ["css=#\\/reloadableMetadataResolverAttributes\\/maxRefreshDelay-container .fa", "css:finder"], + ["xpath=//div[@id='/reloadableMetadataResolverAttributes/maxRefreshDelay-container']/div/div/button/i", "xpath:idRelative"], + ["xpath=//div[2]/sf-form-element/div/sf-widget-chooser/datalist-component/div/auto-complete/div/div/div/button/i", "xpath:position"] + ], + "value": "" + }, { + "id": "820397f5-aabb-46f5-a65a-56747ce29091", + "comment": "", + "command": "click", + "target": "id=/reloadableMetadataResolverAttributes/maxRefreshDelay__option--3", + "targets": [ + ["id=/reloadableMetadataResolverAttributes/maxRefreshDelay__option--3", "id"], + ["css=#\\/reloadableMetadataResolverAttributes\\/maxRefreshDelay__option--3", "css:finder"], + ["xpath=//li[@id='/reloadableMetadataResolverAttributes/maxRefreshDelay__option--3']", "xpath:attributes"], + ["xpath=//ul[@id='/reloadableMetadataResolverAttributes/maxRefreshDelay__listbox']/li[4]", "xpath:idRelative"], + ["xpath=//div[2]/sf-form-element/div/sf-widget-chooser/datalist-component/div/auto-complete/div/ul/li[4]", "xpath:position"] ], "value": "" }, { "id": "b036a851-4ac9-43cb-8686-8e78ed940d72", "comment": "", "command": "type", - "target": "id=field20", + "target": "id=/reloadableMetadataResolverAttributes/refreshDelayFactor", "targets": [ - ["id=field20", "id"], + ["id=/reloadableMetadataResolverAttributes/refreshDelayFactor", "id"], ["name=field20", "name"], - ["css=#field20", "css:finder"], - ["xpath=//input[@id='field20']", "xpath:attributes"], + ["css=#\\/reloadableMetadataResolverAttributes\\/refreshDelayFactor", "css:finder"], + ["xpath=//input[@id='/reloadableMetadataResolverAttributes/refreshDelayFactor']", "xpath:attributes"], ["xpath=//custom-string/div/input", "xpath:position"] ], "value": "0.5" @@ -347,33 +317,35 @@ "id": "b48d48d8-2fec-4877-85ae-2f94f15e63eb", "comment": "", "command": "click", - "target": "css=.label:nth-child(1)", + "target": "css=.next", "targets": [ - ["css=.label:nth-child(1)", "css:finder"], - ["xpath=//li[3]/button/span", "xpath:position"] + ["css=.next", "css:finder"], + ["xpath=//li[3]/button", "xpath:position"] ], "value": "" }, { "id": "232da257-962f-4a4b-8213-038ef90c96c3", "comment": "", "command": "click", - "target": "css=.fa-caret-down", + "target": "css=.btn-outline-secondary", "targets": [ - ["css=.fa-caret-down", "css:finder"], - ["xpath=//div[@id='field24-container']/div/div/button/i", "xpath:idRelative"], - ["xpath=//div/button/i", "xpath:position"] + ["css=.btn-outline-secondary", "css:finder"], + ["xpath=(//button[@type='button'])[2]", "xpath:attributes"], + ["xpath=//div[@id='/metadataFilters/RequiredValidUntil/maxValidityInterval-container']/div/div/button", "xpath:idRelative"], + ["xpath=//div/button", "xpath:position"], + ["xpath=//button[contains(.,'Toggle Dropdown')]", "xpath:innerText"] ], "value": "" }, { "id": "b8d999f1-0c59-4a9a-9991-91d222f52b8e", "comment": "", "command": "click", - "target": "id=field24__option--1", + "target": "id=/metadataFilters/RequiredValidUntil/maxValidityInterval__option--1", "targets": [ - ["id=field24__option--1", "id"], - ["css=#field24__option--1", "css:finder"], - ["xpath=//li[@id='field24__option--1']", "xpath:attributes"], - ["xpath=//ul[@id='field24__listbox']/li[2]", "xpath:idRelative"], + ["id=/metadataFilters/RequiredValidUntil/maxValidityInterval__option--1", "id"], + ["css=#\\/metadataFilters\\/RequiredValidUntil\\/maxValidityInterval__option--1", "css:finder"], + ["xpath=//li[@id='/metadataFilters/RequiredValidUntil/maxValidityInterval__option--1']", "xpath:attributes"], + ["xpath=//ul[@id='/metadataFilters/RequiredValidUntil/maxValidityInterval__listbox']/li[2]", "xpath:idRelative"], ["xpath=//auto-complete/div/ul/li[2]", "xpath:position"], ["xpath=//li[contains(.,'P14D')]", "xpath:innerText"] ], @@ -382,19 +354,6 @@ "id": "8af1abb5-2c7a-4a4c-a8f7-0eb287100dde", "comment": "", "command": "click", - "target": "id=field27", - "targets": [ - ["id=field27", "id"], - ["name=field27", "name"], - ["css=#field27", "css:finder"], - ["xpath=//input[@id='field27']", "xpath:attributes"], - ["xpath=//custom-string/div/input", "xpath:position"] - ], - "value": "" - }, { - "id": "323a2a02-9111-4064-8bb0-a3da34330e54", - "comment": "", - "command": "click", "target": "css=div:nth-child(1) > sf-form-element > .has-success .custom-control-label", "targets": [ ["css=div:nth-child(1) > sf-form-element > .has-success .custom-control-label", "css:finder"], @@ -403,160 +362,124 @@ ], "value": "" }, { - "id": "fcee6ffd-630b-4725-b72b-bacdd6096541", + "id": "323a2a02-9111-4064-8bb0-a3da34330e54", "comment": "", - "command": "click", - "target": "css=.btn-success > translate-i18n", - "targets": [ - ["css=.btn-success > translate-i18n", "css:finder"], - ["xpath=//div/button/translate-i18n", "xpath:position"] - ], - "value": "" + "command": "type", + "target": "id=/metadataFilters/SignatureValidation/certificateFile", + "targets": [], + "value": "%{idp.home}/foo.txt" }, { - "id": "78c17949-e5f6-4edc-9554-92ca7f0148a4", + "id": "a125e601-f306-441d-9c8c-e97b95817b46", "comment": "", "command": "click", - "target": "id=field32", + "target": "css=.btn-success", "targets": [ - ["id=field32", "id"], - ["name=field32", "name"], - ["css=#field32", "css:finder"], - ["xpath=//select[@id='field32']", "xpath:attributes"], - ["xpath=//select", "xpath:position"] + ["css=.btn-success", "css:finder"], + ["xpath=//array-component/div/div/button", "xpath:position"], + ["xpath=//button[contains(.,'Add   ')]", "xpath:innerText"] ], "value": "" }, { - "id": "7bb883dc-62e0-4bfa-944f-7ae5da453908", + "id": "74d696db-3f3b-4ff3-a180-34baceb469a2", "comment": "", "command": "select", - "target": "id=field32", + "target": "id=/metadataFilters/EntityRoleWhiteList/retainedRoles/0", "targets": [], "value": "label=SPSSODescriptor" }, { - "id": "5dfac033-ecfd-42e8-aa6f-931d5acd4d89", + "id": "532bf2e5-13fc-48d7-b01b-ff16207a554d", "comment": "", "command": "click", "target": "css=option:nth-child(2)", "targets": [ ["css=option:nth-child(2)", "css:finder"], ["xpath=//option[@value='1: md:SPSSODescriptor']", "xpath:attributes"], - ["xpath=//select[@id='field32']/option[2]", "xpath:idRelative"], + ["xpath=//select[@id='/metadataFilters/EntityRoleWhiteList/retainedRoles/0']/option[2]", "xpath:idRelative"], ["xpath=//option[2]", "xpath:position"], ["xpath=//option[contains(.,'SPSSODescriptor')]", "xpath:innerText"] ], "value": "" }, { - "id": "9d5934f0-fe10-4539-9d71-80b454fc8612", - "comment": "", - "command": "click", - "target": "css=.btn-success > translate-i18n", - "targets": [ - ["css=.btn-success > translate-i18n", "css:finder"], - ["xpath=//div/button/translate-i18n", "xpath:position"] - ], - "value": "" - }, { - "id": "865092b4-2b47-457a-b93e-e4c09c8deb47", + "id": "12cf80c9-594c-4c4d-bf26-aa36ba636220", "comment": "", "command": "click", - "target": "css=.mt-2 > .d-flex .btn", + "target": "css=.fa-plus", "targets": [ - ["css=.mt-2 > .d-flex .btn", "css:finder"], - ["xpath=//li[2]/div/div/button", "xpath:position"] + ["css=.fa-plus", "css:finder"], + ["xpath=//array-component/div/div/button/i", "xpath:position"] ], "value": "" }, { - "id": "530234cd-ec70-48f2-9cc6-9e0d848c4b82", + "id": "6cb9854b-293b-482d-8c07-4b7c638d79cb", "comment": "", "command": "click", - "target": "css=.btn-success", + "target": "css=#\\/metadataFilters\\/EntityRoleWhiteList\\/retainedRoles\\/1 > option:nth-child(1)", "targets": [ - ["css=.btn-success", "css:finder"], - ["xpath=//array-component/div/div/button", "xpath:position"], - ["xpath=//button[contains(.,'Add   ')]", "xpath:innerText"] + ["css=#\\/metadataFilters\\/EntityRoleWhiteList\\/retainedRoles\\/1 > option:nth-child(1)", "css:finder"], + ["xpath=(//option[@value=''])[2]", "xpath:attributes"], + ["xpath=//select[@id='/metadataFilters/EntityRoleWhiteList/retainedRoles/1']/option", "xpath:idRelative"], + ["xpath=//li[2]/div/sf-form-element/div/sf-widget-chooser/select-component/div/select/option", "xpath:position"] ], "value": "" }, { - "id": "0916f6d6-c3b9-489b-bb35-7295feaf9319", + "id": "f366c86c-1420-4fb7-86c2-82c49d81208d", "comment": "", "command": "select", - "target": "id=field34", + "target": "id=/metadataFilters/EntityRoleWhiteList/retainedRoles/1", "targets": [], "value": "label=AttributeAuthorityDescriptor" }, { - "id": "6e2b28ee-0c2c-4103-a9eb-7945964c4c49", - "comment": "", - "command": "click", - "target": "css=#field34 > option:nth-child(3)", - "targets": [ - ["css=#field34 > option:nth-child(3)", "css:finder"], - ["xpath=(//option[@value='2: md:AttributeAuthorityDescriptor'])[2]", "xpath:attributes"], - ["xpath=//select[@id='field34']/option[3]", "xpath:idRelative"], - ["xpath=//li[2]/div/sf-form-element/div/sf-widget-chooser/select-component/div/select/option[3]", "xpath:position"] - ], - "value": "" - }, { - "id": "ed96b46a-2e89-427a-85d8-4017b4ea3270", + "id": "5dfac033-ecfd-42e8-aa6f-931d5acd4d89", "comment": "", "command": "click", - "target": "css=.btn-success > translate-i18n", + "target": "css=div:nth-child(2) > sf-form-element > .has-success > sf-widget-chooser > checkbox-component .custom-control-label", "targets": [ - ["css=.btn-success > translate-i18n", "css:finder"], - ["xpath=//div/button/translate-i18n", "xpath:position"] + ["css=div:nth-child(2) > sf-form-element > .has-success > sf-widget-chooser > checkbox-component .custom-control-label", "css:finder"], + ["xpath=//div[2]/sf-form-element/div/sf-widget-chooser/checkbox-component/div/div/div/label", "xpath:position"], + ["xpath=//label[contains(.,'Remove Roleless Entity Descriptors?')]", "xpath:innerText"] ], "value": "" }, { - "id": "bfe30b75-f75f-4562-af7b-832b8639352e", + "id": "9d5934f0-fe10-4539-9d71-80b454fc8612", "comment": "", "command": "click", - "target": "css=#field35 > option:nth-child(1)", + "target": "css=div:nth-child(3) > sf-form-element > .has-success > sf-widget-chooser > checkbox-component .custom-control-label", "targets": [ - ["css=#field35 > option:nth-child(1)", "css:finder"], - ["xpath=(//option[@value=''])[3]", "xpath:attributes"], - ["xpath=//select[@id='field35']/option", "xpath:idRelative"], - ["xpath=//li[3]/div/sf-form-element/div/sf-widget-chooser/select-component/div/select/option", "xpath:position"] + ["css=div:nth-child(3) > sf-form-element > .has-success > sf-widget-chooser > checkbox-component .custom-control-label", "css:finder"], + ["xpath=//div[3]/sf-form-element/div/sf-widget-chooser/checkbox-component/div/div/div/label", "xpath:position"], + ["xpath=//label[contains(.,'Remove Empty Entities Descriptors?')]", "xpath:innerText"] ], "value": "" }, { - "id": "fff0c88e-8554-48b7-9ad4-ac9128afd708", - "comment": "", - "command": "select", - "target": "id=field35", - "targets": [], - "value": "label=SPSSODescriptor" - }, { - "id": "d0a966a9-f97d-4d36-b0de-e06872ad7fcd", + "id": "530234cd-ec70-48f2-9cc6-9e0d848c4b82", "comment": "", "command": "click", - "target": "css=.mt-2:nth-child(3) .fa", + "target": "css=.next", "targets": [ - ["css=.mt-2:nth-child(3) .fa", "css:finder"], - ["xpath=//li[3]/div/div/button/i", "xpath:position"] + ["css=.next", "css:finder"], + ["xpath=//li[3]/button", "xpath:position"] ], "value": "" }, { - "id": "b6471365-3d66-482f-9258-4eb6feed4192", + "id": "79b96f40-2677-438a-9564-62df0ea2c116", "comment": "", "command": "click", - "target": "css=.label:nth-child(1)", - "targets": [ - ["css=.label:nth-child(1)", "css:finder"], - ["xpath=//li[3]/button/span", "xpath:position"] - ], + "target": "css=.custom-control-label", + "targets": [], "value": "" }, { - "id": "b22efa37-3c12-40ac-a43d-e3349d68a45d", + "id": "52f5680c-c63d-411e-8332-52901f12ea3b", "comment": "", - "command": "click", - "target": "css=.custom-control-label", + "command": "verifyText", + "target": "css=.px-3:nth-child(1) > summary-property:nth-child(2) > .mb-3 > .d-block:nth-child(2)", "targets": [ - ["css=.custom-control-label", "css:finder"], - ["xpath=//label", "xpath:position"], - ["xpath=//label[contains(.,'Enable this service?')]", "xpath:innerText"] + ["css=.px-3:nth-child(1) > summary-property:nth-child(2) > .mb-3 > .d-block:nth-child(2)", "css:finder"], + ["xpath=//summary-property/div/span", "xpath:position"], + ["xpath=//span[contains(.,'Test Metadata Provider')]", "xpath:innerText"] ], - "value": "" + "value": "Test Metadata Provider" }, { - "id": "52298de6-ba25-4eb7-a8c8-e358662b9745", + "id": "67ff44aa-1efd-4b13-a0e9-3648a09911dd", "comment": "", "command": "verifyText", "target": "css=.px-3:nth-child(2) > summary-property:nth-child(2) > .mb-3 > .d-block:nth-child(2)", @@ -566,17 +489,6 @@ ["xpath=//span[contains(.,'123')]", "xpath:innerText"] ], "value": "123" - }, { - "id": "79b96f40-2677-438a-9564-62df0ea2c116", - "comment": "", - "command": "verifyText", - "target": "css=summary-property:nth-child(5) .d-block:nth-child(2)", - "targets": [ - ["css=summary-property:nth-child(5) .d-block:nth-child(2)", "css:finder"], - ["xpath=//summary-property[4]/div/span", "xpath:position"], - ["xpath=//span[contains(.,'%{idp.home}/foo.txt')]", "xpath:innerText"] - ], - "value": "%{idp.home}/foo.txt" }, { "id": "f5197d46-41a7-4ef2-ac40-19f80c953929", "comment": "", @@ -661,12 +573,12 @@ "id": "6437379e-d34f-479e-82f1-bf52654a95cb", "comment": "", "command": "click", - "target": "id=field39", + "target": "id=/name", "targets": [ - ["id=field39", "id"], - ["name=field39", "name"], - ["css=#field39", "css:finder"], - ["xpath=//input[@id='field39']", "xpath:attributes"], + ["id=/name", "id"], + ["name=field37", "name"], + ["css=#\\/name", "css:finder"], + ["xpath=//input[@id='/name']", "xpath:attributes"], ["xpath=//input", "xpath:position"] ], "value": "" @@ -674,7 +586,7 @@ "id": "79471f9f-e04f-4d98-8e78-f8f554d36821", "comment": "", "command": "type", - "target": "id=field39", + "target": "id=/name", "targets": [ ["id=field39", "id"], ["name=field39", "name"], @@ -687,22 +599,15 @@ "id": "90dffd02-8971-4bf5-bc57-33194fdb27a2", "comment": "", "command": "select", - "target": "id=field40", - "targets": [], - "value": "label=FileBackedHttpMetadataProvider" - }, { - "id": "4d07a76f-5d21-4ca7-b743-c74f35429c1e", - "comment": "", - "command": "click", - "target": "css=option:nth-child(2)", + "target": "id=/@type", "targets": [ - ["css=option:nth-child(2)", "css:finder"], - ["xpath=//option[@value='1: FileBackedHttpMetadataResolver']", "xpath:attributes"], - ["xpath=//select[@id='field40']/option[2]", "xpath:idRelative"], - ["xpath=//option[2]", "xpath:position"], - ["xpath=//option[contains(.,'FileBackedHttpMetadataProvider')]", "xpath:innerText"] + ["id=/@type", "id"], + ["name=field38", "name"], + ["css=#\\/\\@type", "css:finder"], + ["xpath=//select[@id='/@type']", "xpath:attributes"], + ["xpath=//select", "xpath:position"] ], - "value": "" + "value": "label=FileBackedHttpMetadataProvider" }, { "id": "48061ec7-f134-4cf4-aba6-4f62708a779a", "comment": "", @@ -717,12 +622,12 @@ "id": "5795f70f-79e1-4b45-9c38-ef96d5197e70", "comment": "", "command": "click", - "target": "id=field45", + "target": "id=/xmlId", "targets": [ - ["id=field45", "id"], - ["name=field45", "name"], - ["css=#field45", "css:finder"], - ["xpath=//input[@id='field45']", "xpath:attributes"], + ["id=/xmlId", "id"], + ["name=field43", "name"], + ["css=#\\/xmlId", "css:finder"], + ["xpath=//input[@id='/xmlId']", "xpath:attributes"], ["xpath=//input", "xpath:position"] ], "value": "" @@ -730,7 +635,7 @@ "id": "88a910a8-1e02-400a-9875-c76d0095aa57", "comment": "", "command": "type", - "target": "id=field45", + "target": "id=/xmlId", "targets": [ ["id=field45", "id"], ["name=field45", "name"], @@ -743,12 +648,12 @@ "id": "9dbebf86-2c5a-4c88-9fa8-437d4bea96e6", "comment": "", "command": "click", - "target": "id=field46", + "target": "id=/metadataURL", "targets": [ - ["id=field46", "id"], - ["name=field46", "name"], - ["css=#field46", "css:finder"], - ["xpath=//input[@id='field46']", "xpath:attributes"], + ["id=/metadataURL", "id"], + ["name=field44", "name"], + ["css=#\\/metadataURL", "css:finder"], + ["xpath=//input[@id='/metadataURL']", "xpath:attributes"], ["xpath=//div[2]/sf-form-element/div/sf-widget-chooser/custom-string/div/input", "xpath:position"] ], "value": "" @@ -756,7 +661,7 @@ "id": "b7e620be-7672-4d3a-8da7-e2b278747f44", "comment": "", "command": "type", - "target": "id=field46", + "target": "id=/metadataURL", "targets": [ ["id=field46", "id"], ["name=field46", "name"], @@ -769,11 +674,10 @@ "id": "d389f80c-4923-40ad-bdb6-f1142cb95a5e", "comment": "", "command": "click", - "target": "id=field47-1", + "target": "css=.form-check:nth-child(4) #\\/initializeFromBackupFile", "targets": [ - ["id=field47-1", "id"], - ["css=#field47-1", "css:finder"], - ["xpath=//input[@id='field47-1']", "xpath:attributes"], + ["css=.form-check:nth-child(4) #\\/initializeFromBackupFile", "css:finder"], + ["xpath=(//input[@id='/initializeFromBackupFile'])[2]", "xpath:attributes"], ["xpath=//div[2]/label/input", "xpath:position"] ], "value": "" @@ -781,12 +685,12 @@ "id": "4ce6d583-aadc-44b4-a694-92ca75a07e31", "comment": "", "command": "click", - "target": "id=field48", + "target": "id=/backingFile", "targets": [ - ["id=field48", "id"], - ["name=field48", "name"], - ["css=#field48", "css:finder"], - ["xpath=//input[@id='field48']", "xpath:attributes"], + ["id=/backingFile", "id"], + ["name=field46", "name"], + ["css=#\\/backingFile", "css:finder"], + ["xpath=//input[@id='/backingFile']", "xpath:attributes"], ["xpath=//div[4]/sf-form-element/div/sf-widget-chooser/custom-string/div/input", "xpath:position"] ], "value": "" @@ -794,7 +698,7 @@ "id": "206dd1e2-1c91-4c92-a99d-b938560d726c", "comment": "", "command": "type", - "target": "id=field48", + "target": "id=/backingFile", "targets": [ ["id=field48", "id"], ["name=field48", "name"], @@ -803,19 +707,6 @@ ["xpath=//div[4]/sf-form-element/div/sf-widget-chooser/custom-string/div/input", "xpath:position"] ], "value": "%{idp.home}/foo.txt" - }, { - "id": "8643497f-d718-4b33-bd47-510ca49aec01", - "comment": "", - "command": "click", - "target": "id=field49", - "targets": [ - ["id=field49", "id"], - ["css=#field49", "css:finder"], - ["xpath=//input[@id='field49']", "xpath:attributes"], - ["xpath=//div[@id='field49-container']/div/input", "xpath:idRelative"], - ["xpath=//div/div/input", "xpath:position"] - ], - "value": "" }, { "id": "43dcf85f-0606-4177-aced-a1817aa2bd05", "comment": "", @@ -831,14 +722,14 @@ "id": "38816b0f-9f4d-46d2-b900-937503ef93a0", "comment": "", "command": "click", - "target": "id=field49__option--3", + "target": "id=/backupFileInitNextRefreshDelay__option--2", "targets": [ - ["id=field49__option--3", "id"], - ["css=#field49__option--3", "css:finder"], - ["xpath=//li[@id='field49__option--3']", "xpath:attributes"], - ["xpath=//ul[@id='field49__listbox']/li[4]", "xpath:idRelative"], - ["xpath=//li[4]", "xpath:position"], - ["xpath=//li[contains(.,'PT10M')]", "xpath:innerText"] + ["id=/backupFileInitNextRefreshDelay__option--2", "id"], + ["css=#\\/backupFileInitNextRefreshDelay__option--2", "css:finder"], + ["xpath=//li[@id='/backupFileInitNextRefreshDelay__option--2']", "xpath:attributes"], + ["xpath=//ul[@id='/backupFileInitNextRefreshDelay__listbox']/li[3]", "xpath:idRelative"], + ["xpath=//auto-complete/div/ul/li[3]", "xpath:position"], + ["xpath=//li[contains(.,'PT1M')]", "xpath:innerText"] ], "value": "" }, { @@ -855,10 +746,10 @@ "id": "bcbc4aaf-e8f6-4369-b6aa-e33c0d9dddf1", "comment": "", "command": "click", - "target": "css=.label:nth-child(1)", + "target": "css=.next", "targets": [ - ["css=.label:nth-child(1)", "css:finder"], - ["xpath=//li[3]/button/span", "xpath:position"] + ["css=.next", "css:finder"], + ["xpath=//li[3]/button", "xpath:position"] ], "value": "" }, { @@ -873,7 +764,7 @@ ], "value": "" }, { - "id": "337993b0-4e0e-4f64-b962-8c46d748ea28", + "id": "fdec5198-73f6-43d1-a16a-55686cb68efa", "comment": "", "command": "click", "target": "css=.next", @@ -883,18 +774,7 @@ ], "value": "" }, { - "id": "14fb1ff6-9d74-4af2-b732-d237e7e0b03c", - "comment": "", - "command": "click", - "target": "css=.custom-control-label", - "targets": [ - ["css=.custom-control-label", "css:finder"], - ["xpath=//label", "xpath:position"], - ["xpath=//label[contains(.,'Enable this service?')]", "xpath:innerText"] - ], - "value": "" - }, { - "id": "fdec5198-73f6-43d1-a16a-55686cb68efa", + "id": "1237c623-a944-4525-9aea-b93fdd007f78", "comment": "", "command": "click", "target": "css=.save", @@ -911,7 +791,21 @@ "targets": [], "value": "10000" }, { - "id": "f72a2169-08f3-4d7e-b814-bf6a61ffd6c9", + "id": "b437068f-d3ed-43b5-9975-fb54decaf7ab", + "comment": "", + "command": "verifyText", + "target": "linkText=Test Metadata Provider", + "targets": [ + ["linkText=Test Metadata Provider", "linkText"], + ["css=tr:nth-child(1) a", "css:finder"], + ["xpath=//a[contains(text(),'Test Metadata Provider')]", "xpath:link"], + ["xpath=//a[contains(@href, '/metadata/provider/e69cdb37-d020-4e34-9a11-fad3a9cb5256/configuration/options')]", "xpath:href"], + ["xpath=//td[2]/a", "xpath:position"], + ["xpath=//a[contains(.,'Test Metadata Provider')]", "xpath:innerText"] + ], + "value": "Test Metadata Provider" + }, { + "id": "abf5ec9e-eeb3-480f-8919-1efecbae20d0", "comment": "", "command": "verifyText", "target": "linkText=Test Provider 2", @@ -919,23 +813,13 @@ ["linkText=Test Provider 2", "linkText"], ["css=tr:nth-child(2) a", "css:finder"], ["xpath=//a[contains(text(),'Test Provider 2')]", "xpath:link"], - ["xpath=(//a[contains(@href, '')])[11]", "xpath:href"], + ["xpath=//a[contains(@href, '/metadata/provider/4d34b788-8b81-43bb-aac6-2062bd067cff/configuration/options')]", "xpath:href"], ["xpath=//tr[2]/td[2]/a", "xpath:position"], ["xpath=//a[contains(.,'Test Provider 2')]", "xpath:innerText"] ], "value": "Test Provider 2" }, { - "id": "190a5481-53b9-464b-9acb-f00165c79a54", - "comment": "", - "command": "verifyText", - "target": "css=tr:nth-child(2) .provider-index", - "targets": [ - ["css=tr:nth-child(2) .provider-index", "css:finder"], - ["xpath=//tr[2]/td/div/div", "xpath:position"] - ], - "value": "1" - }, { - "id": "a36771ab-07cc-4dd3-96c5-e40d002aef62", + "id": "b799fede-c85b-4bd3-8e03-347f8a7d188a", "comment": "", "command": "click", "target": "css=tr:nth-child(2) .fa-chevron-circle-up", @@ -945,63 +829,35 @@ ], "value": "" }, { - "id": "2fbec171-a254-4282-b46a-367e47c108c9", - "comment": "", - "command": "verifyText", - "target": "linkText=Test Metadata Provider", - "targets": [ - ["linkText=Test Metadata Provider", "linkText"], - ["css=tr:nth-child(2) a", "css:finder"], - ["xpath=//a[contains(text(),'Test Metadata Provider')]", "xpath:link"], - ["xpath=(//a[contains(@href, '')])[11]", "xpath:href"], - ["xpath=//tr[2]/td[2]/a", "xpath:position"], - ["xpath=//a[contains(.,'Test Metadata Provider')]", "xpath:innerText"] - ], - "value": "Test Metadata Provider" - }, { - "id": "fadffda3-b2a4-4006-8f57-83ec5c8d9e4f", + "id": "72123a28-c3be-478c-8f30-555e346837e2", "comment": "", "command": "verifyText", - "target": "css=tr:nth-child(2) .provider-index", + "target": "css=.badge-success > span", "targets": [ - ["css=tr:nth-child(2) .provider-index", "css:finder"], - ["xpath=//tr[2]/td/div/div", "xpath:position"] + ["css=.badge-success > span", "css:finder"], + ["xpath=//tr[2]/td[6]/span/span", "xpath:position"] ], - "value": "1" + "value": "Enabled" }, { - "id": "06bd511e-5561-4521-a330-defb05a26ea1", + "id": "664aafa3-9f6f-4eab-9eb6-a4d1a8344c5c", "comment": "", "command": "click", - "target": "css=tr:nth-child(1) .fa-chevron-circle-down", + "target": "css=tr:nth-child(2) .fa-chevron-circle-up", "targets": [ - ["css=tr:nth-child(1) .fa-chevron-circle-down", "css:finder"], - ["xpath=//div/button/i", "xpath:position"] + ["css=tr:nth-child(2) .fa-chevron-circle-up", "css:finder"], + ["xpath=//tr[2]/td/div/button[2]/i", "xpath:position"] ], "value": "" }, { - "id": "de6477a2-4738-4852-a7ba-89ee9b494012", - "comment": "", - "command": "verifyText", - "target": "linkText=Test Provider 2", - "targets": [ - ["linkText=Test Provider 2", "linkText"], - ["css=tr:nth-child(2) a", "css:finder"], - ["xpath=//a[contains(text(),'Test Provider 2')]", "xpath:link"], - ["xpath=(//a[contains(@href, '')])[11]", "xpath:href"], - ["xpath=//tr[2]/td[2]/a", "xpath:position"], - ["xpath=//a[contains(.,'Test Provider 2')]", "xpath:innerText"] - ], - "value": "Test Provider 2" - }, { - "id": "17aebc64-35c8-40e7-8bda-e8fee86d8464", + "id": "ad8842de-2a4c-42a4-b919-dd7524a679c6", "comment": "", "command": "verifyText", - "target": "css=tr:nth-child(2) .provider-index", + "target": "css=.badge-danger > span", "targets": [ - ["css=tr:nth-child(2) .provider-index", "css:finder"], - ["xpath=//tr[2]/td/div/div", "xpath:position"] + ["css=.badge-danger > span", "css:finder"], + ["xpath=//tr[2]/td[6]/span/span", "xpath:position"] ], - "value": "1" + "value": "Disabled" }] }], "suites": [{ diff --git a/backend/src/integration/resources/SHIBUI-950.side b/backend/src/integration/resources/SHIBUI-950.side index 9e9eee1a2..0410a5155 100644 --- a/backend/src/integration/resources/SHIBUI-950.side +++ b/backend/src/integration/resources/SHIBUI-950.side @@ -127,29 +127,22 @@ "id": "67ad4a51-7c15-41e1-bc34-62a9f3e83b46", "comment": "", "command": "click", - "target": "css=.direction", + "target": "css=.next", "targets": [ - ["css=.direction", "css:finder"], - ["xpath=//span[2]", "xpath:position"] - ], - "value": "" - }, { - "id": "6b05d265-a392-4fe4-ad3f-9b4da12ca2d2", - "comment": "", - "command": "click", - "target": "css=td:nth-child(2)", - "targets": [ - ["css=td:nth-child(2)", "css:finder"], - ["xpath=//td[2]", "xpath:position"], - ["xpath=//td[contains(.,'https://wiki.shibboleth.net/shibboleth')]", "xpath:innerText"] + ["css=.next", "css:finder"], + ["xpath=//li[2]/button", "xpath:position"] ], "value": "" }, { "id": "cf4285d3-6f70-499e-ad3a-85278e27dbf0", "comment": "", "command": "waitForElementVisible", - "target": "css=.badge", - "targets": [], + "target": "css=tr > .text-right", + "targets": [ + ["css=tr > .text-right", "css:finder"], + ["xpath=//td[5]", "xpath:position"], + ["xpath=//td[contains(.,'Disabled')]", "xpath:innerText"] + ], "value": "10000" }, { "id": "185696df-a872-419e-81aa-7c9cfa1e2b90", diff --git a/backend/src/main/resources/entity-attributes-filters-ui-schema.json b/backend/src/main/resources/entity-attributes-filters-ui-schema.json index d67364b21..c7bb95b1a 100644 --- a/backend/src/main/resources/entity-attributes-filters-ui-schema.json +++ b/backend/src/main/resources/entity-attributes-filters-ui-schema.json @@ -46,7 +46,7 @@ }, "properties": { "entityAttributesFilterTargetType": { - "title": "", + "title": "label.filter-target-type", "type": "string", "default": "ENTITY", "oneOf": [ @@ -71,6 +71,7 @@ ] }, "value": { + "title": "label.filter-target-value", "type": "array", "buttons": [ { diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties index f3054d636..90edf9bc7 100644 --- a/backend/src/main/resources/i18n/messages.properties +++ b/backend/src/main/resources/i18n/messages.properties @@ -41,6 +41,7 @@ action.copy=Copy action.choose-file=Choose File action.search-by=Search By action.preview=Preview +action.preview-xml=Preview XML action.select-metadata-filter-type=Select a metadata filter type action.add-authentication-method=Add Authentication Method action.move-up=Move Up @@ -51,6 +52,9 @@ action.manage-filters=Manage Filters action.version-history=Version History action.options=Options action.xml=XML +action.manage=Manage +action.close=Close +action.back-to-top=Back to Top value.enabled=Enabled value.disabled=Disabled @@ -239,7 +243,11 @@ label.filter-name=Filter Name label.filter-enabled=Filter Enabled label.filter-target=FilterTarget label.filter-type=Filter Type +label.filter-target-type=Filter Target Type +label.filter-target-value=Filter Target Value +label.target=Filter Target label.option=Option +label.options=Options label.value=Value label.binding-type=Binding Type label.sign-assertion=Sign Assertions @@ -261,6 +269,8 @@ label.make-default=Make Default label.metadata-provider-name-dashboard-display-only=Metadata Provider Name (Dashboard Display Only) label.default-authentication-methods=Default Authentication Method(s) label.new-of-type=New { type } +label.filters=Filters +label.attributes=Attributes label.metadata-filter-name=Metadata Filter Name (Dashboard Display Only) label.filter-enable=Enable this Filter? @@ -458,6 +468,9 @@ message.required-for-regex=Required for Regex message.file-doesnt-exist=The requested file to be processed does not exist on the server. message.database-constraint=There was a database constraint problem processing the request. Check the request to ensure that fields that must be unique are truly unique. +message.no-filters=No Filters +message.no-filters-added=No filters have been added to this Metadata Provider + tooltip.entity-id=Entity ID tooltip.service-provider-name=Service Provider Name (Dashboard Display Only) tooltip.force-authn=Disallows use (or reuse) of authentication results and login flows that don\u0027t provide a real-time proof of user presence in the login process diff --git a/ui/package-lock.json b/ui/package-lock.json index 25fad932c..4595deae4 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -3511,7 +3511,6 @@ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, - "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -6468,8 +6467,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -6490,14 +6488,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6512,20 +6508,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -6642,8 +6635,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -6655,7 +6647,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6670,7 +6661,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6678,14 +6668,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6704,7 +6692,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -6785,8 +6772,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -6798,7 +6784,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -6884,8 +6869,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -6921,7 +6905,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6941,7 +6924,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6985,14 +6967,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -9302,8 +9282,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", - "dev": true, - "optional": true + "dev": true }, "http-signature": { "version": "1.2.0", @@ -9545,8 +9524,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true, - "optional": true + "dev": true }, "loose-envify": { "version": "1.3.1", @@ -10204,17 +10182,18 @@ } }, "ngx-schema-form": { - "version": "2.2.0-beta.1", - "resolved": "https://registry.npmjs.org/ngx-schema-form/-/ngx-schema-form-2.2.0-beta.1.tgz", - "integrity": "sha512-tNJR/rFEU2zHAOKOl47ujqM/7y08x8slPYyozgUgKt6aJa5JATqzf2Ee0WAF0fYrJzN4diF1fpNWHYqoA3qDGg==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/ngx-schema-form/-/ngx-schema-form-2.3.5.tgz", + "integrity": "sha512-MAenwMUhY/Mi4OuDOzeo+l5iBScIQ5e6q4V+pRanvlGWkNXrvVaDIzEUxs6XHiYSe1s3q9qJsEJQU++WUpVjgA==", "requires": { - "tslib": "^1.9.0" + "tslib": "^1.9.0", + "z-schema": "^3.17.0" }, "dependencies": { "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" } } }, diff --git a/ui/package.json b/ui/package.json index b293be085..ced90da0f 100644 --- a/ui/package.json +++ b/ui/package.json @@ -44,7 +44,7 @@ "file-saver": "^1.3.3", "font-awesome": "^4.7.0", "ngx-infinite-scroll": "^7.2.0", - "ngx-schema-form": "^2.2.0-beta.1", + "ngx-schema-form": "2.3.5", "rxjs": "^6.5.1", "rxjs-compat": "^6.5.1", "xml-formatter": "^1.0.1", diff --git a/ui/src/app/app.routing.ts b/ui/src/app/app.routing.ts index 99b8d88de..34ad45010 100644 --- a/ui/src/app/app.routing.ts +++ b/ui/src/app/app.routing.ts @@ -15,7 +15,8 @@ const routes: Routes = [ @NgModule({ imports: [RouterModule.forRoot(routes, { - preloadingStrategy: PreloadAllModules + preloadingStrategy: PreloadAllModules, + scrollOffset: [0, 64] })], exports: [RouterModule] }) diff --git a/ui/src/app/core/reducer/configuration.reducer.spec.ts b/ui/src/app/core/reducer/configuration.reducer.spec.ts new file mode 100644 index 000000000..e8e8a802e --- /dev/null +++ b/ui/src/app/core/reducer/configuration.reducer.spec.ts @@ -0,0 +1,35 @@ +import { reducer } from './configuration.reducer'; +import * as fromConfiguration from './configuration.reducer'; +import * as actions from '../action/configuration.action'; + +describe('Configuration Reducer', () => { + const initialState: fromConfiguration.ConfigState = { + roles: [] + }; + + describe('undefined action', () => { + it('should return the default state', () => { + const result = reducer(undefined, {} as any); + expect(result).toEqual(initialState); + }); + }); + + describe('Role Load Request', () => { + it('should set fetching to true', () => { + const action = new actions.LoadRoleSuccess(['ADMIN']); + const result = reducer(initialState, action); + expect(result).toEqual( + { + ...initialState, + roles: ['ADMIN'] + } + ); + }); + }); + + describe('selector functions', () => { + it('should return the roles from state', () => { + expect(fromConfiguration.getRoles(initialState)).toEqual([]); + }); + }); +}); diff --git a/ui/src/app/core/reducer/index.spec.ts b/ui/src/app/core/reducer/index.spec.ts index f14a08006..5a1fbef3e 100644 --- a/ui/src/app/core/reducer/index.spec.ts +++ b/ui/src/app/core/reducer/index.spec.ts @@ -10,7 +10,6 @@ describe('Core index reducers', () => { version: fromVersion.initialState as fromVersion.VersionState, config: fromConfig.initialState as fromConfig.ConfigState }; - describe('getUserStateFn function', () => { it('should return the user state', () => { expect(fromIndex.getUserStateFn(state)).toEqual(state.user); @@ -21,4 +20,21 @@ describe('Core index reducers', () => { expect(fromIndex.getVersionStateFn(state)).toEqual(state.version); }); }); + describe('getConfigStateFn function', () => { + it('should return the config state', () => { + expect(fromIndex.getConfigStateFn(state)).toEqual(state.config); + }); + }); + describe('filterRolesFn', () => { + it('should return the roles that are not `non roles`', () => { + expect(fromIndex.filterRolesFn(['ROLE_ADMIN', 'ROLE_NONE'])).toEqual(['ROLE_ADMIN']); + }); + }); + describe('isUserAdminFn', () => { + it('should check if the provided user has the ROLE_ADMIN role', () => { + expect(fromIndex.isUserAdminFn({role: 'ROLE_ADMIN'})).toBe(true); + expect(fromIndex.isUserAdminFn({role: 'ROLE_USER'})).toBe(false); + expect(fromIndex.isUserAdminFn(null)).toBe(false); + }); + }); }); diff --git a/ui/src/app/core/reducer/index.ts b/ui/src/app/core/reducer/index.ts index f2d64e934..f5e5b94c2 100644 --- a/ui/src/app/core/reducer/index.ts +++ b/ui/src/app/core/reducer/index.ts @@ -40,7 +40,7 @@ export const getVersionLoading = createSelector(getVersionState, fromVersion.get export const getVersionError = createSelector(getVersionState, fromVersion.getVersionError); export const filterRolesFn = (roles: string[]) => roles.filter(r => r !== 'ROLE_NONE'); -export const isUserAdminFn = (user) => user ? user.role === 'ROLE_ADMIN' : null; +export const isUserAdminFn = (user) => user ? user.role === 'ROLE_ADMIN' : false; export const getConfigState = createSelector(getCoreFeature, getConfigStateFn); export const getRoles = createSelector(getConfigState, fromConfig.getRoles); diff --git a/ui/src/app/metadata/configuration/action/compare.action.ts b/ui/src/app/metadata/configuration/action/compare.action.ts new file mode 100644 index 000000000..410a8dcab --- /dev/null +++ b/ui/src/app/metadata/configuration/action/compare.action.ts @@ -0,0 +1,47 @@ +import { Action } from '@ngrx/store'; +import { MetadataHistory } from '../model/history'; +import { MetadataVersion } from '../model/version'; +import { Metadata } from '../../domain/domain.type'; + +export enum CompareActionTypes { + COMPARE_METADATA_REQUEST = '[Compare Version] Compare Version Request', + COMPARE_METADATA_SUCCESS = '[Compare Version] Compare Version Success', + COMPARE_METADATA_ERROR = '[Compare Version] Compare Version Error', + SET_VERSIONS = '[Compare Version] Set Versions', + CLEAR_VERSIONS = '[Compare Version] Clear Versions' +} + +export class CompareVersionRequest implements Action { + readonly type = CompareActionTypes.COMPARE_METADATA_REQUEST; + + constructor(public payload: string[]) { } +} + +export class CompareVersionSuccess implements Action { + readonly type = CompareActionTypes.COMPARE_METADATA_SUCCESS; + + constructor(public payload: Metadata[]) { } +} + +export class CompareVersionError implements Action { + readonly type = CompareActionTypes.COMPARE_METADATA_ERROR; + + constructor(public payload: any) { } +} + +export class SetMetadataVersions implements Action { + readonly type = CompareActionTypes.SET_VERSIONS; + + constructor(public payload: Metadata[]) { } +} + +export class ClearVersions implements Action { + readonly type = CompareActionTypes.CLEAR_VERSIONS; +} + +export type CompareActionsUnion = + | CompareVersionRequest + | CompareVersionSuccess + | CompareVersionError + | SetMetadataVersions + | ClearVersions; diff --git a/ui/src/app/metadata/configuration/action/configuration.action.ts b/ui/src/app/metadata/configuration/action/configuration.action.ts index b5b86ade1..78e834eea 100644 --- a/ui/src/app/metadata/configuration/action/configuration.action.ts +++ b/ui/src/app/metadata/configuration/action/configuration.action.ts @@ -4,10 +4,6 @@ import { Schema } from '../model/schema'; import { Wizard } from '../../../wizard/model'; export enum ConfigurationActionTypes { - LOAD_METADATA_REQUEST = '[Metadata Configuration] Load Metadata Request', - LOAD_METADATA_SUCCESS = '[Metadata Configuration] Load Metadata Success', - LOAD_METADATA_ERROR = '[Metadata Configuration] Load Metadata Error', - LOAD_SCHEMA_REQUEST = '[Metadata Configuration] Load Schema Request', LOAD_SCHEMA_SUCCESS = '[Metadata Configuration] Load Schema Success', LOAD_SCHEMA_ERROR = '[Metadata Configuration] Load Schema Error', @@ -26,24 +22,6 @@ export enum ConfigurationActionTypes { CLEAR = '[Metadata Configuration] Clear' } -export class LoadMetadataRequest implements Action { - readonly type = ConfigurationActionTypes.LOAD_METADATA_REQUEST; - - constructor(public payload: { id: string, type: string }) { } -} - -export class LoadMetadataSuccess implements Action { - readonly type = ConfigurationActionTypes.LOAD_METADATA_SUCCESS; - - constructor(public payload: Metadata) { } -} - -export class LoadMetadataError implements Action { - readonly type = ConfigurationActionTypes.LOAD_METADATA_ERROR; - - constructor(public payload: any) { } -} - export class LoadSchemaRequest implements Action { readonly type = ConfigurationActionTypes.LOAD_SCHEMA_REQUEST; @@ -83,7 +61,7 @@ export class LoadXmlError implements Action { export class SetMetadata implements Action { readonly type = ConfigurationActionTypes.SET_METADATA; - constructor(public payload: Metadata) { } + constructor(public payload: { id: string, type: string }) { } } export class SetDefinition implements Action { @@ -113,9 +91,6 @@ export class ClearConfiguration implements Action { } export type ConfigurationActionsUnion = - | LoadMetadataRequest - | LoadMetadataSuccess - | LoadMetadataError | LoadSchemaRequest | LoadSchemaSuccess | LoadSchemaError diff --git a/ui/src/app/metadata/configuration/component/array-property.component.html b/ui/src/app/metadata/configuration/component/array-property.component.html index ee177445e..d51a8e0fb 100644 --- a/ui/src/app/metadata/configuration/component/array-property.component.html +++ b/ui/src/app/metadata/configuration/component/array-property.component.html @@ -1,22 +1,29 @@
-
{{ property.name }}
-
-
-
-
- {{ i + 1 }}.  - {{ property.items.properties[prop].title }} +
{{ property.name }}
+
+
+
+ {{ property.items.properties[prop].title }} +
+ +
+ {{ version[i][prop] }}
-
- {{ value[prop] }} +
+ -
-
+
- + @@ -24,28 +31,52 @@ -
- {{ attr.label }} -
- - true - - - false - +
+ +
+
+
+ {{ attr.label }} +
+ + true + + + false + +
-
- {{ property.name }} -

-
    -
  • - {{ item }} -
  • -
+
+ {{ property.name }} + +

-

+
    +
  • + +   + + {{ item }} +
  • +
+ +
    +
  • + {{ item }} +
  • +
+
+
\ No newline at end of file diff --git a/ui/src/app/metadata/configuration/component/configuration-property.component.html b/ui/src/app/metadata/configuration/component/array-property.component.scss similarity index 100% rename from ui/src/app/metadata/configuration/component/configuration-property.component.html rename to ui/src/app/metadata/configuration/component/array-property.component.scss diff --git a/ui/src/app/metadata/configuration/component/array-property.component.spec.ts b/ui/src/app/metadata/configuration/component/array-property.component.spec.ts index 453d9d484..614738b06 100644 --- a/ui/src/app/metadata/configuration/component/array-property.component.spec.ts +++ b/ui/src/app/metadata/configuration/component/array-property.component.spec.ts @@ -21,12 +21,12 @@ class TestHostComponent { @ViewChild(ArrayPropertyComponent) public componentUnderTest: ArrayPropertyComponent; - property: Property = getStepProperty(SCHEMA.properties.list, { + property: Property = getStepProperty(SCHEMA.properties.list, [{ name: 'foo', type: 'baz', description: 'foo bar baz', list: [] - }, SCHEMA.definitions); + }], SCHEMA.definitions); setProperty(property: Property): void { this.property = property; diff --git a/ui/src/app/metadata/configuration/component/array-property.component.ts b/ui/src/app/metadata/configuration/component/array-property.component.ts index ff9cd0ac4..a17ad01da 100644 --- a/ui/src/app/metadata/configuration/component/array-property.component.ts +++ b/ui/src/app/metadata/configuration/component/array-property.component.ts @@ -1,24 +1,38 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, OnChanges, Output, EventEmitter } from '@angular/core'; import { Property } from '../../domain/model/property'; import { Observable, of } from 'rxjs'; import { AttributesService } from '../../domain/service/attributes.service'; import { ConfigurationPropertyComponent } from './configuration-property.component'; +import UriValidator from '../../../shared/validation/uri.validator'; @Component({ selector: 'array-property', templateUrl: './array-property.component.html', - styleUrls: [] + styleUrls: ['./array-property.component.scss'] }) -export class ArrayPropertyComponent extends ConfigurationPropertyComponent { +export class ArrayPropertyComponent extends ConfigurationPropertyComponent implements OnChanges { @Input() property: Property; + @Output() preview: EventEmitter = new EventEmitter(); + + range = []; + constructor( private attrService: AttributesService ) { super(); } + ngOnChanges(): void { + const keys = this.property.value.reduce((val, version) => version ? version.length > val ? version.length : val : val, 0); + this.range = [...Array(keys).keys()]; + } + + isUrl(str: string): boolean { + return UriValidator.isUri(str); + } + get attributeList$(): Observable<{ key: string, label: string }[]> { if (this.property.widget && this.property.widget.hasOwnProperty('data')) { return of(this.property.widget.data); diff --git a/ui/src/app/metadata/configuration/component/configuration-property.component.spec.ts b/ui/src/app/metadata/configuration/component/configuration-property.component.spec.ts index 5ef0452e0..aa7fd9478 100644 --- a/ui/src/app/metadata/configuration/component/configuration-property.component.spec.ts +++ b/ui/src/app/metadata/configuration/component/configuration-property.component.spec.ts @@ -62,7 +62,8 @@ describe('Configuration Property Component', () => { describe('getItemType method', () => { it('should return the item`s type', () => { - expect(app.getItemType({ widget: { id: 'string' } } as Property)).toBe('string'); + expect(app.getItemType({items: { widget: { id: 'string' } } } as Property)).toBe('string'); + expect(app.getItemType({items: {}} as Property)).toBe('default'); expect(app.getItemType({} as Property)).toBe('default'); }); }); diff --git a/ui/src/app/metadata/configuration/component/configuration-property.component.ts b/ui/src/app/metadata/configuration/component/configuration-property.component.ts index bcdd45711..5418bde30 100644 --- a/ui/src/app/metadata/configuration/component/configuration-property.component.ts +++ b/ui/src/app/metadata/configuration/component/configuration-property.component.ts @@ -3,12 +3,12 @@ import { Property } from '../../domain/model/property'; @Component({ selector: 'configuration-property', - template: `{{ property | json }}`, - styleUrls: [] + template: `{{ property | json }}` }) export class ConfigurationPropertyComponent { @Input() property: Property; + @Input() columns = 1; constructor() { } @@ -16,8 +16,14 @@ export class ConfigurationPropertyComponent { return Object.keys(schema.properties); } - getItemType(items: Property): string { - return items.widget ? items.widget.id : 'default'; + getItemType(property: Property): string { + const items = property.items; + const def = 'default'; + return items ? items.widget ? items.widget.id : def : def; + } + + get width(): string { + return `${ Math.floor(100 / (this.columns + 1)) }%`; } } diff --git a/ui/src/app/metadata/configuration/component/filter-configuration-list-item.component.html b/ui/src/app/metadata/configuration/component/filter-configuration-list-item.component.html new file mode 100644 index 000000000..b8df62a11 --- /dev/null +++ b/ui/src/app/metadata/configuration/component/filter-configuration-list-item.component.html @@ -0,0 +1,47 @@ +
+ {{ index + 1 }} +
+ + +
+ + {{ filter['@type'] }} + + Enabled + Disabled + +
+
+
+
+
+ +   + Edit + + +
+
+ + +
\ No newline at end of file diff --git a/ui/src/app/metadata/configuration/component/filter-configuration-list-item.component.ts b/ui/src/app/metadata/configuration/component/filter-configuration-list-item.component.ts new file mode 100644 index 000000000..ede42a55a --- /dev/null +++ b/ui/src/app/metadata/configuration/component/filter-configuration-list-item.component.ts @@ -0,0 +1,52 @@ +import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { MetadataFilter } from '../../domain/model'; +import { MetadataConfigurationService } from '../service/configuration.service'; +import { MetadataConfiguration } from '../model/metadata-configuration'; +import { PreviewEntity } from '../../domain/action/entity.action'; +import { Metadata } from '../../domain/domain.type'; +import * as fromRoot from '../../../app.reducer'; + +@Component({ + selector: 'filter-configuration-list-item', + templateUrl: './filter-configuration-list-item.component.html' +}) +export class FilterConfigurationListItemComponent implements OnChanges { + @Input() filter: MetadataFilter; + @Input() index: number; + @Input() isFirst: boolean; + @Input() isLast: boolean; + + @Output() onUpdateOrderUp: EventEmitter = new EventEmitter(); + @Output() onUpdateOrderDown: EventEmitter = new EventEmitter(); + @Output() onRemove: EventEmitter = new EventEmitter(); + + open = false; + configuration: MetadataConfiguration; + definition: any; + + constructor( + private configService: MetadataConfigurationService, + private store: Store + ) {} + + onPreview($event: { data: any, parent: Metadata }): void { + this.store.dispatch(new PreviewEntity({ + id: $event.data, + entity: this.definition.getEntity($event.parent) + })); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.filter) { + this.definition = this.configService.getDefinition(this.filter['@type']); + this.configService.loadSchema(this.definition.schema).subscribe(schema => { + this.configuration = this.configService.getMetadataConfiguration( + this.filter, + this.definition, + schema + ); + }); + } + } +} diff --git a/ui/src/app/metadata/configuration/component/filter-configuration-list.component.html b/ui/src/app/metadata/configuration/component/filter-configuration-list.component.html new file mode 100644 index 000000000..c49a7738c --- /dev/null +++ b/ui/src/app/metadata/configuration/component/filter-configuration-list.component.html @@ -0,0 +1,17 @@ +
    +
  • + +
  • +
+
+

No Filters

+

No filters have been added to this Metadata Provider

+
\ No newline at end of file diff --git a/ui/src/app/metadata/configuration/component/filter-configuration-list.component.ts b/ui/src/app/metadata/configuration/component/filter-configuration-list.component.ts new file mode 100644 index 000000000..5208a7f4c --- /dev/null +++ b/ui/src/app/metadata/configuration/component/filter-configuration-list.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; +import { FilterListComponent } from '../../filter/component/filter-list.component'; + +@Component({ + selector: 'filter-configuration-list', + templateUrl: './filter-configuration-list.component.html' +}) +export class FilterConfigurationListComponent extends FilterListComponent { } diff --git a/ui/src/app/metadata/configuration/component/filter-target-property.component.html b/ui/src/app/metadata/configuration/component/filter-target-property.component.html new file mode 100644 index 000000000..f8bfbb5c8 --- /dev/null +++ b/ui/src/app/metadata/configuration/component/filter-target-property.component.html @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/ui/src/app/metadata/configuration/component/filter-target-property.component.spec.ts b/ui/src/app/metadata/configuration/component/filter-target-property.component.spec.ts new file mode 100644 index 000000000..98c08d4c4 --- /dev/null +++ b/ui/src/app/metadata/configuration/component/filter-target-property.component.spec.ts @@ -0,0 +1,66 @@ +import { Component, ViewChild } from '@angular/core'; +import { TestBed, async, ComponentFixture } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; + +import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; +import { Property } from '../../domain/model/property'; +import { MockI18nModule } from '../../../../testing/i18n.stub'; +import { SCHEMA } from '../../../../testing/form-schema.stub'; +import { getStepProperty } from '../../domain/utility/configuration'; +import { FilterTargetPropertyComponent } from './filter-target-property.component'; +import { PrimitivePropertyComponent } from './primitive-property.component'; +import { ArrayPropertyComponentStub, PrimitivePropertyComponentStub } from '../../../../testing/property-component.stub'; +import { AttributesService } from '../../domain/service/attributes.service'; +import { of } from 'rxjs'; + +@Component({ + template: ` + + ` +}) +class TestHostComponent { + @ViewChild(FilterTargetPropertyComponent) + public componentUnderTest: FilterTargetPropertyComponent; + + property: Property = getStepProperty(SCHEMA.properties.formatFilterTarget, { + formatFilterTargetType: 'ENTITY_ID', + value: [ + 'foo', + 'bar', + 'baz' + ] + }, SCHEMA.definitions); +} + +describe('Filter Target Property Component', () => { + + let fixture: ComponentFixture; + let instance: TestHostComponent; + let app: FilterTargetPropertyComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + NgbPopoverModule, + MockI18nModule, + RouterTestingModule + ], + declarations: [ + FilterTargetPropertyComponent, + PrimitivePropertyComponentStub, + ArrayPropertyComponentStub, + TestHostComponent + ], + providers: [] + }).compileComponents(); + + fixture = TestBed.createComponent(TestHostComponent); + instance = fixture.componentInstance; + app = instance.componentUnderTest; + fixture.detectChanges(); + })); + + it('should accept a property input', async(() => { + expect(app).toBeTruthy(); + })); +}); diff --git a/ui/src/app/metadata/configuration/component/filter-target-property.component.ts b/ui/src/app/metadata/configuration/component/filter-target-property.component.ts new file mode 100644 index 000000000..6b7ebf216 --- /dev/null +++ b/ui/src/app/metadata/configuration/component/filter-target-property.component.ts @@ -0,0 +1,26 @@ +import { Component, Input, Output, EventEmitter } from '@angular/core'; +import { Property } from '../../domain/model/property'; +import { ConfigurationPropertyComponent } from './configuration-property.component'; + +@Component({ + selector: 'filter-target-property', + templateUrl: './filter-target-property.component.html', + styleUrls: [] +}) +export class FilterTargetPropertyComponent extends ConfigurationPropertyComponent { + @Input() parent: Property; + + @Output() preview: EventEmitter = new EventEmitter(); + + constructor() { + super(); + } + + onPreview(data: any) { + this.preview.emit({ + parent: this.parent, + data + }); + } +} + diff --git a/ui/src/app/metadata/configuration/component/history-list.component.html b/ui/src/app/metadata/configuration/component/history-list.component.html index 2983c151c..82a275060 100644 --- a/ui/src/app/metadata/configuration/component/history-list.component.html +++ b/ui/src/app/metadata/configuration/component/history-list.component.html @@ -21,9 +21,9 @@
- Current (v{{ i + 1 }}) - v{{ i + 1 }} - {{ version.date | date }} + Current (v{{ history.length - i }}) + v{{ history.length - (i) }} + {{ version.date | date:'medium' }} {{ version.creator }}
-
- Option - Value +
+
+ Option + + Value + {{ date | date:'medium' }} + +
+ +
-
-
+
\ No newline at end of file diff --git a/ui/src/app/metadata/configuration/component/metadata-configuration.component.spec.ts b/ui/src/app/metadata/configuration/component/metadata-configuration.component.spec.ts index f26c8d65c..c17a469af 100644 --- a/ui/src/app/metadata/configuration/component/metadata-configuration.component.spec.ts +++ b/ui/src/app/metadata/configuration/component/metadata-configuration.component.spec.ts @@ -7,6 +7,7 @@ import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; import { MetadataConfiguration } from '../model/metadata-configuration'; import { Property } from '../../domain/model/property'; import { MockI18nModule } from '../../../../testing/i18n.stub'; +import { Router } from '@angular/router'; @Component({ selector: 'object-property', @@ -14,6 +15,7 @@ import { MockI18nModule } from '../../../../testing/i18n.stub'; }) class ObjectPropertyComponent { @Input() property: Property; + @Input() columns = 1; } @Component({ @@ -25,7 +27,10 @@ class TestHostComponent { @ViewChild(MetadataConfigurationComponent) public componentUnderTest: MetadataConfigurationComponent; - configuration: MetadataConfiguration = {sections: []}; + configuration: MetadataConfiguration = { + dates: [], + sections: [] + }; } describe('Metadata Configuration Component', () => { @@ -33,6 +38,7 @@ describe('Metadata Configuration Component', () => { let fixture: ComponentFixture; let instance: TestHostComponent; let app: MetadataConfigurationComponent; + let router: Router; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -51,10 +57,36 @@ describe('Metadata Configuration Component', () => { fixture = TestBed.createComponent(TestHostComponent); instance = fixture.componentInstance; app = instance.componentUnderTest; + router = TestBed.get(Router); fixture.detectChanges(); })); it('should accept a configuration input', async(() => { expect(app).toBeTruthy(); })); + + describe('edit method', () => { + it('should call router.navigate', () => { + spyOn(router, 'navigate'); + app.edit('foo'); + expect(router.navigate).toHaveBeenCalled(); + }); + }); + + describe('width getter', () => { + it('should default to 100%', () => { + expect(app.width).toBe('100%'); + }); + it('should calculate the width based on dates', () => { + instance.configuration = { + ...instance.configuration, + dates: [ + new Date().toISOString(), + new Date().toISOString() + ] + }; + fixture.detectChanges(); + expect(app.width).toBe('33%'); + }); + }); }); diff --git a/ui/src/app/metadata/configuration/component/metadata-configuration.component.ts b/ui/src/app/metadata/configuration/component/metadata-configuration.component.ts index 9e94bcdbd..86e8bd23b 100644 --- a/ui/src/app/metadata/configuration/component/metadata-configuration.component.ts +++ b/ui/src/app/metadata/configuration/component/metadata-configuration.component.ts @@ -1,6 +1,7 @@ -import { Component, ChangeDetectionStrategy, Input } from '@angular/core'; +import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; import { MetadataConfiguration } from '../model/metadata-configuration'; +import { Metadata } from '../../domain/domain.type'; @Component({ selector: 'metadata-configuration', @@ -10,13 +11,28 @@ import { MetadataConfiguration } from '../model/metadata-configuration'; }) export class MetadataConfigurationComponent { @Input() configuration: MetadataConfiguration; + @Input() definition: any; + @Input() entity: Metadata; + @Input() numbered = true; + @Input() editable = true; + + @Output() preview: EventEmitter = new EventEmitter(); constructor( private router: Router, private activatedRoute: ActivatedRoute - ) { } + ) {} edit(id: string): void { this.router.navigate(['../', 'edit', id], { relativeTo: this.activatedRoute.parent }); } + + onPreview($event): void { + this.preview.emit($event); + } + + get width(): string { + const columns = this.configuration.dates.length; + return `${Math.floor(100 / (columns + 1)) }%`; + } } diff --git a/ui/src/app/metadata/configuration/component/object-property.component.html b/ui/src/app/metadata/configuration/component/object-property.component.html index b0aa7b967..e31da24ad 100644 --- a/ui/src/app/metadata/configuration/component/object-property.component.html +++ b/ui/src/app/metadata/configuration/component/object-property.component.html @@ -1,7 +1,17 @@ - - - + + + + + + + diff --git a/ui/src/app/metadata/configuration/component/object-property.component.spec.ts b/ui/src/app/metadata/configuration/component/object-property.component.spec.ts index 6299b20d5..8817711c9 100644 --- a/ui/src/app/metadata/configuration/component/object-property.component.spec.ts +++ b/ui/src/app/metadata/configuration/component/object-property.component.spec.ts @@ -1,15 +1,16 @@ -import { Component, ViewChild, Input } from '@angular/core'; +import { Component, ViewChild } from '@angular/core'; import { TestBed, async, ComponentFixture } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { NgbDropdownModule, NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; import { Property } from '../../domain/model/property'; import { MockI18nModule } from '../../../../testing/i18n.stub'; import { ObjectPropertyComponent } from './object-property.component'; import { SCHEMA } from '../../../../testing/form-schema.stub'; -import { getStepProperties, getStepProperty } from '../../domain/utility/configuration'; +import { getStepProperty } from '../../domain/utility/configuration'; import { PrimitivePropertyComponent } from './primitive-property.component'; import { ArrayPropertyComponent } from './array-property.component'; +import { FilterTargetPropertyComponent } from './filter-target-property.component'; @Component({ template: ` @@ -44,6 +45,7 @@ describe('Object Property Component', () => { ObjectPropertyComponent, PrimitivePropertyComponent, ArrayPropertyComponent, + FilterTargetPropertyComponent, TestHostComponent ] }).compileComponents(); diff --git a/ui/src/app/metadata/configuration/component/object-property.component.ts b/ui/src/app/metadata/configuration/component/object-property.component.ts index f7892877e..1fafafa25 100644 --- a/ui/src/app/metadata/configuration/component/object-property.component.ts +++ b/ui/src/app/metadata/configuration/component/object-property.component.ts @@ -1,4 +1,4 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, Output, EventEmitter } from '@angular/core'; import { Property } from '../../domain/model/property'; import { ConfigurationPropertyComponent } from './configuration-property.component'; @@ -10,6 +10,7 @@ import { ConfigurationPropertyComponent } from './configuration-property.compone export class ObjectPropertyComponent extends ConfigurationPropertyComponent { @Input() property: Property; + @Output() preview: EventEmitter = new EventEmitter(); constructor() { super(); diff --git a/ui/src/app/metadata/configuration/component/primitive-property.component.html b/ui/src/app/metadata/configuration/component/primitive-property.component.html index 9eef2181f..4d93c07cc 100644 --- a/ui/src/app/metadata/configuration/component/primitive-property.component.html +++ b/ui/src/app/metadata/configuration/component/primitive-property.component.html @@ -1,5 +1,10 @@ -
- {{ property.name }} - {{ property.value || property.value === false ? property.value : '-' }} +
+ {{ property.name }} + {{ v ? v : (v === false) ? v : '-' }}
\ No newline at end of file diff --git a/ui/src/app/metadata/configuration/component/primitive-property.component.ts b/ui/src/app/metadata/configuration/component/primitive-property.component.ts index 951d2c72a..e18b525af 100644 --- a/ui/src/app/metadata/configuration/component/primitive-property.component.ts +++ b/ui/src/app/metadata/configuration/component/primitive-property.component.ts @@ -6,7 +6,6 @@ import { ConfigurationPropertyComponent } from './configuration-property.compone templateUrl: './primitive-property.component.html', styleUrls: [] }) - export class PrimitivePropertyComponent extends ConfigurationPropertyComponent { constructor() { super(); diff --git a/ui/src/app/metadata/configuration/configuration.module.ts b/ui/src/app/metadata/configuration/configuration.module.ts index dc291952c..fa395529b 100644 --- a/ui/src/app/metadata/configuration/configuration.module.ts +++ b/ui/src/app/metadata/configuration/configuration.module.ts @@ -2,7 +2,7 @@ import { NgModule, ModuleWithProviders } from '@angular/core'; import { CommonModule } from '@angular/common'; import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; - +import { RouterModule } from '@angular/router'; import { NgbPopoverModule } from '@ng-bootstrap/ng-bootstrap'; import { I18nModule } from '../../i18n/i18n.module'; @@ -15,7 +15,6 @@ import { ConfigurationPropertyComponent } from './component/configuration-proper import { PrimitivePropertyComponent } from './component/primitive-property.component'; import { ObjectPropertyComponent } from './component/object-property.component'; import { ArrayPropertyComponent } from './component/array-property.component'; -import { RouterModule } from '@angular/router'; import { MetadataOptionsComponent } from './container/metadata-options.component'; import { MetadataXmlComponent } from './container/metadata-xml.component'; import { MetadataHeaderComponent } from './component/metadata-header.component'; @@ -24,6 +23,13 @@ import { MetadataHistoryService } from './service/history.service'; import { MetadataHistoryComponent } from './container/metadata-history.component'; import { HistoryListComponent } from './component/history-list.component'; import { DomainModule } from '../domain/domain.module'; +import { MetadataComparisonComponent } from './container/metadata-comparison.component'; +import { CompareVersionEffects } from './effect/compare.effect'; +import { FilterModule } from '../filter/filter.module'; +import { FilterConfigurationListComponent } from './component/filter-configuration-list.component'; +import { FilterConfigurationListItemComponent } from './component/filter-configuration-list-item.component'; +import { SharedModule } from '../../shared/shared.module'; +import { FilterTargetPropertyComponent } from './component/filter-target-property.component'; @NgModule({ declarations: [ @@ -37,7 +43,11 @@ import { DomainModule } from '../domain/domain.module'; ConfigurationComponent, MetadataHeaderComponent, MetadataHistoryComponent, - HistoryListComponent + HistoryListComponent, + MetadataComparisonComponent, + FilterConfigurationListComponent, + FilterConfigurationListItemComponent, + FilterTargetPropertyComponent ], entryComponents: [], imports: [ @@ -45,7 +55,9 @@ import { DomainModule } from '../domain/domain.module'; I18nModule, NgbPopoverModule, RouterModule, - DomainModule + DomainModule, + FilterModule, + SharedModule ], exports: [], providers: [] @@ -66,7 +78,12 @@ export class MetadataConfigurationModule { imports: [ MetadataConfigurationModule, StoreModule.forFeature('metadata-configuration', fromConfig.reducers), - EffectsModule.forFeature([MetadataConfigurationEffects, MetadataHistoryEffects]) + EffectsModule.forFeature( + [ + MetadataConfigurationEffects, + MetadataHistoryEffects, + CompareVersionEffects + ]) ], providers: [] }) diff --git a/ui/src/app/metadata/configuration/configuration.routing.ts b/ui/src/app/metadata/configuration/configuration.routing.ts index d27b29872..0a77b0c2b 100644 --- a/ui/src/app/metadata/configuration/configuration.routing.ts +++ b/ui/src/app/metadata/configuration/configuration.routing.ts @@ -3,6 +3,7 @@ import { ConfigurationComponent } from './container/configuration.component'; import { MetadataOptionsComponent } from './container/metadata-options.component'; import { MetadataXmlComponent } from './container/metadata-xml.component'; import { MetadataHistoryComponent } from './container/metadata-history.component'; +import { MetadataComparisonComponent } from './container/metadata-comparison.component'; export const ConfigurationRoutes: Routes = [ { @@ -24,6 +25,10 @@ export const ConfigurationRoutes: Routes = [ { path: 'history', component: MetadataHistoryComponent + }, + { + path: 'compare', + component: MetadataComparisonComponent } ] } diff --git a/ui/src/app/metadata/configuration/container/configuration.component.html b/ui/src/app/metadata/configuration/container/configuration.component.html index e4709611b..53f8fa697 100644 --- a/ui/src/app/metadata/configuration/container/configuration.component.html +++ b/ui/src/app/metadata/configuration/container/configuration.component.html @@ -13,8 +13,14 @@ -

Source Configuration

- +

+ Source + Provider + Configuration +

+ + +
\ No newline at end of file diff --git a/ui/src/app/metadata/configuration/container/configuration.component.spec.ts b/ui/src/app/metadata/configuration/container/configuration.component.spec.ts index c399fbacf..71bb05ab0 100644 --- a/ui/src/app/metadata/configuration/container/configuration.component.spec.ts +++ b/ui/src/app/metadata/configuration/container/configuration.component.spec.ts @@ -7,6 +7,8 @@ import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; import { MetadataConfiguration } from '../model/metadata-configuration'; import { ConfigurationComponent } from './configuration.component'; import * as fromConfiguration from '../reducer'; +import * as fromProviders from '../../provider/reducer'; +import * as fromResolvers from '../../resolver/reducer'; import { MockI18nModule } from '../../../../testing/i18n.stub'; @Component({ @@ -18,7 +20,10 @@ class TestHostComponent { @ViewChild(ConfigurationComponent) public componentUnderTest: ConfigurationComponent; - configuration: MetadataConfiguration = { sections: [] }; + configuration: MetadataConfiguration = { + dates: [], + sections: [] + }; } describe('Metadata Configuration Page Component', () => { @@ -33,6 +38,8 @@ describe('Metadata Configuration Page Component', () => { NgbDropdownModule, StoreModule.forRoot({ 'metadata-configuration': combineReducers(fromConfiguration.reducers), + 'provider': combineReducers(fromProviders.reducers), + 'resolver': combineReducers(fromResolvers.reducers) }), MockI18nModule, RouterTestingModule diff --git a/ui/src/app/metadata/configuration/container/configuration.component.ts b/ui/src/app/metadata/configuration/container/configuration.component.ts index 357d745fd..4c06d7f9d 100644 --- a/ui/src/app/metadata/configuration/container/configuration.component.ts +++ b/ui/src/app/metadata/configuration/container/configuration.component.ts @@ -1,14 +1,15 @@ -import { Component, ChangeDetectionStrategy, OnDestroy } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { takeUntil, map, withLatestFrom, filter } from 'rxjs/operators'; +import { Component, ChangeDetectionStrategy, OnDestroy, HostListener } from '@angular/core'; +import { ActivatedRoute, Router, Scroll, Event } from '@angular/router'; +import { takeUntil, map, withLatestFrom, filter, timeout, delay } from 'rxjs/operators'; import { Store } from '@ngrx/store'; -import { Observable, Subject } from 'rxjs'; +import { Observable, Subject, interval } from 'rxjs'; import * as fromConfiguration from '../reducer'; -import { LoadMetadataRequest, ClearConfiguration } from '../action/configuration.action'; +import { ClearConfiguration, SetMetadata } from '../action/configuration.action'; import { LoadHistoryRequest, ClearHistory, SelectVersion } from '../action/history.action'; import * as fromReducer from '../reducer'; +import { ViewportScroller } from '@angular/common'; @Component({ selector: 'configuration-page', @@ -20,6 +21,7 @@ export class ConfigurationComponent implements OnDestroy { private ngUnsubscribe: Subject = new Subject(); name$: Observable; + type$: Observable; constructor( private store: Store, @@ -27,7 +29,7 @@ export class ConfigurationComponent implements OnDestroy { ) { this.routerState.params.pipe( takeUntil(this.ngUnsubscribe), - map(params => new LoadMetadataRequest({id: params.id, type: params.type})) + map(params => new SetMetadata({id: params.id, type: params.type})) ).subscribe(store); this.routerState.params.pipe( @@ -52,12 +54,8 @@ export class ConfigurationComponent implements OnDestroy { } }); - this.name$ = this.store - .select(fromReducer.getConfigurationModel) - .pipe( - filter(model => !!model), - map(model => model ? ('serviceProviderName' in model) ? model.serviceProviderName : model.name : false) - ); + this.name$ = this.store.select(fromReducer.getConfigurationModelName); + this.type$ = this.store.select(fromReducer.getConfigurationModelType); } ngOnDestroy() { diff --git a/ui/src/app/metadata/configuration/container/metadata-comparison.component.html b/ui/src/app/metadata/configuration/container/metadata-comparison.component.html new file mode 100644 index 000000000..d5b533716 --- /dev/null +++ b/ui/src/app/metadata/configuration/container/metadata-comparison.component.html @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/ui/src/app/metadata/configuration/container/metadata-comparison.component.spec.ts b/ui/src/app/metadata/configuration/container/metadata-comparison.component.spec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/ui/src/app/metadata/configuration/container/metadata-comparison.component.ts b/ui/src/app/metadata/configuration/container/metadata-comparison.component.ts new file mode 100644 index 000000000..92019297d --- /dev/null +++ b/ui/src/app/metadata/configuration/container/metadata-comparison.component.ts @@ -0,0 +1,34 @@ +import { Component, ChangeDetectionStrategy } from '@angular/core'; +import { Observable } from 'rxjs'; +import { Store } from '@ngrx/store'; +import { ActivatedRoute } from '@angular/router'; +import { map } from 'rxjs/operators'; +import { ConfigurationState, getVersionConfigurations, getVersionConfigurationCount } from '../reducer'; +import { Metadata } from '../../domain/domain.type'; +import { CompareVersionRequest } from '../action/compare.action'; +import { MetadataConfiguration } from '../model/metadata-configuration'; + +@Component({ + selector: 'metadata-comparison', + changeDetection: ChangeDetectionStrategy.OnPush, + templateUrl: './metadata-comparison.component.html', + styleUrls: [] +}) +export class MetadataComparisonComponent { + + versions$: Observable; + numVersions$: Observable; + + constructor( + private store: Store, + private activatedRoute: ActivatedRoute + ) { + this.activatedRoute.queryParams.pipe( + map(params => params.versions), + map(versions => new CompareVersionRequest(versions)) + ).subscribe(this.store); + + this.versions$ = this.store.select(getVersionConfigurations); + this.numVersions$ = this.store.select(getVersionConfigurationCount); + } +} diff --git a/ui/src/app/metadata/configuration/container/metadata-history.component.html b/ui/src/app/metadata/configuration/container/metadata-history.component.html index 225912756..2bcc27fe5 100644 --- a/ui/src/app/metadata/configuration/container/metadata-history.component.html +++ b/ui/src/app/metadata/configuration/container/metadata-history.component.html @@ -1,3 +1,5 @@
- +
diff --git a/ui/src/app/metadata/configuration/container/metadata-history.component.spec.ts b/ui/src/app/metadata/configuration/container/metadata-history.component.spec.ts index 084d79ef0..4a322ee3c 100644 --- a/ui/src/app/metadata/configuration/container/metadata-history.component.spec.ts +++ b/ui/src/app/metadata/configuration/container/metadata-history.component.spec.ts @@ -8,14 +8,16 @@ import { MetadataHistoryService } from '../service/history.service'; import { of } from 'rxjs'; import { StoreModule, combineReducers } from '@ngrx/store'; import * as fromConfiguration from '../reducer'; +import { Router, ActivatedRoute } from '@angular/router'; +import { RouterStub } from '../../../../testing/router.stub'; +import { ActivatedRouteStub } from '../../../../testing/activated-route.stub'; export const TestData = { versions: [ { - versionNumber: 1, - saveDate: new Date(), - changedBy: 'admin', - actions: [] + id: '1', + date: new Date().toDateString(), + creator: 'admin' } ] }; @@ -37,12 +39,19 @@ const MockHistoryService = { describe('Metadata Version History Component', () => { let fixture: ComponentFixture; let instance: MetadataHistoryComponent; + let router: Router; beforeEach(() => { TestBed.configureTestingModule({ providers: [ { provide: MetadataHistoryService, useValue: MockHistoryService + }, + { + provide: Router, useClass: RouterStub + }, + { + provide: ActivatedRoute, useClass: ActivatedRouteStub } ], imports: [ @@ -59,10 +68,59 @@ describe('Metadata Version History Component', () => { fixture = TestBed.createComponent(MetadataHistoryComponent); instance = fixture.componentInstance; + router = TestBed.get(Router); + spyOn(router, 'navigate'); fixture.detectChanges(); }); it('should compile', () => { expect(instance).toBeDefined(); }); + + describe('compare versions method', () => { + it('should call the router.navigate method', () => { + instance.compareVersions(TestData.versions); + expect(router.navigate).toHaveBeenCalled(); + }); + }); + + describe('sortVersionsByDate method', () => { + it('should sort the versions by their date', () => { + const nowTime = new Date().getTime(); + const futureTime = nowTime + 10000; + const beforeTime = nowTime - 10000; + const nowDate = new Date(nowTime); + const futureDate = new Date(futureTime); + const beforeDate = new Date(beforeTime); + + const versions = [ + { + id: 'foo', + creator: 'bar', + date: nowDate.toISOString() + }, + { + id: 'bar', + creator: 'baz', + date: beforeDate.toISOString() + }, + { + id: 'baz', + creator: 'foo', + date: beforeDate.toISOString() + }, + { + id: 'baz2', + creator: 'foo', + date: futureDate.toISOString() + } + ]; + + const sorted = instance.sortVersionsByDate(versions); + expect(sorted[0].id).toEqual('baz2'); + expect(sorted[1].id).toEqual('foo'); + expect(sorted[2].id).toEqual('baz'); + expect(sorted[3].id).toEqual('bar'); + }); + }); }); diff --git a/ui/src/app/metadata/configuration/container/metadata-history.component.ts b/ui/src/app/metadata/configuration/container/metadata-history.component.ts index 6fb60bdb9..c49e0c70f 100644 --- a/ui/src/app/metadata/configuration/container/metadata-history.component.ts +++ b/ui/src/app/metadata/configuration/container/metadata-history.component.ts @@ -3,6 +3,9 @@ import { Observable } from 'rxjs'; import { Store } from '@ngrx/store'; import { ConfigurationState, getVersionCollection } from '../reducer'; import { MetadataVersion } from '../model/version'; +import { CompareVersionRequest } from '../action/compare.action'; +import { Router, ActivatedRoute } from '@angular/router'; +import { map } from 'rxjs/operators'; @Component({ selector: 'metadata-history', @@ -15,8 +18,30 @@ export class MetadataHistoryComponent { history$: Observable; constructor( - private store: Store + private store: Store, + private router: Router, + private route: ActivatedRoute ) { - this.history$ = this.store.select(getVersionCollection); + this.history$ = this.store.select(getVersionCollection) + .pipe(map(versions => this.sortVersionsByDate(versions))); + } + + sortVersionsByDate(versions: MetadataVersion[]): MetadataVersion[] { + return versions.sort((a, b) => { + const aDate = new Date(a.date).getTime(); + const bDate = new Date(b.date).getTime(); + return aDate === bDate ? 0 : aDate < bDate ? -1 : 1; + }).reverse(); + } + + compareVersions(versions: MetadataVersion[]): void { + const sorted = this.sortVersionsByDate(versions); + this.router.navigate( + ['../', 'compare'], + { + queryParams: { versions: sorted.map(v => v.id) }, + relativeTo: this.route + } + ); } } diff --git a/ui/src/app/metadata/configuration/container/metadata-options.component.html b/ui/src/app/metadata/configuration/container/metadata-options.component.html index 0825b10d4..d99166c11 100644 --- a/ui/src/app/metadata/configuration/container/metadata-options.component.html +++ b/ui/src/app/metadata/configuration/container/metadata-options.component.html @@ -1,20 +1,58 @@ -
+