@@ -113,6 +119,10 @@ along with this program. If not, see
.
+
+
+
+
@@ -221,6 +231,7 @@ import ODialog from "@/lib/overlay/Dialog/ODialog.vue";
import OForm from "@/lib/forms/Form/OForm.vue";
import OFormInput from "@/lib/forms/Input/OFormInput.vue";
import OTable from "@/lib/core/Table/OTable.vue";
+import OTag from "@/lib/core/Badge/OTag.vue";
import OCodeCell from "@/lib/core/Table/cells/OCodeCell.vue";
import OUserCell from "@/lib/core/Table/cells/OUserCell.vue";
import {
@@ -260,6 +271,7 @@ export default defineComponent({
OForm,
OFormInput,
OTable,
+ OTag,
OCodeCell,
OUserCell,
},
@@ -308,6 +320,15 @@ export default defineComponent({
size: 340,
meta: { align: "left" },
},
+ {
+ id: "status",
+ header: t("ingestion.tokenStatus"),
+ accessorKey: "enabled",
+ sortable: true,
+ hideable: true,
+ size: 120,
+ meta: { align: "left" },
+ },
{
id: "created_by",
header: t("ingestion.createdBy"),
diff --git a/web/src/components/iam/SyntheticsTokens.vue b/web/src/components/iam/SyntheticsTokens.vue
index a6ad616142..b21892abcf 100644
--- a/web/src/components/iam/SyntheticsTokens.vue
+++ b/web/src/components/iam/SyntheticsTokens.vue
@@ -65,10 +65,17 @@ along with this program. If not, see
.
:loading="loading"
v-model:global-filter="filterQuery"
:show-global-filter="false"
+ :default-columns="false"
:enable-column-resize="true"
:persist-columns="true"
table-id="iam-synthetics-tokens"
filter-mode="client"
+ pagination="client"
+ :page-size="20"
+ :page-size-options="[20, 50, 100, 250, 500]"
+ sorting="client"
+ show-index
+ :footer-title="t('synthetics.tokens.title')"
>
@@ -86,10 +93,15 @@ along with this program. If not, see .
size="icon-sm"
icon-left="refresh"
:loading="loading"
- :title="t('common.refresh')"
data-test="synthetics-tokens-refresh-btn"
@click="fetchTokens"
- />
+ >
+
+
.
-
- {{ row.enabled ? t("common.enable") : t("common.disable") }}
-
+
@@ -272,7 +282,6 @@ import ODialog from "@/lib/overlay/Dialog/ODialog.vue";
import OForm from "@/lib/forms/Form/OForm.vue";
import OFormInput from "@/lib/forms/Input/OFormInput.vue";
import OTable from "@/lib/core/Table/OTable.vue";
-import OBadge from "@/lib/core/Badge/OBadge.vue";
import OTag from "@/lib/core/Badge/OTag.vue";
import OUserCell from "@/lib/core/Table/cells/OUserCell.vue";
import OEmptyState from "@/lib/core/EmptyState/OEmptyState.vue";
@@ -284,6 +293,8 @@ import {
import { COL, type OTableColumnDef } from "@/lib/core/Table/OTable.types";
import { toast } from "@/lib/feedback/Toast/useToast";
import { copyToClipboard } from "@/utils/clipboard";
+import { useShortcuts } from "@/lib/vue-shortcut-manager";
+import { focusSearchInput, isInputFocused } from "@/utils/keyboardShortcuts";
import syntheticsService from "@/services/synthetics";
import type { AgentSetup } from "@/types/synthetics";
@@ -310,7 +321,6 @@ export default defineComponent({
OForm,
OFormInput,
OTable,
- OBadge,
OTag,
OUserCell,
},
@@ -529,6 +539,28 @@ export default defineComponent({
fetchAgentSetup();
});
+ // ── Keyboard shortcuts ────────────────────────────────────────────────
+ useShortcuts([
+ {
+ id: "syntheticsTokensAdd",
+ handler: () => {
+ if (!isInputFocused()) showCreateForm.value = true;
+ },
+ },
+ {
+ id: "syntheticsTokensRefresh",
+ handler: () => {
+ if (!isInputFocused()) fetchTokens();
+ },
+ },
+ {
+ id: "syntheticsTokensFocusSearch",
+ handler: () => {
+ focusSearchInput("synthetics-tokens-search-input");
+ },
+ },
+ ]);
+
return {
t,
tokens,
diff --git a/web/src/components/iam/roles/AppRoles.spec.ts b/web/src/components/iam/roles/AppRoles.spec.ts
index 876fb2df0d..59179f0e54 100644
--- a/web/src/components/iam/roles/AppRoles.spec.ts
+++ b/web/src/components/iam/roles/AppRoles.spec.ts
@@ -82,7 +82,7 @@ describe("AppRoles - rendering", () => {
it("renders the Add Role button", async () => {
const wrapper = await mountAppRoles();
- expect(wrapper.find('[data-test="alert-list-add-alert-btn"]').exists()).toBe(true);
+ expect(wrapper.find('[data-test="iam-roles-add-role-btn"]').exists()).toBe(true);
});
});
@@ -120,7 +120,7 @@ describe("AppRoles - setupRoles", () => {
describe("AppRoles - addRole", () => {
it("opens the add role dialog when button is clicked", async () => {
const wrapper = await mountAppRoles();
- await wrapper.find('[data-test="alert-list-add-alert-btn"]').trigger("click");
+ await wrapper.find('[data-test="iam-roles-add-role-btn"]').trigger("click");
expect((wrapper.vm as any).showAddGroup).toBe(true);
});
});
@@ -469,7 +469,7 @@ describe("AppRoles - ODialog/ODrawer Migration", () => {
it("propagates showAddGroup=true to AddRole when addRole() handler is invoked", async () => {
const wrapper = await mountAppRolesWithAddRoleStub();
- await wrapper.find('[data-test="alert-list-add-alert-btn"]').trigger("click");
+ await wrapper.find('[data-test="iam-roles-add-role-btn"]').trigger("click");
await flushPromises();
const addRole = wrapper.findComponent({ name: "AddRole" });
diff --git a/web/src/components/iam/roles/AppRoles.vue b/web/src/components/iam/roles/AppRoles.vue
index 2a740a571b..21155a3c5b 100644
--- a/web/src/components/iam/roles/AppRoles.vue
+++ b/web/src/components/iam/roles/AppRoles.vue
@@ -22,7 +22,7 @@ along with this program. If not, see .
-
+
{{ t("iam.addRole") }}
diff --git a/web/src/lib/core/Badge/badgeGroups.ts b/web/src/lib/core/Badge/badgeGroups.ts
index e2a3e7bcc4..c520ffac0b 100644
--- a/web/src/lib/core/Badge/badgeGroups.ts
+++ b/web/src/lib/core/Badge/badgeGroups.ts
@@ -556,7 +556,7 @@ export const BADGE_GROUPS = {
featureStatus: {
mode: "plain",
shape: "pill",
- size: "md",
+ size: "sm",
values: {
enabled: { variant: "success" },
disabled: { variant: "error" },
diff --git a/web/src/lib/vue-shortcut-manager/shortcutRegistry.ts b/web/src/lib/vue-shortcut-manager/shortcutRegistry.ts
index 4690bdbd6a..c6cceda52b 100644
--- a/web/src/lib/vue-shortcut-manager/shortcutRegistry.ts
+++ b/web/src/lib/vue-shortcut-manager/shortcutRegistry.ts
@@ -656,6 +656,29 @@ export const SHORTCUT_REGISTRY: ShortcutGroup[] = [
],
},
+ // ── IAM — Synthetics Tokens ─────────────────────────────────────────────
+ {
+ pageKey: "shortcuts.pages.syntheticsTokens",
+ scope: "synthetics-tokens",
+ shortcuts: [
+ {
+ id: "syntheticsTokensAdd",
+ key: "n",
+ descriptionKey: "shortcuts.actions.syntheticsTokensAdd",
+ },
+ {
+ id: "syntheticsTokensRefresh",
+ key: "r",
+ descriptionKey: "shortcuts.actions.syntheticsTokensRefresh",
+ },
+ {
+ id: "syntheticsTokensFocusSearch",
+ key: "/",
+ descriptionKey: "shortcuts.actions.focusSearch",
+ },
+ ],
+ },
+
// ── Running Queries ─────────────────────────────────────────────────────
{
pageKey: "shortcuts.pages.runningQueries",
diff --git a/web/src/locales/languages/en-US.json b/web/src/locales/languages/en-US.json
index 0575234bcd..dbeac35ccf 100644
--- a/web/src/locales/languages/en-US.json
+++ b/web/src/locales/languages/en-US.json
@@ -2848,7 +2848,8 @@
"tokenRotateError": "Failed to rotate token.",
"tokenDeleteError": "Failed to delete token.",
"noTokensFound": "No ingestion tokens found.",
- "createdBy": "Created by"
+ "createdBy": "Created by",
+ "tokenStatus": "Status"
},
"dashboard": {
"autoName": {
@@ -10827,6 +10828,7 @@
"traceDetail": "Trace Detail",
"runningQueries": "Running Queries",
"ingestionTokens": "IAM — Ingestion Tokens",
+ "syntheticsTokens": "IAM — Synthetics Tokens",
"alertIncidents": "Alerts — Incidents",
"pipelineDestinations": "Pipelines — Destinations",
"enrichmentTables": "Enrichment Tables",
@@ -10924,6 +10926,8 @@
"runningQueriesRefresh": "Refresh query list",
"ingestionTokensAdd": "Create new token",
"ingestionTokensRefresh": "Refresh token list",
+ "syntheticsTokensAdd": "Create new token",
+ "syntheticsTokensRefresh": "Refresh token list",
"aiChatToggle": "Toggle AI chat",
"dashboardEdit": "Enter / exit edit mode",
"logsSaveView": "Save as saved view",