added error marker for each collection tab and fixed the styles of the raw errors tooltip

This commit is contained in:
Gani Georgiev
2026-05-14 09:15:05 +03:00
parent b061673d9a
commit 820b9afe98
13 changed files with 103 additions and 25 deletions
+3 -1
View File
@@ -1,4 +1,4 @@
## v0.38.1 (WIP) ## v0.38.1
- Silenced the superuser IPs confirmation if there is no change. - Silenced the superuser IPs confirmation if there is no change.
@@ -7,6 +7,8 @@
- Force unset the auth state of existing realtime connections on user password, collection secret, etc. changes. - Force unset the auth state of existing realtime connections on user password, collection secret, etc. changes.
_This is not strictly necessery because the realtime connections have short-lived idle timeout by design but nonetheless it was implemented to restrict the abuse vectors._ _This is not strictly necessery because the realtime connections have short-lived idle timeout by design but nonetheless it was implemented to restrict the abuse vectors._
- Added error marker for each collection tab and fixed the styles of the raw errors tooltip.
## v0.38.0 ## v0.38.0
+1 -1
View File
@@ -4,7 +4,7 @@
## v0.22.44 ## v0.22.44
- (_Backported from v0.38.1_) Force unset the auth state of existing realtime connections on user password change. - (_Backported from v0.38.1_) Force unset the auth state of existing realtime connections on user tokenKey change.
## v0.22.43 ## v0.22.43
+1 -1
View File
@@ -12,4 +12,4 @@ PB_DOCS_URL = "https://pocketbase.io/docs"
PB_JS_SDK_URL = "https://github.com/pocketbase/js-sdk" PB_JS_SDK_URL = "https://github.com/pocketbase/js-sdk"
PB_DART_SDK_URL = "https://github.com/pocketbase/dart-sdk" PB_DART_SDK_URL = "https://github.com/pocketbase/dart-sdk"
PB_RELEASES = "https://github.com/pocketbase/pocketbase/releases" PB_RELEASES = "https://github.com/pocketbase/pocketbase/releases"
PB_VERSION = "v0.38.1-dev" PB_VERSION = "v0.38.1"
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -13,9 +13,9 @@
<!-- prism --> <!-- prism -->
<script src="./libs/prism/prism.js" data-manual></script> <script src="./libs/prism/prism.js" data-manual></script>
<script type="module" crossorigin src="./assets/index-C5XHp9-e.js"></script> <script type="module" crossorigin src="./assets/index-Dko-neZT.js"></script>
<link rel="modulepreload" crossorigin href="./assets/pocketbase.es-B_4DUNUU.js"> <link rel="modulepreload" crossorigin href="./assets/pocketbase.es-B_4DUNUU.js">
<link rel="stylesheet" crossorigin href="./assets/index-DR1PnFnr.css"> <link rel="stylesheet" crossorigin href="./assets/index-DRWtZ-mO.css">
</head> </head>
<body> <body>
</body> </body>
+6 -5
View File
@@ -7,9 +7,10 @@ const tooltip = t.div({
}); });
document.body.appendChild(tooltip); document.body.appendChild(tooltip);
function updateTooltipPosition(node, position) { function updateTooltipPosition(node, position, styleClass) {
let nodeRect = node.getBoundingClientRect(); let nodeRect = node.getBoundingClientRect();
tooltip.setAttribute("data-style", styleClass || "");
tooltip.setAttribute("data-position", position); tooltip.setAttribute("data-position", position);
// reset tooltip position // reset tooltip position
@@ -76,7 +77,7 @@ function hideTooltip() {
tooltip.hidePopover(); tooltip.hidePopover();
} }
function showTooltip(node, text, position) { function showTooltip(node, text, position, styleClass) {
if (!node || !text) { if (!node || !text) {
hideTooltip(); hideTooltip();
return; return;
@@ -84,14 +85,14 @@ function showTooltip(node, text, position) {
tooltip.showPopover(); tooltip.showPopover();
tooltip.textContent = text; tooltip.textContent = text;
updateTooltipPosition(node, position); updateTooltipPosition(node, position, styleClass);
} }
document.body.addEventListener("mouseleave", () => { document.body.addEventListener("mouseleave", () => {
hideTooltip(); hideTooltip();
}); });
function tooltipAction(textOrFunc, position = "top") { function tooltipAction(textOrFunc, position = "top", styleClass = "") {
return (el) => { return (el) => {
if (!el._tooltipText) { if (!el._tooltipText) {
el._tooltipText = store({ el._tooltipText = store({
@@ -105,7 +106,7 @@ function tooltipAction(textOrFunc, position = "top") {
tooltipTextWatcher = watch( tooltipTextWatcher = watch(
() => el._tooltipText.value, () => el._tooltipText.value,
async (result) => { async (result) => {
showTooltip(el, result, position); showTooltip(el, result, position, styleClass);
}, },
); );
} }
@@ -342,6 +342,9 @@ window.app.modals.openCollectionChangesConfirmation = async function(
), ),
yesCallback, yesCallback,
noCallback, noCallback,
{ className: "collection-changes-confirm-modal" }, {
className: "collection-changes-confirm-modal",
yesButton: "Yes, save changes",
},
); );
}; };
+64 -7
View File
@@ -63,6 +63,7 @@ function collectionUpsertModal(rawCollection, modalSettings) {
originalCollection: {}, originalCollection: {},
collection: {}, collection: {},
selectedTab: "", selectedTab: "",
errorTabs: {},
get activeTab() { get activeTab() {
if (!app.collectionTypes[data.collection.type]?.tabs) { if (!app.collectionTypes[data.collection.type]?.tabs) {
return data.selectedTab; return data.selectedTab;
@@ -211,6 +212,9 @@ function collectionUpsertModal(rawCollection, modalSettings) {
function resetForm() { function resetForm() {
data.collection = JSON.parse(JSON.stringify(data.originalCollection)); data.collection = JSON.parse(JSON.stringify(data.originalCollection));
// reset all errors
app.store.errors = null;
} }
async function duplicate() { async function duplicate() {
@@ -345,6 +349,30 @@ function collectionUpsertModal(rawCollection, modalSettings) {
}, 150); }, 150);
}, },
), ),
// check for tab errors
watch(
() => JSON.stringify(app.store.errors),
async (errors) => {
if (!errors) {
data.errorTabs = {};
return;
}
// ui tick
await new Promise((r) => setTimeout(r, 0));
data.errorTabs = {}; // reset after the tick to minimize flickering
const errorElems = modal?.querySelectorAll(".modal-content [data-tab] .error");
for (let el of errorElems) {
const tabName = el.closest("[data-tab]")?.dataset?.tab;
if (tabName) {
data.errorTabs[tabName] = true;
}
}
},
),
]; ];
}, },
onunmount: (el) => { onunmount: (el) => {
@@ -546,24 +574,35 @@ function collectionUpsertModal(rawCollection, modalSettings) {
t.nav( t.nav(
{ className: "tabs-header equal-width" }, { className: "tabs-header equal-width" },
() => { () => {
const tabItems = []; const tabHeaderItems = [];
const tabs = app.collectionTypes[data.collection.type]?.tabs || {}; const tabs = app.collectionTypes[data.collection.type]?.tabs || {};
for (let tabName in tabs) { for (let tabName in tabs) {
tabItems.push( tabHeaderItems.push(
t.button( t.button(
{ {
type: "button", type: "button",
"html-data-tab": tabName,
disabled: () => data.isSaving, disabled: () => data.isSaving,
className: () => `tab-item ${data.activeTab == tabName ? "active" : ""}`, className: () => `tab-item ${data.activeTab == tabName ? "active" : ""}`,
onclick: () => changeTab(tabName), onclick: () => changeTab(tabName),
}, },
t.span({ className: "txt" }, tabName), t.span({ className: "txt" }, tabName),
() => {
if (!data.errorTabs[tabName]) {
return;
}
return t.i({
className: "ri-error-warning-fill txt-danger txt-base",
ariaDescription: app.attrs.tooltip("Has errors"),
});
},
), ),
); );
} }
return tabItems; return tabHeaderItems;
}, },
), ),
), ),
@@ -571,7 +610,25 @@ function collectionUpsertModal(rawCollection, modalSettings) {
), ),
t.div( t.div(
{ className: "modal-content" }, { className: "modal-content" },
() => app.collectionTypes[data.collection.type]?.tabs?.[data.activeTab]?.(data), () => {
const tabContentItems = [];
const tabs = app.collectionTypes[data.collection.type]?.tabs || {};
for (let tabName in tabs) {
tabContentItems.push(
t.div(
{
"html-data-tab": tabName,
hidden: () => data.activeTab != tabName,
className: "tab-content-wrapper block",
},
() => app.collectionTypes[data.collection.type]?.tabs?.[tabName]?.(data),
),
);
}
return tabContentItems;
},
), ),
t.footer( t.footer(
{ className: "modal-footer" }, { className: "modal-footer" },
@@ -585,14 +642,14 @@ function collectionUpsertModal(rawCollection, modalSettings) {
t.span({ className: "txt" }, "Close"), t.span({ className: "txt" }, "Close"),
), ),
() => { () => {
const rawErrors = JSON.stringify(app.store.errors); const rawErrors = JSON.stringify(app.store.errors, null, 2);
if (rawErrors == "" || rawErrors == "null" || rawErrors == "{}" || rawErrors == "[]") { if (rawErrors == "" || rawErrors == "null" || rawErrors == "{}" || rawErrors == "[]") {
return; return;
} }
return t.i({ return t.i({
className: "ri-alert-line txt-danger", className: "ri-error-warning-line txt-danger",
ariaDescription: app.attrs.tooltip(() => "Raw error:\n" + rawErrors), ariaDescription: app.attrs.tooltip(() => "Raw errors:\n" + rawErrors, "top", "code"),
}); });
}, },
t.div( t.div(
+4
View File
@@ -411,6 +411,10 @@ hr {
} }
/* txt helpers */ /* txt helpers */
.txt-base {
line-height: var(--lineHeight) !important;
font-size: var(--fontSize) !important;
}
.txt-sm { .txt-sm {
line-height: var(--smLineHeight) !important; line-height: var(--smLineHeight) !important;
font-size: var(--smFontSize) !important; font-size: var(--smFontSize) !important;
+3
View File
@@ -65,6 +65,9 @@
i { i {
display: inline-block; display: inline-block;
} }
.label {
vertical-align: baseline;
}
} }
.rule-content { .rule-content {
margin: 5px 0; margin: 5px 0;
+8
View File
@@ -3,6 +3,7 @@
z-index: 99999; z-index: 99999;
max-width: 300px; max-width: 300px;
min-width: 30px; min-width: 30px;
max-height: 90%;
text-align: center; text-align: center;
white-space: pre-line; white-space: pre-line;
word-break: break-word; word-break: break-word;
@@ -13,6 +14,7 @@
font-size: var(--smFontSize); font-size: var(--smFontSize);
line-height: var(--smLineHeight); line-height: var(--smLineHeight);
font-family: var(--baseFontFamily); font-family: var(--baseFontFamily);
scrollbar-width: thin;
margin: 3px; margin: 3px;
padding: 3px 5px; padding: 3px 5px;
pointer-events: none; pointer-events: none;
@@ -27,4 +29,10 @@
opacity: 0; opacity: 0;
} }
} }
&[data-style="code"] {
text-align: left;
white-space: pre-wrap;
max-width: 350px;
font-family: var(--monospaceFontFamily);
}
} }
+1 -1
View File
@@ -88,7 +88,7 @@
--modalOverlayColor: rgba(70, 90, 115, 0.25); --modalOverlayColor: rgba(70, 90, 115, 0.25);
--tooltipTxtColor: #fff; --tooltipTxtColor: #fff;
--tooltipSurfaceColor: rgba(34, 36, 36, 0.9); --tooltipSurfaceColor: rgba(37, 39, 45, 0.9);
--boxShadow: 0px 8px 5px -5px rgba(34, 36, 36, 0.1); --boxShadow: 0px 8px 5px -5px rgba(34, 36, 36, 0.1);
--leftBoxShadow: -1px 0px 5px 0 rgba(34, 36, 36, 0.1); --leftBoxShadow: -1px 0px 5px 0 rgba(34, 36, 36, 0.1);