Skip to content

Commit 533b54f

Browse files
Merge pull request #58 from exadel-inc/feature/38
[ELI_38] Combine 'Fix selected' and 'Replace by Pattern' in one button.
2 parents 222195f + 5a42a15 commit 533b54f

File tree

8 files changed

+94
-42
lines changed

8 files changed

+94
-42
lines changed

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

+1-1
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)
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

+2-2
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

@@ -68,7 +68,7 @@ public class InternalLinkResolverImpl implements LinkResolver {
6868

6969
private String internalLinksHost;
7070

71-
@Reference(target = "(service.pid=com.exadel.etoolbox.linkinspector.core.services.resolvers.ExternalLinkResolverImpl)")
71+
@Reference
7272
private LinkResolver externalLinkResolver;
7373

7474
@Activate

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

+16-8
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

+3
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

+3
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

+1
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,4 @@ tr.elc-card {
158158
font-size: 12px;
159159
}
160160
}
161+

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

+64-15
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);

ui.content/src/main/content/jcr_root/content/etoolbox-link-inspector/link-inspector/.content.xml

+4-16
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,7 @@
109109
sling:resourceType="etoolbox-link-inspector/components/footer"/>
110110
<actions jcr:primaryType="nt:unstructured">
111111
<primary jcr:primaryType="nt:unstructured">
112-
<fixBroken
113-
jcr:primaryType="nt:unstructured"
114-
sling:resourceType="granite/ui/components/coral/foundation/collection/action"
115-
action="cq-admin.etoolbox.linkinspector.action.fix-broken-link"
116-
activeCondition="cq-admin.etoolbox.linkinspector.actioncondition.fix-broken-link"
117-
disabled="{Boolean}true"
118-
icon="linkCheck"
119-
rel="etoolbox-link-inspector-fix-broken-link"
120-
target=".etoolbox-link-inspector"
121-
text="Fix Selected"
122-
title="Fix Selected"
123-
variant="primary"/>
124-
<replaceByPattern
112+
<fixSelected
125113
jcr:primaryType="nt:unstructured"
126114
sling:resourceType="granite/ui/components/coral/foundation/collection/action"
127115
action="cq-admin.etoolbox.linkinspector.action.replace-by-pattern"
@@ -130,10 +118,10 @@
130118
icon="findAndReplace"
131119
rel="etoolbox-link-inspector-fix-by-pattern"
132120
target=".etoolbox-link-inspector"
133-
text="Replace By Pattern"
134-
title="Replace By Pattern"
121+
text="Fix Selected"
122+
title="Fix Selected"
135123
granite:id="elc-replace-by-pattern"
136-
variant="minimal"/>
124+
variant="primary"/>
137125
<filterOptions
138126
jcr:primaryType="nt:unstructured"
139127
sling:resourceType="granite/ui/components/coral/foundation/collection/action"

0 commit comments

Comments
 (0)