Skip to content

Commit 11b4425

Browse files
authored
Merge pull request #482 from wpengine/fix-logging-plugin-ui
chore(logging): UI enhancements
2 parents 6fd39e3 + 99c82ad commit 11b4425

File tree

10 files changed

+284
-31
lines changed

10 files changed

+284
-31
lines changed

.changeset/lemon-plums-nail.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@wpengine/wpgraphql-logging-wordpress-plugin": patch
3+
---
4+
5+
UI improvements for WPGraphQL Logging plugin: refactored styles, added GraphQL query formatting, and implemented unsaved changes warning

plugins/wpgraphql-logging/assets/css/settings/wp-graphql-logging-settings.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
.settings_page_wpgraphql-logging #poststuff .postbox .inside h2 {
2-
font-size: 1.3em;
1+
.graphql-logs_page_wpgraphql-logging #poststuff .postbox .inside h2 {
2+
font-size: 16.9px;
33
font-weight: 600;
44
padding-left: 0;
55
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
.wpgraphql-logging-view-header {
2+
display: flex;
3+
justify-content: space-between;
4+
align-items: center;
5+
margin-bottom: 20px;
6+
}
7+
8+
.wpgraphql-logging-details pre.wpgraphql-logging-query,
9+
.wpgraphql-logging-details pre.wpgraphql-logging-context,
10+
.wpgraphql-logging-details pre.wpgraphql-logging-extra {
11+
white-space: pre-wrap;
12+
max-height: 540px;
13+
overflow-y: scroll;
14+
padding: 15px;
15+
border: 1px solid #ddd;
16+
border-radius: 4px;
17+
}
18+
19+
pre.wpgraphql-logging-list-table-query {
20+
overflow-x: auto;
21+
background: #f4f4f4;
22+
margin-top: 0;
23+
margin-bottom: 0;
24+
padding: 15px;
25+
border: 1px solid #ddd;
26+
border-radius: 4px;
27+
max-height: 20px;
28+
}
29+
30+
.wpgraphql-logging-filters input.wpgraphql-logging-datepicker,
31+
.wpgraphql-logging-filters select[name="level_filter"] {
32+
width: 120px;
33+
}
34+
35+
.wpgraphql-logging-filters {
36+
display: inline-flex;
37+
align-items: center;
38+
gap: 8px;
39+
margin-right: 10px;
40+
}
41+
42+
.wpgraphql-logging-filters .clear-all-button {
43+
margin: 0;
44+
margin-left: 5px;
45+
text-decoration: none;
46+
}
Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,96 @@
1-
document.addEventListener('DOMContentLoaded', function() {
2-
const sanitizationMethodSelect = document.querySelector("#data_sanitization_method");
3-
if (!sanitizationMethodSelect) {
4-
return;
1+
document.addEventListener("DOMContentLoaded", function () {
2+
function listenForSanitizationMethodChange() {
3+
const sanitizationMethodSelect = document.querySelector(
4+
"#data_sanitization_method"
5+
);
6+
7+
if (!sanitizationMethodSelect) {
8+
return;
9+
}
10+
11+
function toggleCustomFields() {
12+
const isCustom = sanitizationMethodSelect.value === "custom";
13+
const customElements = document.querySelectorAll(
14+
".wpgraphql-logging-custom"
15+
);
16+
17+
customElements.forEach((el) => {
18+
if (isCustom) {
19+
el.classList.add("block");
20+
} else {
21+
el.classList.remove("block");
22+
}
23+
});
24+
}
25+
26+
toggleCustomFields();
27+
sanitizationMethodSelect.addEventListener("change", toggleCustomFields);
528
}
629

7-
function toggleCustomFields() {
8-
const isCustom = sanitizationMethodSelect.value === 'custom';
9-
const customElements = document.querySelectorAll('.wpgraphql-logging-custom');
30+
function listenForUnsavedChanges() {
31+
const formElement = document.querySelector("form");
32+
33+
function getFormState(form) {
34+
const data = new FormData(form);
35+
return JSON.stringify(Array.from(data.entries()));
36+
}
1037

11-
customElements.forEach((el) => {
12-
if (isCustom) {
13-
el.classList.add('block');
14-
} else {
15-
el.classList.remove('block');
38+
// Save the initial state of the form for later comparison
39+
const initialState = getFormState(formElement);
40+
41+
// Warn the user if they try to leave with unsaved changes
42+
function beforeUnload(e) {
43+
const formState = getFormState(formElement);
44+
45+
if (formState !== initialState) {
46+
e.preventDefault();
47+
e.returnValue = true;
1648
}
49+
}
50+
51+
window.addEventListener("beforeunload", beforeUnload);
52+
53+
// Remove the warning on submit so it doesn't appear when saving
54+
formElement.addEventListener("submit", function () {
55+
window.removeEventListener("beforeunload", beforeUnload);
1756
});
1857
}
1958

20-
toggleCustomFields();
21-
sanitizationMethodSelect.addEventListener('change', toggleCustomFields);
59+
function listenForLogPointsSelection() {
60+
const logPointsInput = document.querySelector("#event_log_selection");
61+
const enableCheckbox = document.querySelector(
62+
"input[name='wpgraphql_logging_settings[basic_configuration][enabled]']"
63+
);
64+
65+
function checkLogPointsSelection() {
66+
const anyLogPointsSelected = logPointsInput.selectedOptions.length > 0;
67+
68+
const existingDescription =
69+
logPointsInput.parentElement.querySelector(".description");
70+
if (existingDescription) {
71+
existingDescription.remove();
72+
}
73+
74+
// If the logging is enabled and no log points are selected, show a description
75+
if (enableCheckbox?.checked && !anyLogPointsSelected) {
76+
const description = document.createElement("p");
77+
78+
if (!logPointsInput.parentElement.querySelector(".description")) {
79+
description.className = "description";
80+
description.textContent =
81+
"If you don't select any log points, no data will be logged.";
82+
description.style.marginLeft = "25px";
83+
logPointsInput.parentElement.appendChild(description);
84+
}
85+
}
86+
}
87+
88+
logPointsInput.addEventListener("change", checkLogPointsSelection);
89+
enableCheckbox.addEventListener("change", checkLogPointsSelection);
90+
checkLogPointsSelection();
91+
}
92+
93+
listenForSanitizationMethodChange();
94+
listenForUnsavedChanges();
95+
listenForLogPointsSelection();
2296
});

plugins/wpgraphql-logging/assets/js/view/wp-graphql-logging-view.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,127 @@ jQuery(document).ready(function($) {
44
timeFormat: "HH:mm:ss"
55
});
66
});
7+
8+
document.addEventListener("DOMContentLoaded", function () {
9+
function formatGraphQLQuery(query, indentSize = 2) {
10+
if (!query || typeof query !== "string") return "";
11+
12+
try {
13+
let formatted = query.trim().replace(/\s+/g, " ");
14+
let indentLevel = 0,
15+
result = "",
16+
inString = false,
17+
stringChar = null,
18+
afterClosingParen = false;
19+
const operationTypes = ["query", "mutation", "subscription", "fragment"];
20+
const indent = () => "\n" + " ".repeat(indentLevel * indentSize);
21+
22+
for (let i = 0; i < formatted.length; i++) {
23+
const char = formatted[i],
24+
prev = formatted[i - 1],
25+
next = formatted[i + 1];
26+
27+
// Track string literals
28+
if ((char === '"' || char === "'") && prev !== "\\") {
29+
if (!inString) {
30+
inString = true;
31+
stringChar = char;
32+
} else if (char === stringChar) {
33+
inString = false;
34+
stringChar = null;
35+
}
36+
}
37+
38+
if (inString) {
39+
result += char;
40+
continue;
41+
}
42+
43+
// Handle braces and parentheses
44+
if (char === "{" || char === "(") {
45+
result = result.trimEnd() + (char === "{" ? " {" : "(");
46+
if (next !== (char === "{" ? "}" : ")")) {
47+
indentLevel++;
48+
result += indent();
49+
}
50+
afterClosingParen = false;
51+
} else if (char === "}" || char === ")") {
52+
if (prev !== (char === "}" ? "{" : "(")) {
53+
indentLevel--;
54+
result = result.trimEnd() + indent();
55+
}
56+
result += char;
57+
afterClosingParen = char === ")";
58+
} else if (char === ",") {
59+
result += "," + indent();
60+
afterClosingParen = false;
61+
} else if (char === " ") {
62+
const trimmed = result.trimEnd();
63+
const lastWord =
64+
trimmed
65+
.split(/[\s\n{}(),]/)
66+
.filter((w) => w)
67+
.pop() || "";
68+
const lastChar = trimmed.slice(-1);
69+
70+
if (
71+
(afterClosingParen && next === "@") ||
72+
trimmed.endsWith("...") ||
73+
lastWord === "on" ||
74+
operationTypes.includes(lastWord) ||
75+
lastChar === ":" ||
76+
lastChar === "@" ||
77+
trimmed.match(/@\w+$/)
78+
) {
79+
result += char;
80+
} else {
81+
const isBetweenFields =
82+
lastChar &&
83+
/[a-zA-Z0-9_]/.test(lastChar) &&
84+
next &&
85+
/[a-zA-Z_]/.test(next) &&
86+
!["{", "}", "(", ")", ",", ":", "\n", "@", "."].includes(next);
87+
88+
if (isBetweenFields) {
89+
result = result.trimEnd() + indent();
90+
afterClosingParen = false;
91+
} else if (!["\n", " "].includes(result.slice(-1))) {
92+
result += char;
93+
}
94+
}
95+
} else {
96+
if (
97+
afterClosingParen &&
98+
char !== "@" &&
99+
char !== "{" &&
100+
char !== "}"
101+
) {
102+
result = result.trimEnd() + " ";
103+
}
104+
result += char;
105+
afterClosingParen = false;
106+
}
107+
}
108+
109+
return result
110+
.split("\n")
111+
.map((line) => line.trimEnd())
112+
.join("\n");
113+
} catch (error) {
114+
console.error("GraphQL formatting error:", error);
115+
return query;
116+
}
117+
}
118+
119+
const queryElements = document.querySelectorAll(
120+
"pre.wpgraphql-logging-query"
121+
);
122+
123+
if (queryElements.length > 0) {
124+
queryElements.forEach(function (element) {
125+
const rawQuery = element.textContent;
126+
const formattedQuery = formatGraphQLQuery(rawQuery);
127+
element.textContent = formattedQuery;
128+
});
129+
}
130+
});

plugins/wpgraphql-logging/src/Admin/View/List/ListTable.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ protected function format_code(string $code): string {
413413
if ( empty( $code ) ) {
414414
return '';
415415
}
416-
return '<pre style="overflow-x: auto; background: #f4f4f4; padding: 15px; border: 1px solid #ddd; border-radius: 4px; max-height: 300px;">' . esc_html( $code ) . '</pre>';
416+
return '<pre class="wpgraphql-logging-list-table-query">' . esc_html( $code ) . '</pre>';
417417
}
418418

419419
/**

plugins/wpgraphql-logging/src/Admin/View/Templates/WPGraphQLLoggerFilters.php

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,22 @@
2222
$wpgraphql_logging_log_levels = apply_filters( 'wpgraphql_logging_log_levels', $wpgraphql_logging_log_levels );
2323
?>
2424

25-
<div class="alignleft actions" style="display: inline-flex; align-items: center; gap: 8px; margin-right: 10px;">
25+
<div class="alignleft actions wpgraphql-logging-filters">
2626
<input type="text"
2727
name="start_date"
2828
class="wpgraphql-logging-datepicker"
2929
placeholder="Start Date"
3030
value="<?php echo esc_attr( $wpgraphql_logging_current_start_date ); ?>"
31-
autocomplete="off"
32-
style="width: 120px;" />
31+
autocomplete="off" />
3332

3433
<input type="text"
3534
name="end_date"
3635
class="wpgraphql-logging-datepicker"
3736
placeholder="End Date"
3837
value="<?php echo esc_attr( $wpgraphql_logging_current_end_date ); ?>"
39-
autocomplete="off"
40-
style="width: 120px;" />
38+
autocomplete="off" />
4139

42-
<select name="level_filter" style="width: 120px;">
40+
<select name="level_filter">
4341
<option value="">All Levels</option>
4442
<?php foreach ( $wpgraphql_logging_log_levels as $wpgraphql_logging_level ) : ?>
4543
<option value="<?php echo esc_attr( $wpgraphql_logging_level ); ?>" <?php selected( $wpgraphql_logging_current_level, $wpgraphql_logging_level ); ?>>
@@ -51,8 +49,7 @@ class="wpgraphql-logging-datepicker"
5149
<?php submit_button( __( 'Filter', 'wpgraphql-logging' ), 'secondary', '', false, [ 'style' => 'margin: 0;' ] ); ?>
5250

5351
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wpgraphql-logging-view' ) ); ?>"
54-
class="clear-all-button"
55-
style="margin: 0; margin-left: 5px; text-decoration: none;">
52+
class="clear-all-button">
5653
<?php esc_html_e( 'Clear All', 'wpgraphql-logging' ); ?>
5754
</a>
5855
</div>

plugins/wpgraphql-logging/src/Admin/View/Templates/WPGraphQLLoggerView.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*/
1414
?>
1515
<div class="wrap">
16-
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
16+
<div class="wpgraphql-logging-view-header">
1717
<h1><?php esc_html_e( 'Log Entry', 'wpgraphql-logging' ); ?></h1>
1818
<a href="
1919
<?php
@@ -33,7 +33,7 @@
3333
</a>
3434
</div>
3535

36-
<table class="widefat striped">
36+
<table class="widefat striped wpgraphql-logging-details">
3737
<tbody>
3838
<tr>
3939
<th><?php esc_html_e( 'ID', 'wpgraphql-logging' ); ?></th>
@@ -61,15 +61,15 @@
6161
</tr>
6262
<tr>
6363
<th><?php esc_html_e( 'Query', 'wpgraphql-logging' ); ?></th>
64-
<td><pre style="overflow-x: auto; background: #f4f4f4; padding: 15px; border: 1px solid #ddd; border-radius: 4px;"><?php echo esc_html( (string) $log->get_query() ); ?></pre></td>
64+
<td><pre class="wpgraphql-logging-query"><?php echo esc_html( (string) $log->get_query() ); ?></pre></td>
6565
</tr>
6666
<tr>
6767
<th><?php esc_html_e( 'Context', 'wpgraphql-logging' ); ?></th>
68-
<td><pre><?php echo esc_html( (string) wp_json_encode( $log->get_context(), JSON_PRETTY_PRINT ) ); ?></pre></td>
68+
<td><pre class="wpgraphql-logging-context"><?php echo esc_html( (string) wp_json_encode( $log->get_context(), JSON_PRETTY_PRINT ) ); ?></pre></td>
6969
</tr>
7070
<tr>
7171
<th><?php esc_html_e( 'Extra', 'wpgraphql-logging' ); ?></th>
72-
<td><pre><?php echo esc_html( (string) wp_json_encode( $log->get_extra(), JSON_PRETTY_PRINT ) ); ?></pre></td>
72+
<td><pre class="wpgraphql-logging-extra"><?php echo esc_html( (string) wp_json_encode( $log->get_extra(), JSON_PRETTY_PRINT ) ); ?></pre></td>
7373
</tr>
7474
</tbody>
7575
</table>

plugins/wpgraphql-logging/src/Admin/ViewLogsPage.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,14 @@ public function enqueue_admin_scripts_styles( string $hook_suffix ): void {
161161
);
162162
}
163163

164+
if ( file_exists( trailingslashit( WPGRAPHQL_LOGGING_PLUGIN_DIR ) . 'assets/css/view/wp-graphql-logging-view.css' ) ) {
165+
wp_enqueue_style(
166+
'wpgraphql-graphql-logging-view',
167+
trailingslashit( WPGRAPHQL_LOGGING_PLUGIN_URL ) . 'assets/css/view/wp-graphql-logging-view.css',
168+
[],
169+
WPGRAPHQL_LOGGING_VERSION
170+
);
171+
}
164172

165173
// Allow other plugins to enqueue their own scripts/styles.
166174
do_action( 'wpgraphql_logging_view_logs_admin_enqueue_scripts', $hook_suffix );

0 commit comments

Comments
 (0)