Skip to content

Commit 9c0374b

Browse files
author
Saldatsenka, Siarhei
committed
Merge branch 'develop' into ELI-47-Transfer_LinkInspector_settings-to-granite-console
# Conflicts: # core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/resolvers/ExternalLinkResolverImpl.java # core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/resolvers/InternalLinkResolverImpl.java
2 parents 52bb47e + 533b54f commit 9c0374b

File tree

10 files changed

+133
-66
lines changed

10 files changed

+133
-66
lines changed

core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/resolvers/ExternalLinkResolverImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
/**
5656
* Validates external links via sending HEAD requests concurrently using {@link PoolingHttpClientConnectionManager}
5757
*/
58-
@Component(service = {LinkResolver.class, ExternalLinkResolverImpl.class})
58+
@Component(service = {LinkResolver.class, ExternalLinkResolverImpl.class}, immediate = true)
5959
@Designate(ocd = ExternalLinkResolverImpl.Configuration.class)
6060
public class ExternalLinkResolverImpl implements LinkResolver {
6161

core/src/main/java/com/exadel/etoolbox/linkinspector/core/services/resolvers/InternalLinkResolverImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
/**
4747
* Validates external links via sending HEAD requests concurrently using {@link PoolingHttpClientConnectionManager}
4848
*/
49-
@Component(service = LinkResolver.class)
49+
@Component(service = LinkResolver.class )
5050
@Designate(ocd = InternalLinkResolverImpl.Config.class)
5151
public class InternalLinkResolverImpl implements LinkResolver {
5252

@@ -69,7 +69,7 @@ public class InternalLinkResolverImpl implements LinkResolver {
6969
private String internalLinksHost;
7070

7171
@Reference
72-
private ExternalLinkResolverImpl externalLinkResolver;
72+
private LinkResolver externalLinkResolver;
7373

7474
@Activate
7575
@Modified

core/src/main/java/com/exadel/etoolbox/linkinspector/core/servlets/ReplaceByPatternServlet.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ public class ReplaceByPatternServlet extends SlingAllMethodsServlet {
9797
private static final String DRY_RUN_PARAM = "isDryRun";
9898
private static final String BACKUP_PARAM = "isBackup";
9999
private static final String OUTPUT_AS_CSV_PARAM = "isOutputAsCsv";
100+
private static final String ADVANCED_MODE_PARAM = "advancedMode";
100101
private static final String ITEMS_COUNT_RESP_PARAM = "updatedItemsCount";
101102
private static final String BACKUP_PACKAGE_GROUP = "EToolbox_Link_Inspector";
102103
private static final String BACKUP_PACKAGE_NAME = "replace_by_pattern_backup_%s";
103104
private static final String BACKUP_PACKAGE_VERSION = "1.0";
104-
private static final String PAGE_PARAM = "page";
105105
private static final String SELECTED_PARAM = "selected";
106106

107107
private static final String[] CSV_COLUMNS = {
@@ -136,18 +136,24 @@ void activate(Configuration configuration) {
136136
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) {
137137
String linkPattern = ServletUtil.getRequestParamString(request, LINK_PATTERN_PARAM);
138138
String replacement = ServletUtil.getRequestParamString(request, REPLACEMENT_PARAM);
139+
boolean isAdvancedMode = ServletUtil.getRequestParamBoolean(request, ADVANCED_MODE_PARAM);
139140
boolean isDryRun = ServletUtil.getRequestParamBoolean(request, DRY_RUN_PARAM);
140141
boolean isBackup = ServletUtil.getRequestParamBoolean(request, BACKUP_PARAM);
141142
boolean isOutputAsCsv = ServletUtil.getRequestParamBoolean(request, OUTPUT_AS_CSV_PARAM);
142143
List<String> selectedItems = ServletUtil.getRequestParamStringList(request, SELECTED_PARAM);
143144

144-
if (StringUtils.isAnyBlank(linkPattern, replacement)) {
145+
if (StringUtils.isBlank(replacement)) {
145146
response.setStatus(HttpStatus.SC_BAD_REQUEST);
146-
LOG.warn("Any (or all) request params are empty: linkPattern - {}, replacement - {}",
147-
linkPattern, replacement);
147+
LOG.warn("Request params is empty: replacement - {}", replacement);
148148
return;
149149
}
150-
if (linkPattern.equals(replacement)) {
150+
151+
if (isAdvancedMode && StringUtils.isBlank(linkPattern)) {
152+
response.setStatus(HttpStatus.SC_BAD_REQUEST);
153+
LOG.warn("Request params is empty: linkPattern - {}", linkPattern);
154+
return;
155+
}
156+
if (isAdvancedMode && linkPattern.equals(replacement)) {
151157
response.setStatus(HttpStatus.SC_ACCEPTED);
152158
LOG.debug("linkPattern and replacement are equal, no processing is required");
153159
return;
@@ -162,7 +168,7 @@ protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse
162168
.format("%s@%s", gridResource.getResourcePath(), gridResource.getPropertyName())))
163169
.collect(Collectors.toList());
164170
List<UpdatedItem> updatedItems =
165-
processResources(filteredGridResources, isDryRun, isBackup, linkPattern, replacement, resourceResolver);
171+
processResources(filteredGridResources, isDryRun, isBackup, isAdvancedMode, linkPattern, replacement, resourceResolver);
166172
if (CollectionUtils.isEmpty(updatedItems)) {
167173
LOG.info("No links were updated, linkPattern: {}, replacement: {}", linkPattern, replacement);
168174
response.setStatus(HttpStatus.SC_NO_CONTENT);
@@ -184,6 +190,7 @@ protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse
184190
private List<UpdatedItem> processResources(Collection<GridResource> gridResources,
185191
boolean isDryRun,
186192
boolean isBackup,
193+
boolean isAdvancedMode,
187194
String linkPattern,
188195
String replacement,
189196
ResourceResolver resourceResolver)
@@ -197,7 +204,7 @@ private List<UpdatedItem> processResources(Collection<GridResource> gridResource
197204
if (isBackup && !isDeactivated) {
198205
createBackupPackage(filteredGridResources, session.get());
199206
}
200-
return replaceByPattern(filteredGridResources, isDryRun, linkPattern, replacement, resourceResolver);
207+
return replaceByPattern(filteredGridResources, isDryRun, isAdvancedMode, linkPattern, replacement, resourceResolver);
201208
}
202209

203210
private List<GridResource> filterGridResources(Collection<GridResource> gridResources,
@@ -216,6 +223,7 @@ private List<GridResource> filterGridResources(Collection<GridResource> gridReso
216223

217224
private List<UpdatedItem> replaceByPattern(Collection<GridResource> gridResources,
218225
boolean isDryRun,
226+
boolean isAdvancedMode,
219227
String linkPattern,
220228
String replacement,
221229
ResourceResolver resourceResolver) throws PersistenceException {
@@ -227,7 +235,7 @@ private List<UpdatedItem> replaceByPattern(Collection<GridResource> gridResource
227235
String currentLink = gridResource.getHref();
228236
String path = gridResource.getResourcePath();
229237
String propertyName = gridResource.getPropertyName();
230-
Optional<String> updated = Optional.of(currentLink.replaceAll(linkPattern, replacement))
238+
Optional<String> updated = Optional.of(isAdvancedMode ? currentLink.replaceAll(linkPattern, replacement) : replacement)
231239
.filter(updatedLink -> !updatedLink.equals(currentLink))
232240
.filter(updatedLink ->
233241
linkHelper.replaceLink(resourceResolver, path, propertyName, currentLink, updatedLink)

core/src/test/java/com/exadel/etoolbox/linkinspector/core/servlets/FixBrokenLinkServletTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class FixBrokenLinkServletTest {
5858
private static final String TEST_CURRENT_LINK = "/content/link-for-replacement";
5959
private static final String TEST_NEW_LINK = "/content/replacement-link";
6060
private static final String TEST_EXCEPTION_MSG = "Test exception message";
61+
private static final String ADVANCED_MODE = "advancedMode";
6162

6263
private final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK);
6364

@@ -100,6 +101,7 @@ void testCurrentLinkEqualToReplacement() {
100101
request.addRequestParameter(PROPERTY_NAME_PARAM, TEST_PROPERTY_NAME);
101102
request.addRequestParameter(CURRENT_LINK_PARAM, TEST_CURRENT_LINK);
102103
request.addRequestParameter(NEW_LINK_PARAM, TEST_CURRENT_LINK);
104+
request.addRequestParameter(ADVANCED_MODE, Boolean.TRUE.toString());
103105
fixture.doPost(request, response);
104106

105107
assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
@@ -119,6 +121,7 @@ void testValidateNewLink_notValid() {
119121
request.addRequestParameter(CURRENT_LINK_PARAM, TEST_CURRENT_LINK);
120122
request.addRequestParameter(NEW_LINK_PARAM, TEST_NEW_LINK);
121123
request.addRequestParameter(IS_SKIP_VALIDATION_PARAM, Boolean.FALSE.toString());
124+
request.addRequestParameter(ADVANCED_MODE, Boolean.TRUE.toString());
122125
fixture.doPost(request, response);
123126

124127
assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatus());

core/src/test/java/com/exadel/etoolbox/linkinspector/core/servlets/ReplaceByPatternServletTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ class ReplaceByPatternServletTest {
101101
private static final String TEST_RESOURCES_TREE_PATH = "/com/exadel/etoolbox/linkinspector/core/servlets/resources.json";
102102
private static final String TEST_FOLDER_PATH = "/content/test-folder";
103103
private static final String TEST_EXCEPTION_MSG = "Test exception message";
104+
private static final String ADVANCED_MODE = "advancedMode";
104105

105106
private final AemContext context = new AemContext(ResourceResolverType.JCR_MOCK);
106107

@@ -153,6 +154,7 @@ void testEmptyParams() {
153154
void testCurrentLinkEqualToReplacement() {
154155
request.addRequestParameter(LINK_PATTERN_PARAM, TEST_LINK_PATTERN);
155156
request.addRequestParameter(REPLACEMENT_PARAM, TEST_LINK_PATTERN);
157+
request.addRequestParameter(ADVANCED_MODE, Boolean.TRUE.toString());
156158
linkHelper = mock(LinkHelper.class);
157159
repositoryHelper = mock(RepositoryHelper.class);
158160
packageHelper = mock(PackageHelper.class);
@@ -433,6 +435,7 @@ private void setUpRequestParamsWithBackup() throws IOException {
433435
private void setUpRequestParamsLinks() throws IOException {
434436
request.addRequestParameter(LINK_PATTERN_PARAM, TEST_LINK_PATTERN);
435437
request.addRequestParameter(REPLACEMENT_PARAM, TEST_REPLACEMENT);
438+
request.addRequestParameter(ADVANCED_MODE, Boolean.TRUE.toString());
436439
Arrays.stream(loadSelectedValues()).forEach(value ->
437440
request.addRequestParameter(SELECTED_PARAM, value)
438441
);

ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/css/console-ui.less

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,15 @@ tr.elc-card {
131131
width:30%
132132
}
133133

134+
#elc-filter-options.elc-filter-active, #elc-filter-options.elc-filter-active:hover {
135+
background-color: #d3d3d3;
136+
}
137+
138+
.filter-dialog-button-group {
139+
display: flex;
140+
justify-content: space-between;
141+
}
142+
134143
#filter-dialog{
135144
.coral3-Dialog-wrapper{
136145
min-width: 50rem;
@@ -149,3 +158,4 @@ tr.elc-card {
149158
font-size: 12px;
150159
}
151160
}
161+

ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/js/console-ui.filter.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
const DIALOG_TITLE_LABEL = Granite.I18n.get('Filter Links');
2222
const CANCEL_LABEL = Granite.I18n.get('Cancel');
2323
const SUBMIT_FILTER_LABEL = Granite.I18n.get('Apply');
24+
const RESET_FILTER_LABEL = Granite.I18n.get('Reset');
2425

2526
function onFilterAction(name, el, config, collection, selections) {
2627
const dialog = document.querySelector('#filter--dialog');
@@ -82,12 +83,21 @@
8283
$('<p>').html('By text').appendTo(dialog.content);
8384
$linkSubstringField.appendTo(dialog.content);
8485

86+
87+
const $dialogActionsButtons = $('<div class="filter-dialog-action-buttons">');
88+
const $resetBtn = $('<button data-dialog-reset is="coral-button" variant="default">').text(RESET_FILTER_LABEL);
8589
const $cancelBtn = $('<button is="coral-button" variant="default" coral-close>').text(CANCEL_LABEL);
8690
const $updateBtn =
8791
$('<button data-dialog-action is="coral-button" variant="primary" coral-close>').text(SUBMIT_FILTER_LABEL);
8892

89-
$cancelBtn.appendTo(dialog.footer);
90-
$updateBtn.appendTo(dialog.footer);
93+
$cancelBtn.appendTo($dialogActionsButtons);
94+
$updateBtn.appendTo($dialogActionsButtons);
95+
96+
const $buttonGroup = $('<div class="filter-dialog-button-group">');
97+
$resetBtn.appendTo($buttonGroup);
98+
$dialogActionsButtons.appendTo($buttonGroup);
99+
100+
$buttonGroup.appendTo(dialog.footer);
91101

92102
function onSubmit(){
93103
searchParams.delete('type');
@@ -102,6 +112,12 @@
102112
document.location.search = searchParams;
103113
}
104114

115+
function onReset(){
116+
$linkSubstringField.val('');
117+
linksTypeSelect.value = '';
118+
}
119+
120+
dialog.on('click', '[data-dialog-reset]', onReset);
105121
dialog.on('click', '[data-dialog-action]', onSubmit);
106122
dialog.on('change', function(event) {
107123
linksTypeSelect.value
@@ -121,9 +137,7 @@
121137

122138
$(document).ready(function () {
123139
let searchParams = new URL(document.location).searchParams;
124-
if (searchParams != null && searchParams.get('type') != null || searchParams.get('substring') != null) {
125-
$('#elc-filter-options').attr('variant', 'primary');
126-
}
140+
$('#elc-filter-options').toggleClass('elc-filter-active', searchParams && searchParams.get('type') != null || searchParams.get('substring') != null)
127141
initFiltersDialog(searchParams);
128142
});
129143

ui.apps/src/main/content/jcr_root/apps/etoolbox-link-inspector/clientlibs/link-inspector-ui/js/console-ui.replace.js

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020
'use strict';
2121

2222
var CANCEL_LABEL = Granite.I18n.get('Cancel');
23-
var REPLACE_LABEL = Granite.I18n.get('Replace By Pattern');
24-
var REPLACE_BUTTON_LABEL = Granite.I18n.get('Replace');
23+
var REPLACE_AND_MODIFY_LABEL = Granite.I18n.get('Replace and Modify by Pattern');
24+
var REPLACE_LABEL = Granite.I18n.get('Replace');
25+
var MODIFY_LABEL = Granite.I18n.get('Modify');
2526
var PATTERN_LABEL = Granite.I18n.get('Please enter the regex pattern to be replaced');
2627
var REPLACEMENT_LINK_LABEL = Granite.I18n.get('Please enter the replacement');
2728
var DRY_RUN_CHECKBOX_LABEL = Granite.I18n.get('Dry run');
@@ -59,6 +60,7 @@
5960
isDryRun: data.isDryRun,
6061
isBackup: data.isBackup,
6162
isOutputAsCsv: data.isOutputAsCsv,
63+
advancedMode: data.advancedMode,
6264
selected: data.selected
6365
}].filter(function (item) {
6466
return item.pattern && item.replacement && item.pattern !== item.replacement;
@@ -136,22 +138,37 @@
136138

137139
var el = ELC.getSharableDlg();
138140
el.variant = 'notice';
139-
el.header.textContent = REPLACE_LABEL;
141+
el.header.textContent = REPLACE_AND_MODIFY_LABEL;
140142
el.footer.innerHTML = ''; // Clean content
141143
el.content.innerHTML = ''; // Clean content
142144

143145
var $cancelBtn = $('<button is="coral-button" variant="default" coral-close>').text(CANCEL_LABEL);
144-
var $updateBtn = $('<button data-dialog-action is="coral-button" variant="primary" coral-close>').text(REPLACE_BUTTON_LABEL);
146+
var $updateBtn = $('<button name="update-button" is="coral-button" variant="primary" coral-close>').text(REPLACE_LABEL);
145147
$cancelBtn.appendTo(el.footer);
146148
$updateBtn.appendTo(el.footer);
147149

148-
buildConfirmationMessage(selection).appendTo(el.content);
150+
buildConfirmationMessage(confirmationMessageSelectionItems(selection)).appendTo(el.content);
149151

150-
// Pattern input group
152+
let $replaceRadio = new Coral.Radio();
153+
$replaceRadio.label.textContent = REPLACE_LABEL;
154+
$replaceRadio.name = 'replace-modify';
155+
$replaceRadio.checked = true;
156+
$replaceRadio.value = 'replace';
157+
158+
let $modifyRadio = new Coral.Radio();
159+
$modifyRadio.label.textContent = MODIFY_LABEL;
160+
$modifyRadio.name = 'replace-modify';
161+
$modifyRadio.value = 'modify';
162+
163+
el.content.appendChild($replaceRadio);
164+
el.content.appendChild($modifyRadio);
165+
166+
let $patternFieldGroup = $('<div class="elc-pattern-field-group" hidden>');
151167
var $patternTextField =
152-
$('<input is="coral-textfield" class="elc-pattern-input" name="pattern" value="" required>');
153-
$('<p>').text(PATTERN_LABEL).appendTo(el.content);
154-
$patternTextField.appendTo(el.content);
168+
$('<input is="coral-textfield" class="elc-pattern-input" name="pattern" value="" placeholder=".+" required>');
169+
$('<p>').text(PATTERN_LABEL).appendTo($patternFieldGroup);
170+
$patternTextField.appendTo($patternFieldGroup);
171+
$patternFieldGroup.appendTo(el.content);
155172

156173
// Replacement input group
157174
var $replacementTextField =
@@ -161,11 +178,11 @@
161178

162179
// Dry run checkbox group
163180
var $isDryRunCheckbox =
164-
$('<coral-checkbox name="$isDryRun" title="' + DRY_RUN_TOOLTIP + '" checked>').text(DRY_RUN_CHECKBOX_LABEL);
181+
$('<coral-checkbox name="dry-run-checkbox" title="' + DRY_RUN_TOOLTIP + '" checked>').text(DRY_RUN_CHECKBOX_LABEL);
165182
$isDryRunCheckbox.appendTo(el.content);
166183

167184
// Backup checkbox group
168-
var $isBackupCheckbox = $('<coral-checkbox name="isBackup">').text(BACKUP_CHECKBOX_LABEL);
185+
var $isBackupCheckbox = $('<coral-checkbox name="isBackup" disabled>').text(BACKUP_CHECKBOX_LABEL);
169186
$isBackupCheckbox.appendTo(el.content);
170187

171188
// CSV output checkbox group
@@ -178,15 +195,18 @@
178195
function onValidate() {
179196
var replVal = $replacementTextField.val();
180197
var patternVal = $patternTextField.val();
198+
var advanced = $modifyRadio.checked;
181199
$replacementTextField.each(function () {
182200
this.setCustomValidity(replVal === patternVal ? VALIDATION_MSG : '');
183201
});
184-
$updateBtn.attr('disabled', !replVal || !patternVal || replVal === patternVal);
202+
$updateBtn.attr('disabled', !replVal || (advanced && !patternVal || replVal === patternVal));
185203
}
204+
186205
/** @param {Event} e */
187206
function onResolve(e) {
188207
var data = {
189208
pattern: $patternTextField.val(),
209+
advancedMode: $modifyRadio.checked,
190210
replacement: $replacementTextField.val(),
191211
isDryRun: $isDryRunCheckbox.prop("checked"),
192212
isBackup: $isBackupCheckbox.prop("checked"),
@@ -198,23 +218,37 @@
198218
deferred.resolve(data);
199219
}
200220

221+
/** @param {Event} e */
222+
function onDryRunChange(e) {
223+
$isBackupCheckbox.attr('disabled', $isDryRunCheckbox.prop('checked'));
224+
}
225+
201226
el.on('input', 'input', onValidate);
202-
el.on('click', '[data-dialog-action]', onResolve);
227+
el.on('click', '[name="update-button"]', onResolve);
228+
el.on('change', '[name="dry-run-checkbox"]', onDryRunChange);
203229
el.on('coral-overlay:close', function () {
204230
el.off('input', 'input', onValidate);
205-
el.off('click', '[data-dialog-action]', onResolve);
231+
el.off('click', '[name="update-button"]', onResolve);
232+
el.off('change', '[name="dry-run-checkbox"]', onDryRunChange);
206233
deferred.reject();
207234
});
208235

209236
el.show();
210237
onValidate();
211238

239+
el.content.addEventListener('change', function(event) {
240+
if (event.target.name == 'replace-modify') {
241+
$patternFieldGroup.attr('hidden', event.target.value != 'modify');
242+
onValidate();
243+
}
244+
});
245+
212246
return deferred.promise();
213247
}
214248

215249
function buildConfirmationMessage(selections) {
216250
let list = selections.slice(0, 12).map(function (row) {
217-
return '<li>' + row.currentLink + '</li>';
251+
return '<li>' + row.currentLink + ' (' + row.count + ')' + '</li>';
218252
});
219253
if (selections.length > 12) {
220254
list.push('<li>&#8230;</li>'); // &#8230; is ellipsis
@@ -226,6 +260,21 @@
226260
return $msg;
227261
}
228262

263+
function confirmationMessageSelectionItems(selections) {
264+
let valuesMap = {};
265+
selections.map(function (row) {
266+
return row.currentLink;
267+
}).forEach(function (item) {
268+
valuesMap[item] = (valuesMap[item]||0) + 1;
269+
});
270+
271+
let items = [];
272+
for (const [key, value] of Object.entries(valuesMap)) {
273+
items.push({currentLink: key, count: value});
274+
}
275+
return items;
276+
}
277+
229278
function buildSelectionItems(selections) {
230279
return selections.map(function (v) {
231280
let row = $(v);

0 commit comments

Comments
 (0)