Skip to content

Commit bb2ccb1

Browse files
author
abrusco
committed
feat: melhorar ignorar objeto e atualizar versao 0.9.4
1 parent 541e98f commit bb2ccb1

5 files changed

Lines changed: 194 additions & 7 deletions

File tree

docs/app.js

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,79 @@ function saveIgnoredObjects() {
112112
}
113113

114114
function addIgnoredObject(name) {
115+
const options = arguments[1] || {};
116+
const deferSelectionMs = Number(options.deferSelectionMs) || 0;
115117
const n = String(name || '').trim().toUpperCase();
116118
if (!n) return;
117119
if (userIgnoredSet.has(n)) return;
118120
userIgnoredSet.add(n);
119121
saveIgnoredObjects();
120122
renderIgnoredList();
121-
render();
123+
124+
const refreshSelectionAndRender = () => {
125+
const visible = filteredEntries();
126+
if (!visible.some((entry) => entry.id === state.selectedId)) {
127+
state.selectedId = visible[0]?.id || null;
128+
}
129+
render();
130+
};
131+
132+
if (state.pendingIgnoreSelectionTimer) {
133+
window.clearTimeout(state.pendingIgnoreSelectionTimer);
134+
state.pendingIgnoreSelectionTimer = null;
135+
}
136+
137+
if (deferSelectionMs > 0) {
138+
// Atualiza a lista imediatamente, mas preserva a selecao atual por um instante
139+
// para tornar o feedback visual de "ignorar" perceptivel ao usuario.
140+
render();
141+
state.pendingIgnoreSelectionTimer = window.setTimeout(() => {
142+
state.pendingIgnoreSelectionTimer = null;
143+
refreshSelectionAndRender();
144+
}, deferSelectionMs);
145+
return;
146+
}
147+
148+
refreshSelectionAndRender();
149+
}
150+
151+
function showIgnoreObjectFeedback(type = 'added') {
152+
const objectBox = elements.metaObject?.closest('.status-item');
153+
if (objectBox) {
154+
objectBox.classList.remove('status-item-feedback-added', 'status-item-feedback-existing');
155+
const feedbackClass = type === 'existing' ? 'status-item-feedback-existing' : 'status-item-feedback-added';
156+
objectBox.classList.add(feedbackClass);
157+
window.setTimeout(() => {
158+
objectBox.classList.remove(feedbackClass);
159+
}, 700);
160+
}
161+
162+
if (!elements.ignoreObjectLink) {
163+
return;
164+
}
165+
166+
const originalText = elements.ignoreObjectLink.textContent || 'ignorar';
167+
const originalTitle = elements.ignoreObjectLink.title || '';
168+
if (type === 'existing') {
169+
elements.ignoreObjectLink.textContent = 'ja ignorado';
170+
elements.ignoreObjectLink.title = 'Este objeto ja esta na lista de ignorados';
171+
} else {
172+
elements.ignoreObjectLink.textContent = 'ignorado';
173+
elements.ignoreObjectLink.title = 'Objeto adicionado a lista de ignorados';
174+
}
175+
176+
window.setTimeout(() => {
177+
const entry = selectedEntry();
178+
const objectName = (entry?.meta4Object || '').trim().toUpperCase();
179+
if (!objectName) {
180+
elements.ignoreObjectLink.textContent = originalText;
181+
elements.ignoreObjectLink.title = originalTitle;
182+
return;
183+
}
184+
const isIgnored = userIgnoredSet.has(objectName);
185+
elements.ignoreObjectLink.textContent = isIgnored ? 'ignorado' : 'ignorar';
186+
elements.ignoreObjectLink.title = isIgnored ? 'Este objeto ja esta na lista de ignorados' : 'Adicionar objeto atual a lista de ignorados';
187+
}, 1200);
122188
}
123189

