Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Add inline grouping pattern creation #219

Merged
merged 9 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 81 additions & 1 deletion client-app/app/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { tracked } from "@glimmer/tracking";
@classic
export default class IndexController extends Controller {
@tracked loading = false;
@tracked buildingGroupingPattern = false;
@tracked rowMessagesForGroupingPattern = [];

showDebug = getLocalStorage("showDebug", false);
showInfo = getLocalStorage("showInfo", false);
Expand All @@ -33,6 +35,13 @@ export default class IndexController extends Controller {
);
}

get showCreateGroupingPattern() {
return (
this.buildingGroupingPattern &&
this.rowMessagesForGroupingPattern.length > 1
);
}

@computed("search")
get searchTerm() {
if (this.search) {
Expand Down Expand Up @@ -67,6 +76,19 @@ export default class IndexController extends Controller {
this.model.selectRow(row, opts);
}

@action
handleCheckboxChange(row, event) {
if (event.target.checked) {
this.rowMessagesForGroupingPattern = [
...this.rowMessagesForGroupingPattern,
row.message,
];
} else {
this.rowMessagesForGroupingPattern =
this.rowMessagesForGroupingPattern.filter((i) => i !== row.message);
}
}

@action
tabChangedAction(newTab) {
this.model.tabChanged(newTab);
Expand All @@ -87,7 +109,6 @@ export default class IndexController extends Controller {
// eslint-disable-next-line no-alert
if (confirm("Clear the logs?\n\nCancel = No, OK = Clear")) {
await ajax("/clear", { type: "POST" });
this.loading = true;
this.model.reload();
this.loading = false;
}
Expand Down Expand Up @@ -171,4 +192,63 @@ export default class IndexController extends Controller {

debounce(this, this.doSearch, term, 250);
}

@action
toggleGroupingPatternFromSelectedRows() {
this.buildingGroupingPattern = !this.buildingGroupingPattern;
this.rowMessagesForGroupingPattern = [];
}

@action
async createGroupingPatternFromSelectedRows() {
let match = this.findLongestMatchingPrefix(
this.rowMessagesForGroupingPattern
);
match = this.escapeRegExp(match);

if (
match.trim().length &&
// eslint-disable-next-line no-alert
confirm(
`Do you want to create the grouping pattern\n\n"${match}"\n\nCancel = No, OK = Create`
)
) {
await ajax("/patterns/grouping.json", {
method: "POST",
data: {
pattern: match,
},
});
this.rowMessagesForGroupingPattern = [];
this.buildingGroupingPattern = false;
this.model.reload();
} else if (!match.trim().length) {
// eslint-disable-next-line no-alert
alert("Can not create a grouping pattern with the given rows");
}
}

findLongestMatchingPrefix(strings) {
const shortestString = strings.reduce(
(shortest, str) => (str.length < shortest.length ? str : shortest),
strings[0]
);

let longestMatchingSubstring = "";
for (let i = 0; i < shortestString.length; i++) {
const currentSubstring = shortestString.substring(0, i + 1);

if (strings.every((str) => str.includes(currentSubstring))) {
longestMatchingSubstring = currentSubstring;
} else {
break;
}
}

return longestMatchingSubstring;
}

escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}
}
23 changes: 16 additions & 7 deletions client-app/app/styles/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,19 @@ tbody tr {
margin: 40dvh auto;
}

.message-row-wrapper {
display: flex;
width: inherit;

.grouping-checkbox {
margin: 0;
}
}

.message-row {
font-family: "Roboto";
display: flex;
width: inherit;
}

.message-row .severity,
Expand Down Expand Up @@ -306,7 +316,7 @@ label span {
}

.severity-filters label {
margin-right: 18px;
margin-right: 10px;
}

.search-clear-all .clear {
Expand Down Expand Up @@ -396,7 +406,7 @@ label span {
.btn {
display: inline-block;
margin: 0;
padding: 5px 12px;
padding: 5px 8px;
font-size: 1em;
line-height: 0;
text-align: center;
Expand Down Expand Up @@ -455,7 +465,6 @@ label span {
.search-clear-all .footer-btns .settings {
height: 100%;
box-sizing: border-box;
margin: 0 7px 0 7px;
display: inline-flex;
align-items: center;
}
Expand All @@ -471,11 +480,11 @@ label span {
}

.footer-btns {
flex-grow: 0;
flex-shrink: 0;
display: flex;
gap: 0.7em;
}

@media (min-width: 771px) {
@media (min-width: 871px) {
.severity-filters,
.search-clear-all {
height: 100%;
Expand All @@ -497,7 +506,7 @@ label span {
}
}

@media (max-width: 770px) {
@media (max-width: 870px) {
.severity-filters {
padding: 10px;
}
Expand Down
29 changes: 28 additions & 1 deletion client-app/app/templates/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,16 @@
{{/if}}

{{#each this.model.rows as |row|}}
<MessageRow @model={{row}} @selectRow={{fn this.selectRowAction row}} />
<div class="message-row-wrapper">
{{#if this.buildingGroupingPattern}}
<input
type="checkbox"
class="grouping-checkbox"
{{on "change" (fn this.handleCheckboxChange row)}}
/>
{{/if}}
<MessageRow @model={{row}} @selectRow={{fn this.selectRowAction row}} />
</div>
{{/each}}
</div>
</div>
Expand Down Expand Up @@ -109,9 +118,27 @@

<div class="footer-btns">
{{#if this.showSettings}}
{{#if this.showCreateGroupingPattern}}
<button
class="settings btn"
type="button"
{{on "click" this.createGroupingPatternFromSelectedRows}}
>
<span>Create Grouping Pattern</span>
</button>
{{/if}}

<LinkTo @route="settings" class="settings btn no-text">
<FaIcon @icon="cog" />
</LinkTo>

<button
class="settings btn no-text"
type="button"
{{on "click" this.toggleGroupingPatternFromSelectedRows}}
>
<FaIcon @icon="list" />
</button>
{{/if}}

<button
Expand Down
1 change: 1 addition & 0 deletions client-app/config/icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module.exports = function () {
"cog",
"lock",
"unlock",
"list",
],
"free-regular-svg-icons": ["trash-alt", "check-square", "copy", "clone"],
// "free-brands-svg-icons": []
Expand Down
33 changes: 32 additions & 1 deletion client-app/tests/unit/controllers/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import * as utilities from "client-app/lib/utilities";

module("Unit | Controller | index", function (hooks) {
setupTest(hooks);
const ajaxStub = sinon.stub(utilities, "ajax");

test("uses search param to filter results", function (assert) {
const controller = this.owner.lookup("controller:index");
const ajaxStub = sinon.stub(utilities, "ajax");
const messages = MessageCollection.create();
const row1 = { message: "error tomtom", severity: 2, key: "ce1f53b0cc" };
const row2 = { message: "error steaky", severity: 3, key: "b083352825" };
Expand Down Expand Up @@ -43,4 +43,35 @@ module("Unit | Controller | index", function (hooks) {
"with correct terms"
);
});

test("Creating inline grouping patterns finds the longest matching prefix between selected messages", function (assert) {
const controller = this.owner.lookup("controller:index");
const messages = ["error foo tomtom", "error foo steaky", "error foo bar"];

assert.deepEqual(
controller.findLongestMatchingPrefix(messages),
"error foo "
);
});
janzenisaac marked this conversation as resolved.
Show resolved Hide resolved

test("Creating inline grouping patterns can handle special characters", function (assert) {
const controller = this.owner.lookup("controller:index");
let messages = [
"error foo!/@ tomtom",
"error foo!/@ steaky",
"error foo!/@ bar",
];

assert.deepEqual(
controller.findLongestMatchingPrefix(messages),
"error foo!/@ "
);

messages = ["/$home/sam/.r\benv/", "/$home/sam/.r\benv/"];

assert.deepEqual(
controller.findLongestMatchingPrefix(messages),
"/$home/sam/.r\benv/"
);
});
});
2 changes: 1 addition & 1 deletion lib/logster/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module Logster
VERSION = "2.15.0"
VERSION = "2.16.0"
end
4 changes: 2 additions & 2 deletions website/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: ..
specs:
logster (2.14.0)
logster (2.15.0)

GEM
remote: https://rubygems.org/
Expand Down Expand Up @@ -33,4 +33,4 @@ DEPENDENCIES
sinatra

BUNDLED WITH
2.2.16
2.5.3