Skip to content

feat(web-console): instance naming UI #427

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

Merged
merged 31 commits into from
May 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4d9ab8f
feat(ui): instance name
glasstiger Apr 24, 2025
fac6306
feat(web-console): instance naming UI
emrberk Apr 29, 2025
18a717f
rename config to preferences
glasstiger May 6, 2025
5f9c6f6
Merge remote-tracking branch 'origin/main' into ia_config_endpoint
glasstiger May 6, 2025
4490f52
update submodule
glasstiger May 7, 2025
34d4b0c
add popper loading, remove flicker upon save, shrink instance name if…
emrberk May 7, 2025
ca1f7cf
update submodule
emrberk May 7, 2025
4bece2d
update submodule
glasstiger May 7, 2025
47571c5
add test cases
emrberk May 8, 2025
021db2c
address review comments
emrberk May 9, 2025
7e1f144
use /settings to save preferences
glasstiger May 13, 2025
436f729
update submodule
glasstiger May 14, 2025
3ae03f3
introduce instance type and change tooltip styling
emrberk May 14, 2025
9536049
add instance type indicator to the badge and document title
emrberk May 16, 2025
6719e00
Merge remote-tracking branch 'origin/main' into ia_config_endpoint
emrberk May 20, 2025
fe3b127
rbac for save instance settings
emrberk May 20, 2025
47dccfd
no access control if acl is not enabled
emrberk May 20, 2025
1f65e49
submodule
emrberk May 20, 2025
f684e8c
further oss check
emrberk May 20, 2025
be2afa4
refresh issues and error handling - wip
emrberk May 20, 2025
9933829
handle 409
emrberk May 21, 2025
7e7eb08
extract error message from response based on content type
glasstiger May 21, 2025
e7819a7
toasts and focus handling
emrberk May 22, 2025
b95efa6
increase toast duration
emrberk May 22, 2025
fa0e99c
update submodule
emrberk May 22, 2025
9a3f626
Merge remote-tracking branch 'origin/main' into ia_config_endpoint
emrberk May 22, 2025
4480aaa
fix release type setting
glasstiger May 22, 2025
ca3a1fe
instance info into telemetry
glasstiger May 23, 2025
8edffef
instance info into telemetry
glasstiger May 23, 2025
e64fccb
refactoring, renaming
glasstiger May 23, 2025
38528f7
submodule
emrberk May 23, 2025
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
94 changes: 52 additions & 42 deletions packages/browser-tests/cypress/integration/auth/auth.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ const interceptSettings = (payload) => {
describe("OSS", () => {
before(() => {
interceptSettings({
"release.type": "OSS",
"release.version": "1.2.3",
"config": {
"release.type": "OSS",
"release.version": "1.2.3",
}
});
cy.visit(baseUrl);
});
Expand All @@ -27,16 +29,18 @@ describe("OSS", () => {
describe("Auth - UI", () => {
before(() => {
interceptSettings({
"release.type": "EE",
"release.version": "1.2.3",
"acl.enabled": true,
"acl.basic.auth.realm.enabled": false,
"acl.oidc.enabled": false,
"acl.oidc.client.id": null,
"acl.oidc.authorization.endpoint": null,
"acl.oidc.token.endpoint": null,
"acl.oidc.pkce.required": null,
"acl.oidc.groups.encoded.in.token": false,
"config": {
"release.type": "EE",
"release.version": "1.2.3",
"acl.enabled": true,
"acl.basic.auth.realm.enabled": false,
"acl.oidc.enabled": false,
"acl.oidc.client.id": null,
"acl.oidc.authorization.endpoint": null,
"acl.oidc.token.endpoint": null,
"acl.oidc.pkce.required": null,
"acl.oidc.groups.encoded.in.token": false,
}
});
cy.visit(baseUrl);
});
Expand All @@ -52,16 +56,18 @@ describe("Auth - UI", () => {
describe("Auth - OIDC", () => {
before(() => {
interceptSettings({
"release.type": "EE",
"release.version": "1.2.3",
"acl.enabled": true,
"acl.basic.auth.realm.enabled": false,
"acl.oidc.enabled": true,
"acl.oidc.client.id": "test",
"acl.oidc.authorization.endpoint": "https://host:9999/auth",
"acl.oidc.token.endpoint": "https://host:9999/token",
"acl.oidc.pkce.required": true,
"acl.oidc.groups.encoded.in.token": false,
"config": {
"release.type": "EE",
"release.version": "1.2.3",
"acl.enabled": true,
"acl.basic.auth.realm.enabled": false,
"acl.oidc.enabled": true,
"acl.oidc.client.id": "test",
"acl.oidc.authorization.endpoint": "https://host:9999/auth",
"acl.oidc.token.endpoint": "https://host:9999/token",
"acl.oidc.pkce.required": true,
"acl.oidc.groups.encoded.in.token": false,
}
});
cy.visit(baseUrl);
});
Expand All @@ -77,16 +83,18 @@ describe("Auth - OIDC", () => {
describe("Auth - Basic", () => {
before(() => {
interceptSettings({
"release.type": "EE",
"release.version": "1.2.3",
"acl.enabled": true,
"acl.basic.auth.realm.enabled": true,
"acl.oidc.enabled": false,
"acl.oidc.client.id": null,
"acl.oidc.authorization.endpoint": null,
"acl.oidc.token.endpoint": null,
"acl.oidc.pkce.required": null,
"acl.oidc.groups.encoded.in.token": false,
"config": {
"release.type": "EE",
"release.version": "1.2.3",
"acl.enabled": true,
"acl.basic.auth.realm.enabled": true,
"acl.oidc.enabled": false,
"acl.oidc.client.id": null,
"acl.oidc.authorization.endpoint": null,
"acl.oidc.token.endpoint": null,
"acl.oidc.pkce.required": null,
"acl.oidc.groups.encoded.in.token": false,
}
});
cy.visit(baseUrl);
});
Expand All @@ -100,16 +108,18 @@ describe("Auth - Basic", () => {
describe("Auth - Disabled", () => {
before(() => {
interceptSettings({
"release.type": "EE",
"release.version": "1.2.3",
"acl.enabled": false,
"acl.basic.auth.realm.enabled": true,
"acl.oidc.enabled": false,
"acl.oidc.client.id": null,
"acl.oidc.authorization.endpoint": null,
"acl.oidc.token.endpoint": null,
"acl.oidc.pkce.required": null,
"acl.oidc.groups.encoded.in.token": false,
"config": {
"release.type": "EE",
"release.version": "1.2.3",
"acl.enabled": false,
"acl.basic.auth.realm.enabled": true,
"acl.oidc.enabled": false,
"acl.oidc.client.id": null,
"acl.oidc.authorization.endpoint": null,
"acl.oidc.token.endpoint": null,
"acl.oidc.pkce.required": null,
"acl.oidc.groups.encoded.in.token": false,
}
});
cy.visit(baseUrl);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe("telemetry config", () => {
cy.wait("@telemetryConfig").then(({ response }) => {
const columnNames = response.body.columns.map((c) => c.name);
expect(response.statusCode).to.equal(200);
["id", "enabled", "version", "os", "package"].forEach((name) => {
["id", "enabled", "version", "os", "package", "instance_name", "instance_type", "instance_desc"].forEach((name) => {
expect(columnNames).to.include(name);
});
expect(response.body.dataset[0][0]).to.be.string;
Expand All @@ -34,6 +34,9 @@ describe("telemetry config", () => {
expect(typeof response.body.dataset[0][4]).to.satisfy(
(v) => v === null || typeof v === "string"
);
expect(response.body.dataset[0][5]).to.be.string;
expect(response.body.dataset[0][6]).to.be.string;
expect(response.body.dataset[0][7]).to.be.string;
});
});
});
Expand Down Expand Up @@ -62,7 +65,7 @@ describe("telemetry enabled", () => {
it("should start telemetry when enabled", () => {
cy.wait("@telemetryConfig").then(({ response }) => {
cy.wait("@addTelemetry").then(({ request }) => {
const payload = JSON.parse(request.body);
const payload = request.body;
expect(payload.id).to.equal(response.body.dataset[0][0]);
expect(payload.version).to.equal(response.body.dataset[0][2]);
expect(payload.os).to.equal(response.body.dataset[0][3]);
Expand Down
64 changes: 64 additions & 0 deletions packages/browser-tests/cypress/integration/console/topbar.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/// <reference types="cypress" />

describe("TopBar", () => {
beforeEach(() => {
cy.loadConsoleWithAuth();
});

it("should show the instance warning and no description", () => {
cy.getByDataHook("topbar-instance-name").should(
"have.text",
"Instance name is not set"
);
cy.getByDataHook("topbar-instance-badge").should(
"have.css",
"background-color",
"rgb(40, 42, 54)"
);
});

it("should preview the color, show error when instance name is empty, and don't save changes on cancel", () => {
cy.getByDataHook("topbar-instance-name").realHover();
cy.getByDataHook("topbar-instance-edit-icon").should("be.visible");
cy.getByDataHook("topbar-instance-edit-icon").click();
cy.getByDataHook("topbar-instance-color-option-r").click();
cy.getByDataHook("topbar-instance-badge").should(
"have.css",
"background-color",
"rgb(199, 7, 45)"
);
cy.getByDataHook("topbar-instance-save-button").click();
cy.contains("Instance name is required").should("be.visible");
cy.getByDataHook("topbar-instance-cancel-button").click();
cy.getByDataHook("topbar-instance-name").should(
"have.text",
"Instance name is not set"
);
cy.getByDataHook("topbar-instance-badge").should(
"have.css",
"background-color",
"rgb(40, 42, 54)"
);
});

it("should change the instance name, description, and type", () => {
cy.getByDataHook("topbar-instance-badge").realHover();
cy.getByDataHook("topbar-instance-edit-icon").should("be.visible");
cy.getByDataHook("topbar-instance-edit-icon").click();
cy.getByDataHook("topbar-instance-name-input").type("test-instance");
cy.getByDataHook("topbar-instance-type-select").select("production");
cy.getByDataHook("topbar-instance-description-input").type(
"test description of the test instance"
);
cy.getByDataHook("topbar-instance-color-option-g").click();
cy.getByDataHook("topbar-instance-save-button").click();
cy.getByDataHook("topbar-instance-save-button").should("not.exist");
cy.getByDataHook("topbar-instance-name").should("contain", "Production");
cy.getByDataHook("topbar-instance-name").should("contain", "test-instance");
cy.getByDataHook("topbar-instance-icon").realHover();
cy.contains("test description of the test instance").should("be.visible");
cy.contains(
"You are connected to a QuestDB instance for production"
).should("be.visible");
});
});
24 changes: 13 additions & 11 deletions packages/browser-tests/cypress/integration/enterprise/oidc.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,19 @@ describe("OIDC authentication", () => {

// load login page
interceptSettings({
"release.type": "EE",
"release.version": "1.2.3",
"acl.enabled": true,
"acl.basic.auth.realm.enabled": false,
"acl.oidc.enabled": true,
"acl.oidc.client.id": "client1",
"acl.oidc.authorization.endpoint": oidcAuthorizationCodeUrl,
"acl.oidc.token.endpoint": oidcTokenUrl,
"acl.oidc.pkce.required": true,
"acl.oidc.state.required": false,
"acl.oidc.groups.encoded.in.token": false,
"config": {
"release.type": "EE",
"release.version": "1.2.3",
"acl.enabled": true,
"acl.basic.auth.realm.enabled": false,
"acl.oidc.enabled": true,
"acl.oidc.client.id": "client1",
"acl.oidc.authorization.endpoint": oidcAuthorizationCodeUrl,
"acl.oidc.token.endpoint": oidcTokenUrl,
"acl.oidc.pkce.required": true,
"acl.oidc.state.required": false,
"acl.oidc.groups.encoded.in.token": false,
}
});
cy.visit(baseUrl);

Expand Down
2 changes: 1 addition & 1 deletion packages/browser-tests/questdb
Submodule questdb updated 216 files
46 changes: 36 additions & 10 deletions packages/web-console/src/components/PopperToggle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,35 +86,61 @@ export const PopperToggle = ({
return
}

setActive(false)
if (_active) {
setActive(false)
if (onToggle) {
onToggle(false)
}
}
},
[container, onToggle, triggerElement, _active],
)

if (onToggle) {
onToggle(false)
const handleKeyDown = useCallback(
(event: KeyboardEvent) => {
if (event.key === "Escape" && _active) {
setActive(false)

if (onToggle) {
onToggle(false)
}
}
},
[container, onToggle, triggerElement],
[_active, onToggle],
)

usePopperStyles(container, styles.popper)

useTransition(container, _active, transitionTimeoutId)

useEffect(() => {
setActive(typeof active === "undefined" ? _active || false : active)
}, [active, _active])
if (typeof active !== "undefined") {
setActive(active)
}
}, [active])

useEffect(() => {
document.body.appendChild(container)

return () => {
clearTimeout(transitionTimeoutId.current)
if (document.body.contains(container)) {
document.body.removeChild(container)
}
}
}, [container])

useEffect(() => {
document.addEventListener("mousedown", handleMouseDown)
document.addEventListener("touchstart", handleMouseDown)
document.addEventListener("keydown", handleKeyDown)

return () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
clearTimeout(transitionTimeoutId.current)
document.removeEventListener("mousedown", handleMouseDown)
document.removeEventListener("touchstart", handleMouseDown)
document.body.contains(container) && document.body.removeChild(container)
document.removeEventListener("keydown", handleKeyDown)
}
}, [container, handleMouseDown])
}, [handleMouseDown, handleKeyDown])

return (
<>
Expand Down
Loading