124190
function removeIgnoredObject(name) {
@@ -155,6 +221,7 @@ const state = {
155221
files: [],
156222
loadedFiles: [],
157223
source: 'default',
224+
pendingIgnoreSelectionTimer: null,
158225
selectedId: null,
159226
filterFile: 'all',
160227
search: '',
@@ -175,6 +242,7 @@ const elements = {
175242
selectedFile: document.querySelector('#selectedFile'),
176243
selectedTitle: document.querySelector('#selectedTitle'),
177244
metaObject: document.querySelector('#metaObject'),
245+
ignoreObjectLink: document.querySelector('#ignoreObjectLink'),
178246
nodeName: document.querySelector('#nodeName'),
179247
roleName: document.querySelector('#roleName'),
180248
organization: document.querySelector('#organization'),
@@ -355,6 +423,16 @@ function looksLikeResultRow(line) {
355423
return /^("?[^"]+"?|-?[0-9]|NULL\b|<null>\b)/i.test(trimmed);
356424
}
357425

426+
function normalizeOracleDateLiterals(sql) {
427+
return String(sql || '')
428+
.replace(/\{\s*d\s*'(\d{4})-(\d{2})-(\d{2})'\s*\}/gi, (_match, year, month, day) => {
429+
return `to_date('${day}/${month}/${year}', 'DD/MM/YYYY')`;
430+
})
431+
.replace(/\{\s*ts\s*'(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})'\s*\}/gi, (_match, year, month, day, hour, minute, second) => {
432+
return `to_date('${year}-${month}-${day} ${hour}:${minute}:${second}', 'YYYY-MM-DD HH24:MI:SS')`;
433+
});
434+
}
435+
358436
function normalizeSql(sql) {
359437
return sql.replace(/\s+/g, ' ').trim();
360438
}
@@ -508,7 +586,7 @@ function parseLogContent(content, fileName) {
508586
if (!current) {
509587
return;
510588
}
511-
current.sql = current.sql.trim();
589+
current.sql = normalizeOracleDateLiterals(current.sql.trim());
512590
current.normalizedSql = normalizeSql(current.sql);
513591
entries.push(current);
514592
current = null;
@@ -929,6 +1007,11 @@ function renderSelectedEntry() {
9291007
elements.selectedFile.textContent = 'Nenhum item selecionado';
9301008
elements.selectedTitle.textContent = 'Selecione uma query';
9311009
elements.metaObject.textContent = '-';
1010+
if (elements.ignoreObjectLink) {
1011+
elements.ignoreObjectLink.classList.remove('is-visible', 'is-disabled');
1012+
elements.ignoreObjectLink.removeAttribute('aria-disabled');
1013+
elements.ignoreObjectLink.dataset.object = '';
1014+
}
9321015
elements.nodeName.textContent = '-';
9331016
elements.roleName.textContent = '-';
9341017
elements.organization.textContent = '-';
@@ -945,7 +1028,19 @@ function renderSelectedEntry() {
9451028

9461029
elements.selectedFile.textContent = `${entry.fileName} | linha ${entry.lineNumber}`;
9471030
elements.selectedTitle.textContent = entryDisplayTitle(entry);
948-
elements.metaObject.textContent = entry.meta4Object || '-';
1031+
const objectName = entry.meta4Object || '-';
1032+
const normalizedObjectName = String(objectName).trim().toUpperCase();
1033+
const isIgnoredObject = !!normalizedObjectName && normalizedObjectName !== '-' && userIgnoredSet.has(normalizedObjectName);
1034+
elements.metaObject.textContent = objectName;
1035+
if (elements.ignoreObjectLink) {
1036+
const shouldShowLink = !!normalizedObjectName && normalizedObjectName !== '-';
1037+
elements.ignoreObjectLink.dataset.object = shouldShowLink ? objectName : '';
1038+
elements.ignoreObjectLink.classList.toggle('is-visible', shouldShowLink);
1039+
elements.ignoreObjectLink.classList.toggle('is-disabled', isIgnoredObject);
1040+
elements.ignoreObjectLink.setAttribute('aria-disabled', isIgnoredObject ? 'true' : 'false');
1041+
elements.ignoreObjectLink.textContent = isIgnoredObject ? 'ignorado' : 'ignorar';
1042+
elements.ignoreObjectLink.title = isIgnoredObject ? 'Este objeto ja esta na lista de ignorados' : 'Adicionar objeto atual a lista de ignorados';
1043+
}
9491044
elements.nodeName.textContent = entry.node || '-';
9501045
elements.roleName.textContent = entry.connection?.role || '-';
9511046
elements.organization.textContent = entry.connection?.organization || '-';
@@ -1194,6 +1289,23 @@ if (elements.addIgnoredButton) {
11941289
});
11951290
}
11961291

1292+
if (elements.ignoreObjectLink) {
1293+
elements.ignoreObjectLink.addEventListener('click', (event) => {
1294+
event.preventDefault();
1295+
const objectName = elements.ignoreObjectLink.dataset.object || selectedEntry()?.meta4Object || '';
1296+
if (!objectName) {
1297+
return;
1298+
}
1299+
const alreadyIgnored = userIgnoredSet.has(String(objectName).trim().toUpperCase());
1300+
if (alreadyIgnored) {
1301+
showIgnoreObjectFeedback('existing');
1302+
return;
1303+
}
1304+
addIgnoredObject(objectName, { deferSelectionMs: 1000 });
1305+
showIgnoreObjectFeedback('added');
1306+
});
1307+
}
1308+
11971309
if (elements.ignoredList) {
11981310
elements.ignoredList.addEventListener('click', (ev) => {
11991311
const btn = ev.target.closest('.remove-ignored');

docs/index.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1">
6-
<meta name="app-version" content="0.9.3">
6+
<meta name="app-version" content="0.9.4">
77
<title>M4 Log Visualizer</title>
88
<link rel="stylesheet" href="styles.css">
99
</head>
@@ -61,7 +61,13 @@
6161
<p class="viewer-meta-file" id="selectedFile">Nenhum item selecionado</p>
6262
<h2 class="viewer-meta-title" id="selectedTitle">Selecione uma query</h2>
6363
<div class="status-bar">
64-
<span class="status-item status-item-primary"><span class="status-label">Objeto</span><strong id="metaObject">-</strong></span>
64+
<span class="status-item status-item-primary">
65+
<span class="status-label">Objeto</span>
66+
<span class="status-object-row">
67+
<strong id="metaObject">-</strong>
68+
<a id="ignoreObjectLink" class="status-ignore-link" href="#" aria-label="Ignorar objeto atual">ignorar</a>
69+
</span>
70+
</span>
6571
<span class="status-item"><span class="status-label">Node</span><strong id="nodeName">-</strong></span>
6672
<span class="status-item status-item-compact"><span class="status-label">Role</span><strong id="roleName">-</strong></span>
6773
<span class="status-item"><span class="status-label">Data</span><strong id="date">-</strong></span>

docs/styles.css

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,12 +670,71 @@ td { font-family: Consolas, "Courier New", monospace; }
670670
background: #f4f8ff;
671671
border-color: #b8cceb;
672672
box-shadow: inset 0 0 0 1px rgba(9, 105, 218, .06);
673+
transition: box-shadow .18s ease, border-color .18s ease, background-color .18s ease;
673674
}
674675

675676
.status-item-primary strong {
676677
font-size: 14px;
677678
}
678679

680+
.status-object-row {
681+
display: flex;
682+
align-items: center;
683+
justify-content: space-between;
684+
gap: 10px;
685+
width: 100%;
686+
}
687+
688+
.status-object-row strong {
689+
flex: 1;
690+
min-width: 0;
691+
}
692+
693+
.status-ignore-link {
694+
display: none;
695+
flex: 0 0 auto;
696+
color: var(--accent);
697+
text-decoration: underline;
698+
text-underline-offset: 2px;
699+
font-size: 12px;
700+
line-height: 1;
701+
}
702+
703+
.status-ignore-link.is-visible {
704+
display: inline;
705+
}
706+
707+
.status-ignore-link.is-disabled {
708+
color: var(--muted);
709+
cursor: default;
710+
pointer-events: none;
711+
text-decoration: none;
712+
}
713+
714+
.status-item-feedback-added {
715+
border-color: #3ca66b;
716+
box-shadow: inset 0 0 0 1px rgba(60, 166, 107, .25), 0 0 0 3px rgba(60, 166, 107, .12);
717+
background: #eefbf3;
718+
}
719+
720+
.status-item-feedback-existing {
721+
border-color: #ca7b1b;
722+
box-shadow: inset 0 0 0 1px rgba(202, 123, 27, .2), 0 0 0 3px rgba(202, 123, 27, .1);
723+
background: #fff7ea;
724+
}
725+
726+
[data-theme="dark"] .status-item-feedback-added {
727+
border-color: #3ca66b;
728+
box-shadow: inset 0 0 0 1px rgba(60, 166, 107, .35), 0 0 0 3px rgba(60, 166, 107, .15);
729+
background: #173226;
730+
}
731+
732+
[data-theme="dark"] .status-item-feedback-existing {
733+
border-color: #ca7b1b;
734+
box-shadow: inset 0 0 0 1px rgba(202, 123, 27, .3), 0 0 0 3px rgba(202, 123, 27, .12);
735+
background: #352712;
736+
}
737+
679738
.status-item-compact {
680739
padding-right: 8px;
681740
}

docs/version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "0.9.3"
2+
"version": "0.9.4"
33
}

public/app.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,16 @@ function looksLikeResultRow(line) {
131131
return /^("?[^"]+"?|-?[0-9]|NULL\b|<null>\b)/i.test(trimmed);
132132
}
133133

134+
function normalizeOracleDateLiterals(sql) {
135+
return String(sql || '')
136+
.replace(/\{\s*d\s*'(\d{4})-(\d{2})-(\d{2})'\s*\}/gi, (_match, year, month, day) => {
137+
return `to_date('${day}/${month}/${year}', 'DD/MM/YYYY')`;
138+
})
139+
.replace(/\{\s*ts\s*'(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})'\s*\}/gi, (_match, year, month, day, hour, minute, second) => {
140+
return `to_date('${year}-${month}-${day} ${hour}:${minute}:${second}', 'YYYY-MM-DD HH24:MI:SS')`;
141+
});
142+
}
143+
134144
function normalizeSql(sql) {
135145
return sql.replace(/\s+/g, ' ').trim();
136146
}
@@ -174,7 +184,7 @@ function parseLogContent(content, fileName) {
174184
if (!current) {
175185
return;
176186
}
177-
current.sql = current.sql.trim();
187+
current.sql = normalizeOracleDateLiterals(current.sql.trim());
178188
current.normalizedSql = normalizeSql(current.sql);
179189
entries.push(current);
180190
current = null;

0 commit comments

Comments
 (0)