Skip to content

Conversation

@nikhilsaikethe
Copy link
Contributor

@nikhilsaikethe nikhilsaikethe commented Aug 18, 2025

User description

This PR improves the following
`Fix: checkboxes as per design for alert list

Fix: general setting, platform settings modified as per design

Fix: numeric input in general settings as per design

Fix: introduced all variables according to design

Fix: secondary button, primary button, tabs, search input added

Fix: another major change related to tabs, sticky header and footer table

Fix: light mode q-toggle redesign done for both lg and small

Fix: pipeline list as per new design

Fix: added removed padding at the child level for pipeline editor

Fix: function list table as per design changed

Fix: made filtering rows based upon filter query this is done to avoid the issue of the table showing some height when the filter is applied and there are no results

Fix: enrichment table list updated with latest design

Fix: added border to the last row when having less rows when filter is applied or not applied

Fix: function list bottom header to take functions

Fix: function list header as per design

Fix: stream list table as per design

Fix: report list table as per new design

Fix: users list table changed as per design

Fix: added filter check for height so to avoid the issue of the table showing some height when the filter is applied and there are no results

Fix: service account list table changed as per design

Fix: organization list table updated as per design

Fix: user groups as per design with app table additional props

Fix: app roles tables list updated as per design

Fix: made group roles virtual scroll to false

Fix: group users, roles, service accounts tables as per new design system

Fix: search icon in IAM tables as per design

Fix: search history table update as per new design

Fix: search scheduler list table updated as per design

Fix: space between app tabs and search in log stream page

Fix: pagination logic modified due to pagination component introduced

Fix: aggregation to streaming aggregation label change in management page

Fix: change sub text for streaming aggregation in management page

Fix: q-toggle for dark mode

Fix: report list added additional checks

Fix: alert destination table as per design

Fix: destination list, template list tables updated as per design

Fix: cipher keys table as per design

Fix: regex pattern list updated as per design

Fix: search input placeholder text fixed

Fix: per page options consistent with streams page

Fix: import and pipeline editor buttons changed as per design

Fix: added primary and secondary buttons in all listing pages

Fix: increased pipeline editor height

Fix: add stream in pipeline should not have more space in x direction

Fix: secondary, primary, and delete buttons modified in pipeline nodes

Fix: IAM add pages in sync

Fix: introduce toggle button in the entire application

Fix: alert folder list made sticky top title and search input

Fix: import alert primary and secondary button changed

Fix: action scripts table modified as per design

Fix: add action script file changed

Fix: add enrichment table submit and cancel at start

Fix: add stream submit and cancel buttons at start

Fix: create report changed as per new design

Fix: real user monitoring get started button

Fix: data source page reset rum token, reset token to primary button

Fix: add destination button position changed

Fix: add cipher key UI modified according to add report

Fix: organization settings toggle changed

Fix: home view layout spacing fixed

Fix: remove negative bg for delete button`


PR Type

Enhancement


Description

  • Adopt new design system across tables

  • Introduce uniform sticky headers/footers

  • Replace filters with tabs and styled inputs

  • Improve pagination, per-page options


Diagram Walkthrough

flowchart LR
  design["New design tokens/components"]
  tables["Tables (Lists across app)"]
  headers["Sticky headers/footers"]
  filters["Tabs + styled search"]
  pagination["Unified pagination options"]
  ux["Consistent UX across themes"]

  design -- applied to --> tables
  tables -- enable --> headers
  tables -- replace --> filters
  tables -- standardize --> pagination
  tables -- results in --> ux
Loading

File Walkthrough

Relevant files
Enhancement
19 files
LogStream.vue
Header redesign, tabs, sticky table, pagination                   
+82/-95 
AlertList.vue
Header styling, search/toggle redesign, sticky table         
+59/-62 
ActionScipts.vue
Styled header/search, computed filtering, sticky table     
+71/-65 
User.vue
New header/search, client filtering, footer pagination     
+63/-53 
HomeView.vue
Card layout spacing and grouping tweaks                                   
+110/-109
ServiceAccountsList.vue
New header/search, client filter, sticky table/footer       
+63/-59 
General.vue
Platform settings UX revamp with GroupHeader                         
+144/-63
PipelinesList.vue
Header/tabs/search restyle, sticky table, export button   
+52/-31 
EnrichmentTableList.vue
Header/search restyle, client filtering, sticky table       
+45/-38 
TemplateList.vue
Header/search/buttons restyle, sticky table/footer             
+43/-43 
FunctionList.vue
Header/search restyle, client filtering, sticky table       
+49/-39 
ReportList.vue
Header/tabs/search restyle, sticky table/footer, filters 
+38/-32 
ExternalDestination.vue
Form controls restyle, large toggles, delete node dialog 
+74/-15 
AlertsDestinationList.vue
Header/search/buttons restyle, sticky table/footer             
+43/-41 
GroupHeader.vue
New shared section header component                                           
+64/-0   
_variables.scss
Introduce/adjust design tokens and variables                         
+289/-0 
RegexPatternList.vue
Apply unified table/header/search styles                                 
+62/-56 
CipherKeys.vue
Apply unified table/header/search styles                                 
+45/-45 
PipelinesDestinationList.vue
Apply unified table/header/search styles                                 
+41/-39 
Tests
1 files
TemplateList.spec.ts
Update tests to match new UI structure                                     
+0/-20   
Additional files
54 files
alertTemplatesPage.js +17/-17 
alertsPage.js +5/-5     
dashboard-chart.js +3/-0     
AppTable.vue +30/-13 
EditScript.vue +37/-34 
AddAlert.vue +12/-10 
AddDestination.vue +15/-12 
AddTemplate.vue +11/-11 
ImportAlert.vue +6/-6     
ImportDestination.vue +6/-6     
ImportTemplate.vue +7/-6     
ScheduledAlert.vue +6/-4     
VariablesInput.vue +8/-11   
AddCipherKey.vue +27/-15 
AddFolder.vue +12/-14 
FolderList.vue +47/-22 
AddEnrichmentTable.vue +12/-10 
FunctionsToolbar.vue +18/-18 
AddGroup.vue +19/-23 
AppGroups.vue +33/-22 
EditGroup.vue +2/-2     
GroupRoles.vue +21/-8   
GroupServiceAccounts.vue +18/-7   
GroupUsers.vue +17/-6   
AddUpdateOrganization.vue +19/-20 
ListOrganizations.vue +30/-37 
Quota.vue +13/-9   
AddRole.vue +14/-14 
AppRoles.vue +27/-17 
EditRole.vue +3/-3     
AddServiceAccount.vue +26/-28 
AddUser.vue +18/-26 
AddStream.vue +11/-12 
ImportPipeline.vue +10/-12 
AssociateFunction.vue +25/-18 
Condition.vue +20/-17 
ScheduledPipeline.vue +21/-19 
Stream.vue +26/-21 
PipelineEditor.vue +21/-19 
StreamSelection.vue +10/-10 
CreateReport.vue +28/-30 
AddRegexPattern.vue +9/-12   
ImportRegexPattern.vue +6/-6     
OrganizationManagement.vue +16/-2   
OrganizationSettings.vue +11/-13 
FilterCreatorPopup.vue +16/-2   
en.json +5/-3     
SearchHistory.vue +30/-18 
SearchSchedulersList.vue +53/-27 
app.scss +414/-8 
Functions.vue +1/-2     
IdentityAccessManagement.vue +1/-1     
Ingestion.vue +9/-9     
RealUserMonitoring.vue +3/-1     

@github-actions
Copy link
Contributor

github-actions bot commented Aug 18, 2025

PR Reviewer Guide 🔍

(Review updated until commit 5c3d466)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

The header container height and table dynamic height calculations were changed (e.g., 100vh - 114px and 71px header). Verify these values match actual rendered heights across layouts to avoid overflow or double scrollbars, especially when tabs/search bars are conditionally shown.

<!-- eslint-disable vue/attribute-hyphenation -->
<template>
  <q-page class="q-pa-none" style="min-height: inherit">
    <div style="height: calc(100vh - 41px); overflow-y: auto;" >
    <div class="flex items-center justify-between tw-py-3 tw-px-4 tw-h-[71px] tw-border-b-[1px]"
    :class="store.state.theme === 'dark' ? 'o2-table-header-dark tw-border-gray-500' : 'o2-table-header-light tw-border-gray-200'"
    >
      <div class="q-table__title tw-font-[600]" data-test="log-stream-title-text">
        {{ t("logStream.header") }}
      </div>
      <div class="flex items-start">
        <div class="flex justify-between items-end">

            <div class="app-tabs-container tw-h-[36px] q-mr-md" :class="store.state.theme === 'dark' ? 'app-tabs-container-dark' : 'app-tabs-container-light'">
                <app-tabs
                class="tabs-selection-container"
                :class="store.state.theme === 'dark' ? 'tabs-selection-container-dark' : 'tabs-selection-container-light'"
                :tabs="streamTabs"
                v-model:active-tab="streamActiveTab"
                @update:active-tab="filterLogStreamByTab"
              />
          </div>
        </div>
        <div data-test="streams-search-stream-input">
          <q-input
            v-model="filterQuery"
            borderless
            dense
            class="q-ml-auto no-border o2-search-input tw-h-[36px]"
            :class="store.state.theme === 'dark' ? 'o2-search-input-dark' : 'o2-search-input-light'"
            :placeholder="t('logStream.search')"
            debounce="300"
          >
            <template #prepend>
              <q-icon class="o2-search-input-icon" :class="store.state.theme === 'dark' ? 'o2-search-input-icon-dark' : 'o2-search-input-icon-light'" name="search" />
            </template>
          </q-input>
        </div>
        <q-btn
          data-test="log-stream-refresh-stats-btn"
          class="q-ml-md text-bold no-border o2-secondary-button tw-h-[36px]"
          flat
          :class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
          no-caps
          :label="t(`logStream.refreshStats`)"
          @click="getLogStream(true)"
        />
        <q-btn
          v-if="isSchemaUDSEnabled"
          data-test="log-stream-add-stream-btn"
          class="q-ml-md o2-primary-button tw-h-[36px]"
          flat
          :class="store.state.theme === 'dark' ? 'o2-primary-button-dark' : 'o2-primary-button-light'"
          no-caps
          :label="t(`logStream.add`)"
          @click="addStream"
        />
      </div>
    </div>
    <q-table
      data-test="log-stream-table"
      class="o2-quasar-table o2-quasar-table-header-sticky"
      :class="store.state.theme === 'dark' ? 'o2-quasar-table-dark o2-quasar-table-header-sticky-dark o2-last-row-border-dark' : 'o2-quasar-table-light o2-quasar-table-header-sticky-light o2-last-row-border-light'"
      ref="qTable"
      v-model:selected="selected"
      :rows="logStream"
Accessibility

Several buttons now rely on icons with visually hidden labels (e.g., Move/Export with icon + span). Confirm appropriate aria-labels or titles exist for screen readers and that flat secondary/primary buttons still meet color contrast requirements in both themes.

    :perPageOptions="perPageOptions"
    @update:changeRecordPerPage="changePagination"
  />
</template> -->

<template #bottom="scope">
  <div class="bottom-btn tw-h-[48px]">
    <div class="o2-table-footer-title tw-flex tw-items-center tw-w-[100px] tw-mr-md">
      {{ resultTotal }} {{ t('alerts.header') }}
    </div>

    <q-btn
      v-if="selectedAlerts.length > 0"
      data-test="alert-list-move-across-folders-btn"
      class="flex items-center q-mr-md no-border o2-secondary-button tw-h-[36px]"
      :class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
      no-caps
      dense
      @click="moveMultipleAlerts"
      >
        <q-icon :name="outlinedDriveFileMove" size="16px" />
        <span class="tw-ml-2">Move</span>
    </q-btn>
    <q-btn
      v-if="selectedAlerts.length > 0"
      data-test="alert-list-export-alerts-btn"
      class="flex items-center no-border o2-secondary-button tw-h-[36px]"
      :class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
      no-caps
      dense
      @click="multipleExportAlert"
    >
      <q-icon name="download" size="16px" />
      <span class="tw-ml-2">Export</span>
  </q-btn>
    <QTablePagination
i18n Consistency

New static strings like "Platform Settings" and descriptive texts appear hard-coded. Ensure they are added to i18n resources and not left as literal English, to keep localization consistent.

<template>
  <div>
    <div class="q-px-md q-py-md">
      <div class="general-page-title">
        {{ t("settings.generalPageTitle") }}
      </div>
      <div class="general-page-subtitle">
        Adjust settings for your Application
      </div>
    </div>
    <!-- platform settings section -->
    <div class="tw-mx-4">
      <GroupHeader title="Platform Settings" :iconPath="store.state.theme == 'dark' ? 'images/common/platform_settings_dark.svg' : 'images/common/platform_settings_light.svg'"/>
      <div class="tw-w-full tw-flex tw-flex-col">
        <q-form @submit.stop="onSubmit.execute">
          <!-- scape interval section -->
          <div class="tw-flex tw-justify-between tw-items-center">
            <div class="tw-flex tw-flex-col tw-items-start">
              <span class="individual-setting-title">
                {{ t('settings.scrapintervalLabel') }}
              </span>
              <span class="individual-setting-description">
                The scrape interval is the frequency, in seconds, at which the monitoring system collects metrics.
              </span>
            </div>
              <q-input
              v-model.number="scrapeIntereval"
              type="number"
              min="0"
              color="input-border"
              bg-color="input-bg"
              class="q-py-md showLabelOnTop o2-numeric-input"
              :class="store.state.theme == 'dark' ? 'o2-numeric-input-dark' : 'o2-numeric-input-light' "
              stack-label
              outlined
              filled
              dense
              :rules="[(val: any) => !!val || 'Scrape interval is required']"
              :lazy-rules="true"
              style="width: 120px;"
              />
          </div>
          <!-- enable web socket search section -->
          <div v-if="store.state.zoConfig.websocket_enabled" class="tw-flex tw-justify-between tw-items-center">
            <div class="tw-flex tw-flex-col tw-items-start">
              <span class="individual-setting-title">
                {{ t('settings.enableWebsocketSearch') }}
              </span>
              <span class="individual-setting-description">
                Websockets Search uses sockets logic to improve performance .
              </span>
            </div>
            <q-toggle
            style="width: 120px;"
              v-model="enableWebsocketSearch"
              :label="'enabled'"
              data-test="general-settings-enable-websocket"
              class="q-pt-md q-pb-md showLabelOnTop"
            />
          </div>
          <!-- enable search streaming section -->
          <div v-if="store.state.zoConfig.streaming_enabled" class="tw-flex tw-justify-between tw-items-center">
            <div class="tw-flex tw-flex-col tw-items-start">
              <span class="individual-setting-title">
                {{ t('settings.enableStreamingSearch') }}
              </span>
              <span class="individual-setting-description">
                Enabling search streaming will increase performance.
              </span>
            </div>
              <q-toggle
              style="width: 120px;"
              v-model="enableStreamingSearch"
              :label="'Enabled'"
              data-test="general-settings-enable-streaming"
              class="q-pb-lg showLabelOnTop"
              />
          </div>
          <!-- enable aggregation cache section -->
          <div v-if="config.isEnterprise == 'true'" class="tw-flex tw-justify-between tw-items-center">
            <div class="tw-flex tw-flex-col tw-items-start">
              <span class="individual-setting-title">
                {{ t('settings.enableStreamingAggregation') }}
              </span>
              <span class="individual-setting-description">
                Enabling streaming aggregates will help improve the performance of aggregate queries.
              </span>
            </div>
                <q-toggle
                style="width: 120px;"
                v-model="enableStreamingAggregation"
                :label="'Enabled'"
                data-test="general-settings-enable-streaming-aggregation"
                class="q-pb-lg showLabelOnTop"
              />
          </div>
          <span>&nbsp;</span>

          <div class="flex justify-start">
            <q-btn
              data-test="dashboard-add-submit"
              :loading="onSubmit.isLoading.value"
              :label="t('dashboard.save')"
              class="q-mb-md o2-primary-button no-border tw-h-[36px]"
              :class="store.state.theme === 'dark' ? 'o2-primary-button-dark' : 'o2-primary-button-light'"
              @click="onSubmit.execute"
              type="submit"
              no-caps
              size="md"
            />
          </div>
        </q-form>
      </div>
    </div>

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Summary

This PR implements a comprehensive UI overhaul across the OpenObserve application, focusing on standardizing table interfaces and introducing a cohesive design system. The changes affect over 25 components and establish a new visual foundation for the entire application.

Key Changes:

  1. Design System Introduction: Added _variables.scss with 230+ color variables covering 11 color families (gray, iris, blue, green, yellow, red, orange, purple, teal) in both light and dark variants, plus semantic CSS custom properties for automatic theme switching.

  2. Component Styling Standardization: Introduced o2-* CSS classes in app.scss for consistent styling across buttons (o2-primary-button, o2-secondary-button), search inputs (o2-search-input), tables (o2-quasar-table), toggles, checkboxes, radio buttons, and tabs.

  3. Table Interface Improvements: Implemented sticky headers and footers across all data tables (alerts, pipelines, reports, IAM modules, streams, functions) with proper scroll behavior. Tables now calculate dynamic heights (typically calc(100vh - 114px)) and only scroll table content while keeping headers/footers visible.

  4. Search Functionality Enhancement: Replaced Quasar's built-in table filtering with custom filtering logic using computed properties (visibleRows, hasVisibleRows) across multiple components. Search inputs now use borderless design with consistent theming.

  5. Navigation Improvements: Updated stream filtering from button-based to modern tab interfaces using the new AppTabs component. Enhanced pagination controls with integrated record counts in table footers.

  6. Theme Integration: All components now support dynamic light/dark theme switching through conditional CSS classes that reference the Vuex store state.

  7. Settings Page Redesign: Complete overhaul of the General Settings page with new GroupHeader component, horizontal form layouts with descriptions, and improved visual hierarchy.

The changes maintain backward compatibility while establishing a foundation for consistent UI/UX across the observability platform. The new design system enables easier maintenance and ensures visual coherence across different modules.

Confidence score: 4/5

  • This PR is generally safe to merge but requires careful review due to the extensive UI changes across the application
  • Score reflects the comprehensive nature of changes and potential for visual regressions, though the code changes are primarily CSS and styling focused
  • Pay close attention to table components, theme switching functionality, and the new variables.scss implementation to ensure no breaking changes

26 files reviewed, 20 comments

Edit Code Review Bot Settings | Greptile

class="no-border q-mr-md o2-search-input tw-h-[36px] tw-w-[200px]"
:class="store.state.theme === 'dark' ? 'o2-search-input-dark' : 'o2-search-input-light'"
:placeholder="`Search Permissions`"
style="width: 300px"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Inline style width: 300px conflicts with Tailwind class tw-w-[200px] - consider removing one for consistency

Suggested change
style="width: 300px"
style=""

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks and fixed it

<template #top="scope">
<div class="tw-flex tw-items-center tw-justify-between tw-w-full q-py-xs ">
<template #top="scope" v-if="!hideTopPagination">
<div v-if="!hideTopPagination" class="tw-flex tw-items-center tw-justify-between tw-w-full q-py-xs ">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Redundant conditional check - the template already has v-if="!hideTopPagination"

Suggested change
<div v-if="!hideTopPagination" class="tw-flex tw-items-center tw-justify-between tw-w-full q-py-xs ">
<div class="tw-flex tw-items-center tw-justify-between tw-w-full q-py-xs ">

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks and removed it

<q-toggle
style="width: 120px;"
v-model="enableWebsocketSearch"
:label="'enabled'"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Toggle label inconsistency: 'enabled' should be 'Enabled' to match lines 91 and 109

Suggested change
:label="'enabled'"
:label="'Enabled'"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks and fixed

class="o2-quasar-table"
class="o2-quasar-table o2-quasar-table-header-sticky"
:class="store.state.theme == 'dark' ? 'o2-quasar-table-dark o2-quasar-table-header-sticky-dark o2-last-row-border-dark' : 'o2-quasar-table-light o2-quasar-table-header-sticky-light o2-last-row-border-light'"
:tableStyle="hasVisibleRows ? 'height: calc(100vh - 250px); overflow-y: auto;' : ''"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Duplicate height calculation - container has same height as tableStyle. Consider removing one to avoid conflicts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed the top height

{{ t('settings.enableWebsocketSearch') }}
</span>
<span class="individual-setting-description">
Websockets Search uses sockets logic to improve performance .
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: Extra space before period in 'performance .'

Suggested change
Websockets Search uses sockets logic to improve performance .
Websockets Search uses sockets logic to improve performance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed

Comment on lines +529 to +539
const visibleRows = computed(() => {
if (!filterQuery.value) return reportsTableRows.value || [];
return filterData(reportsTableRows.value || [], filterQuery.value);
});
const hasVisibleRows = computed(() => visibleRows.value.length > 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: The visibleRows computed property doesn't account for tab filtering - it only applies search filtering to reportsTableRows, potentially showing cached reports when scheduled tab is active

Suggested change
const visibleRows = computed(() => {
if (!filterQuery.value) return reportsTableRows.value || [];
return filterData(reportsTableRows.value || [], filterQuery.value);
});
const hasVisibleRows = computed(() => visibleRows.value.length > 0)
const visibleRows = computed(() => {
const filteredByTab = reportsTableRows.value || [];
if (!filterQuery.value) return filteredByTab;
return filterData(filteredByTab, filterQuery.value);
});
const hasVisibleRows = computed(() => visibleRows.value.length > 0)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NO we are using computed right it will get updated eventually

{{ t("iam.groups") }}
</div>
<div class=" row items-center justify-end">
<div date-test="iam-groups-search-input">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: typo in data-test attribute: 'date-test' should be 'data-test'

Suggested change
<div date-test="iam-groups-search-input">
<div data-test="iam-groups-search-input">

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not there

</q-input>
</div>
<q-btn
data-test="alert-list-add-alert-btn"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: data-test attribute references 'alert-list-add-alert-btn' but this is for groups - should be 'iam-groups-add-group-btn' for consistency

Suggested change
data-test="alert-list-add-alert-btn"
data-test="iam-groups-add-group-btn"

:pagination="pagination"
:filter="filterQuery"
:filter-method="filterData"
:style="hasVisibleRows ? 'height: calc(100vh - 114px); overflow-y: auto;' : ''"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: The height calculation calc(100vh - 114px) is hardcoded and might break if the header height changes. Consider using CSS custom properties for maintainability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No the header height is constant

class="col-6"
:placeholder="t('iam.searchRole')"
class="q-ml-auto no-border o2-search-input tw-h-[36px]"
:placeholder="t('iam.searchGroup')"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Incorrect placeholder text - should be 'iam.searchRole' not 'iam.searchGroup' for consistency

Suggested change
:placeholder="t('iam.searchGroup')"
:placeholder="t('iam.searchRole')"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is fixed

@github-actions
Copy link
Contributor

github-actions bot commented Aug 18, 2025

PR Code Suggestions ✨

Latest suggestions up to 5c3d466

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix hidden search input text

The rule sets color: transparent !important; on the control, which can hide
placeholder and typed text in search inputs, breaking usability and tests using
getByPlaceholder. Remove this and style nested elements without obscuring text. Also
drop the debug background-color: red on focus highlight.

web/src/styles/app.scss [504-528]

 .o2-search-input{
   height: 36px !important;
   .q-field__control{
-  height: 36px !important;
-  border-radius: 4px !important;
-  display: flex;
-  align-items: end;
-  font-size: 13px;
-  padding: 0px 6px !important;
-  font-weight: 500 !important;
-  color: transparent !important;
-}
+    height: 36px !important;
+    border-radius: 4px !important;
+    display: flex;
+    align-items: center;
+    font-size: 13px;
+    padding: 0px 6px !important;
+    font-weight: 500 !important;
+  }
   .q-field__prepend{
     height: 36px !important;
     padding-bottom: 4px !important;
   }
   .q-field--highlighted{
     .q-field__control{
-      background-color: red !important;
+      /* keep focus ring handled by theme variants below */
+      background-color: inherit !important;
     }
   }
   .q-field__append{
     padding-top: 8px !important;
   }
 }
Suggestion importance[1-10]: 9

__

Why: The CSS sets color: transparent !important on .o2-search-input .q-field__control, which can hide placeholder and user input, breaking accessibility and tests; removing it and the debug red background is a clear, high-impact fix aligned with the new styles.

High
Enable vertical scrolling

The inline height: calc(100vh - 118px) lacks overflow-y: auto, causing the table
body to overflow the viewport without scrolling. Add vertical overflow to keep
content accessible and prevent layout breakage.

web/src/plugins/logs/SearchSchedulersList.vue [53-59]

 <q-table
   data-test="search-scheduler-table"
   ref="qTableSchedule"
   :rows="dataToBeLoaded"
   :columns="columns"
   :pagination="pagination"
   row-key="trace_id"
   :rows-per-page-options="[]"
   class="o2-quasar-table o2-quasar-table-header-sticky"
   :class="store.state.theme == 'dark' ? ' o2-quasar-table-dark o2-quasar-table-header-sticky-dark' : 'o2-quasar-table-light o2-quasar-table-header-sticky-light'"
-  :style="dataToBeLoaded.length > 0 ? 'width: 100%; height: calc(100vh - 118px)'  : 'width: 100%'"
+  :style="dataToBeLoaded.length > 0 ? 'width: 100%; height: calc(100vh - 118px); overflow-y: auto;'  : 'width: 100%'"
   :sort-method="sortMethod"
 >
Suggestion importance[1-10]: 7

__

Why: The table’s inline style omits vertical overflow when constrained by viewport height; adding overflow-y: auto improves usability and matches similar patterns elsewhere in the PR. Clear, low-risk enhancement.

Medium
Sync pagination with filtered rows

You removed the built-in :filter/:filter-method props and introduced visibleRows,
but resultTotal and pagination likely still calculate from the unfiltered dataset.
Ensure counts and pagination derive from visibleRows to avoid mismatched totals and
empty pages when filtering.

web/src/components/settings/CipherKeys.vue [53-64]

 <q-table
   ref="qTable"
   :rows="visibleRows"
   :columns="columns"
   row-key="id"
   :pagination="pagination"
   class="o2-quasar-table o2-quasar-table-header-sticky"
   :style="hasVisibleRows
       ? 'width: 100%; height: calc(100vh - 158px); overflow-y: auto;' 
       : 'width: 100%'"
   :class="store.state.theme == 'dark' ? 'o2-quasar-table-dark o2-quasar-table-header-sticky-dark o2-last-row-border-dark' : 'o2-quasar-table-light o2-quasar-table-header-sticky-light o2-last-row-border-light'"
+  @request="(props) => { pagination = props.pagination }"
 >
Suggestion importance[1-10]: 6

__

Why: Moving to visibleRows removes Quasar's built-in filtering, so pagination/total may desync; recommending syncing pagination is reasonable, but adding @request alone may not fully solve totals. Moderate impact and partially specified fix.

Low
Stabilize dynamic table height

Inline style strings with calc heights can break on small viewports or when header
height changes, causing overflow or clipped content. Bind a computed style that sets
height only when needed and uses consistent constants to avoid off-by-one issues.

web/src/views/LogStream.vue [91-93]

-:style="logStream?.length
-        ? 'width: 100%; height: calc(100vh - 114px)' 
-        : 'width: 100%'"
+:style="{
+  width: '100%',
+  height: (logStream && logStream.length > 0) ? 'calc(100vh - 114px)' : undefined
+}"
Suggestion importance[1-10]: 5

__

Why: Replacing the inline string with an object style is a reasonable refactor that can make the binding clearer and avoid setting height when not needed. It's a minor maintainability improvement; functionality remains the same.

Low
Ensure checkbox selection updates correctly

Passing the event handler reference directly risks losing the intended boolean
argument, leading to inconsistent selection. Wrap the call to forward the emitted
value to props.select(val) ensuring proper toggling.

web/src/components/pipeline/PipelinesList.vue [288-294]

 <q-checkbox
   v-model="props.selected"
   size="sm"
   :class="store.state.theme === 'dark' ? 'o2-table-checkbox-dark' : 'o2-table-checkbox-light'"
   class="o2-table-checkbox"
-  @update:model-value="props.select"
+  @update:model-value="(val) => props.select(val)"
 />
Suggestion importance[1-10]: 4

__

Why: Wrapping the handler with (val) => props.select(val) aligns with Quasar’s event signature and is harmless, but the existing @update:model-value="props.select" already works. This is a small, non-critical tweak.

Low
General
Align button props for consistency

The button mixes the deprecated padding prop with flat-style classes and theming;
Quasar ignores padding on flat buttons, and lack of flat causes visual inconsistency
with other updated buttons. Add flat and remove padding for consistent behavior.

web/src/components/alerts/ImportAlert.vue [46-51]

 <q-btn
   class="o2-primary-button no-border tw-h-[36px]"
   :class="store.state.theme === 'dark' ? 'o2-primary-button-dark' : 'o2-primary-button-light'"
   :label="t('dashboard.import')"
   type="submit"
-  padding="sm xl"
   no-caps
+  flat
 />
Suggestion importance[1-10]: 8

__

Why: The PR modernizes buttons to use themed classes and flat; this instance still includes padding="sm xl" without flat. Removing padding and adding flat matches the new pattern, improving consistency and visual correctness.

Medium
Avoid reactive callback in dialog state

Storing a mutable callback inside reactive state can create stale references across
re-renders. Keep the callback stable and only store a boolean plus static text in
state; invoke the delete handler directly on confirm.

web/src/components/pipeline/NodeForm/ExternalDestination.vue [354-359]

 const dialog = ref({
   show: false,
-  title: "",
-  message: "",
-  okCallback: () => {},
+  title: "Delete Node",
+  message: "Are you sure you want to delete stream routing?",
 });
-...
 const openDeleteDialog = () => {
   dialog.value.show = true;
-  dialog.value.title = "Delete Node";
-  dialog.value.message = "Are you sure you want to delete stream routing?";
-  dialog.value.okCallback = deleteRoute;
 };
+const onConfirmDelete = () => {
+  deletePipelineNode(pipelineObj.currentSelectedNodeID);
+  emit("cancel:hideform");
+  dialog.value.show = false;
+};
+...
+<confirm-dialog
+  v-model="dialog.show"
+  :title="dialog.title"
+  :message="dialog.message"
+  @update:ok="onConfirmDelete"
+  @update:cancel="() => (dialog.value.show = false)"
+/>
Suggestion importance[1-10]: 7

__

Why: Moving the confirm logic out of reactive state avoids potential stale references and simplifies dialog state. It's accurate given the new dialog usage and improves robustness without altering behavior.

Medium
Stabilize test selector for search

Using a hardcoded placeholder string makes tests brittle to i18n or copy changes.
Prefer a data-test attribute to locate the search input consistently. Update the
selector to a stable data-test and use locator instead of placeholder-based queries.

tests/ui-testing/pages/alertsPages/alertTemplatesPage.js [20-23]

-this.templateSearchInput = 'Search Template';
+this.templateSearchInput = '[data-test="template-list-search-input"]';
 ...
-await this.page.getByPlaceholder(this.templateSearchInput).click();
-await this.page.getByPlaceholder(this.templateSearchInput).fill(templateName);
+await this.page.locator(this.templateSearchInput).click();
+await this.page.locator(this.templateSearchInput).fill(templateName);
Suggestion importance[1-10]: 7

__

Why: The PR changed the tests to rely on a placeholder string ('Search Template') instead of the previous data-test selector; recommending a stable data-test improves robustness, though it conflicts with the PR’s new approach rather than a clear bug.

Medium
Handle cancel to close dialog

This button now relies on a dialog that can be closed via a new @cancel:hideform
event. Ensure the dialog's visibility is toggled consistently on both save and
cancel; wire the cancel event in the parent to reset showAddDialog to avoid a stuck
open state.

web/src/components/iam/organizations/ListOrganizations.vue [105-109]

-<q-btn
-  class="q-ml-md o2-primary-button tw-h-[36px]"
-  flat
-  :class="store.state.theme === 'dark' ? 'o2-primary-button-dark' : 'o2-primary-button-light'"
-  no-caps
-  :label="t(`organization.add`)"
-  @click="addOrganization"
-  data-test="Add Organization"
-/>
+<q-dialog
+  v-model="showAddDialog"
+  persistent
+  maximized
+  @before-hide="hideAddOrgDialog"
+>
+  <add-update-organization
+    @updated="updateOrganizationList"
+    @cancel:hideform="() => { showAddDialog = false }"
+  />
+</q-dialog>
Suggestion importance[1-10]: 6

__

Why: The PR introduced @cancel:hideform on the child; wiring it to set showAddDialog = false in the parent prevents stuck dialogs. Useful integration detail, though the PR already adds the event hook; this clarifies consistent state handling.

Low

Previous suggestions

Suggestions up to commit 56b9282
CategorySuggestion                                                                                                                                    Impact
Possible issue
Avoid duplicate filtering

You now pre-filter rows via visibleRows but still pass :filter and :filter-method to
q-table. This double-filtering can cause empty or inconsistent results. Remove the
table-level filtering and rely solely on visibleRows.

web/src/components/reports/ReportList.vue [69-81]

 <q-table
   data-test="report-list-table"
   ref="reportListTableRef"
   :rows="visibleRows"
   :columns="columns"
   row-key="id"
   :pagination="pagination"
-  :filter="filterQuery"
-  :filter-method="filterData"
-  style="width: 100%"
   :style="hasVisibleRows
       ? 'width: 100%; height: calc(100vh - 114px)' 
       : 'width: 100%'"
 >
Suggestion importance[1-10]: 8

__

Why: The table already uses visibleRows while also passing :filter and :filter-method, leading to double filtering and inconsistent results; removing table-level filtering is correct and improves correctness.

Medium
Remove redundant table filter

Since visibleRows already contains filtered data, passing :filter="filterQuery" may
lead to unexpected behavior and mismatched counts. Remove the :filter binding from
the table to prevent double-filtering.

web/src/components/functions/FunctionList.vue [52-64]

 <q-table
   ref="qTable"
   :rows="visibleRows"
   :columns="columns"
   row-key="id"
   :pagination="pagination"
-  :filter="filterQuery"
   style="width: 100%"
   :style="hasVisibleRows
       ? 'width: 100%; height: calc(100vh - 114px)' 
       : 'width: 100%'"
   class="o2-quasar-table o2-quasar-table-header-sticky"
   :class="store.state.theme === 'dark' ? 'o2-quasar-table-dark o2-quasar-table-header-sticky-dark o2-last-row-border-dark' : 'o2-quasar-table-light o2-quasar-table-header-sticky-light o2-last-row-border-light'"
 >
Suggestion importance[1-10]: 8

__

Why: visibleRows is pre-filtered; keeping :filter="filterQuery" can cause double filtering and mismatched counts. Removing it aligns with the new pattern and avoids bugs.

Medium
Prevent double form submission

The button is both type="submit" and has a click handler, which can result in
duplicate submissions if inside a form. Remove the submit type and rely on the
explicit click, or keep submit and remove the click handler.

web/src/components/pipeline/ImportPipeline.vue [44-52]

 <q-btn
   class="o2-primary-button no-border tw-h-[36px]"
   :label="t('dashboard.import')"
-  type="submit"
   no-caps
   flat
   :class="store.state.theme === 'dark' ? 'o2-primary-button-dark' : 'o2-primary-button-light'"
   @click="importJson"
   data-test="pipeline-import-json-btn"
 />
Suggestion importance[1-10]: 8

__

Why: Having both type="submit" and @click can cause duplicate submissions in forms; removing one is a practical fix that prevents a potential bug without functional loss.

Medium
Show accurate total count

Using rows.length for the count ignores server-side pagination and filtering, and
may display incorrect totals. Bind to resultTotal when provided, falling back to
rows.length only if resultTotal is unavailable.

web/src/components/AppTable.vue [62-65]

 <template #top="scope" v-if="!hideTopPagination">
-  <div v-if="!hideTopPagination" class="tw-flex tw-items-center tw-justify-between tw-w-full q-py-xs  "> 
+  <div class="tw-flex tw-items-center tw-justify-between tw-w-full q-py-xs">
     <span class="tw-font-bold tw-text-[14px] tw-w-full q-pa-none">
-    {{ rows.length }} {{ title }}
-  </span>
+      {{ typeof resultTotal === 'number' && resultTotal >= 0 ? resultTotal : rows.length }} {{ title }}
+    </span>
Suggestion importance[1-10]: 7

__

Why: Correctly points out that rows.length may be inaccurate with server-side totals; switching to resultTotal when present improves correctness. The change is localized and low risk.

Medium
Guard array length check

The inline style string uses logStream?.length, which Vue template expressions don't
support with optional chaining in all build setups and can evaluate to undefined at
runtime. Replace with a safe length check to avoid rendering errors when logStream
is null/undefined.

web/src/views/LogStream.vue [91-93]

-:style="logStream?.length
-        ? 'width: 100%; height: calc(100vh - 114px)' 
+:style="Array.isArray(logStream) && logStream.length
+        ? 'width: 100%; height: calc(100vh - 114px)'
         : 'width: 100%'"
Suggestion importance[1-10]: 6

__

Why: Using optional chaining in templates can be brittle; replacing with an explicit array check is a safe, low-risk improvement. It modestly improves robustness without changing behavior.

Low
Fix table selection handler

Quasar's QTable provides props.select as a method to toggle selection without
parameters; assigning it directly as an event handler with the emitted boolean can
break selection behavior. Wrap the call to pass the emitted value explicitly to
props.select to ensure correct selection state.

web/src/components/pipeline/PipelinesList.vue [288-294]

 <q-checkbox
   v-model="props.selected"
   size="sm"
   :class="store.state.theme === 'dark' ? 'o2-table-checkbox-dark' : 'o2-table-checkbox-light'"
   class="o2-table-checkbox"
-  @update:model-value="props.select"
+  @update:model-value="val => props.select(val)"
 />
Suggestion importance[1-10]: 5

__

Why: Wrapping the event to pass the emitted value ensures props.select receives the boolean, which can improve selection correctness. Impact is moderate and context-dependent but aligns with Quasar patterns.

Low
General
Prevent double form submission

The button both calls onSubmit.execute via click and also has type="submit" inside a
form that already handles submit, causing duplicate submissions. Remove one trigger
to prevent double requests. Keeping only type="submit" is cleaner.

web/src/components/settings/General.vue [117-128]

 <q-btn
   data-test="dashboard-add-submit"
   :loading="onSubmit.isLoading.value"
   :label="t('dashboard.save')"
   class="q-mb-md o2-primary-button no-border tw-h-[36px]"
   :class="store.state.theme === 'dark' ? 'o2-primary-button-dark' : 'o2-primary-button-light'"
-  @click="onSubmit.execute"
   type="submit"
   no-caps
   size="md"
 />
Suggestion importance[1-10]: 8

__

Why: The button is inside a form with a submit handler and also calls the submit function on click, which risks duplicate submissions; removing the click handler is accurate and prevents a real bug.

Medium
Use explicit destructive styling

The delete button uses the generic secondary styling while indicating a destructive
action with color="negative". This can reduce affordance and accessibility. Apply a
clear negative style to the button to reflect the destructive action consistently
across themes.

web/src/components/pipeline/NodeForm/ExternalDestination.vue [247-259]

 <q-btn
     v-if="pipelineObj.isEditNode && !createNewDestination"
     data-test="add-condition-delete-btn"
-    class="o2-secondary-button tw-h-[36px] q-mr-md"
+    class="o2-danger-button tw-h-[36px] q-mr-md"
+    :class="store.state.theme === 'dark' ? 'o2-danger-button-dark' : 'o2-danger-button-light'"
     color="negative"
-    flat
-    :class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
+    unelevated
     no-caps
     @click="openDeleteDialog"
   >
   <q-icon name="delete" class="q-mr-xs" />
   {{ t('pipeline.deleteNode') }}
 </q-btn>
Suggestion importance[1-10]: 5

__

Why: The change is stylistic to better convey destructive action; it's reasonable but depends on existing design system (o2-danger-button classes may not exist), so impact is moderate and somewhat speculative.

Low
Restore close navigation behavior

The header close icon now emits cancel:hideform, but the previous implementation
also navigated back to the organizations route. If the parent does not handle this
emit, the dialog may remain open without navigation. Ensure both closing and
navigation are triggered to preserve previous behavior.

web/src/components/iam/organizations/AddUpdateOrganization.vue [34-41]

 <q-icon
   data-test="add-role-close-dialog-btn"
   name="cancel"
   class="cursor-pointer"
   size="20px"
-  @click="$emit('cancel:hideform')"
+  @click="
+    $emit('cancel:hideform');
+    router.replace({ name: 'organizations' })
+  "
 />
Suggestion importance[1-10]: 5

__

Why: It’s reasonable to ensure navigation on close to match prior behavior, but this depends on parent handling and UX decisions; not strictly required by the PR and may duplicate parent logic.

Low
Suggestions up to commit c31b1ee
CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix incorrect placeholder key

The placeholder uses t('iam.searchGroup') on the Roles page, which is likely
incorrect and confusing. Update it to the correct roles-related translation key for
consistency and clarity.

web/src/components/iam/roles/AppRoles.vue [30-37]

 <q-input
   v-model="filterQuery"
   borderless
   dense
   class="q-ml-auto no-border o2-search-input tw-h-[36px]"
-  :placeholder="t('iam.searchGroup')"
+  :placeholder="t('iam.searchRole')"
   :class="store.state.theme === 'dark' ? 'o2-search-input-dark' : 'o2-search-input-light'"
 >
Suggestion importance[1-10]: 8

__

Why: In the Roles page the placeholder uses t('iam.searchGroup') instead of t('iam.searchRole'), which is a clear correctness issue and confusing to users; the fix is accurate and directly mapped to the shown code.

Medium
Avoid double client-side filtering

The table uses a custom visibleRows client-side filter but still passes
:filter="filterQuery". This double-filtering can produce empty results or mismatched
pagination. Remove the :filter binding when using prefiltered rows.

web/src/components/pipeline/PipelinesList.vue [82-98]

 <q-table
   data-test="pipeline-list-table"
   ref="qTableRef"
   :rows="visibleRows"
   :columns="columns"
   row-key="name"
   :pagination="pagination"
-  :filter="filterQuery"
   style="width: 100%"
   selection="multiple"
   v-model:selected="selectedPipelines"
   :style="hasVisibleRows
       ? 'width: 100%; height: calc(100vh - 114px)' 
       : 'width: 100%'"
   class="o2-quasar-table o2-quasar-table-header-sticky "
   :class="store.state.theme === 'dark' ? 'o2-quasar-table-dark o2-quasar-table-header-sticky-dark' : 'o2-quasar-table-light o2-quasar-table-header-sticky-light'"
 >
   ...
   <template v-slot:header="props">
     <q-tr :props="props">
       <q-th auto-width>
         <q-checkbox
           v-model="props.selected"
           size="sm"
           :class="store.state.theme === 'dark' ? 'o2-table-checkbox-dark' : 'o2-table-checkbox-light'"
           class="o2-table-checkbox"
           @update:model-value="props.select"
         />
       </q-th>
Suggestion importance[1-10]: 7

__

Why: The component now computes visibleRows and still passes :filter="filterQuery", which can lead to double filtering and pagination mismatches; removing the :filter binding is a reasonable improvement and consistent with the new code.

Medium
General
Prevent table overflow/misalignment

Setting a fixed width on all columns can cause horizontal overflow and header/body
misalignment when the viewport is narrow. Use min-width and max-width or only
min-width for flexible layouts while preserving sticky header alignment.

web/src/plugins/logs/SearchSchedulersList.vue [545-553]

 return {
-  name: key, // Field name
-  label: label, // Column label
-  field: key, // Field accessor
-  align: align,
-  sortable: sortable,
-  classes: classes,
-  style: `max-width: ${columnWidth}px; width: ${columnWidth}px;`,
+  name: key,
+  label: label,
+  field: key,
+  align,
+  sortable,
+  classes,
+  style: `min-width: ${columnWidth}px; max-width: ${columnWidth}px;`,
 };
Suggestion importance[1-10]: 6

__

Why: Switching from fixed width to min-width/max-width can improve responsiveness and avoid overflow; it aligns with the table’s sticky header and dynamic classes, though the current fixed widths are not necessarily incorrect.

Low
Remove redundant conditional

You already gate the slot with v-if="!hideTopPagination". The inner v-if duplicates
the condition and can lead to unnecessary DOM churn. Remove the inner v-if for
cleaner logic and to avoid potential rendering inconsistencies.

web/src/components/AppTable.vue [62-65]

 <template #top="scope" v-if="!hideTopPagination">
-  <div v-if="!hideTopPagination" class="tw-flex tw-items-center tw-justify-between tw-w-full q-py-xs  "> 
+  <div class="tw-flex tw-items-center tw-justify-between tw-w-full q-py-xs"> 
     <span class="tw-font-bold tw-text-[14px] tw-w-full q-pa-none">
-    {{ rows.length }} {{ title }}
-  </span>
+      {{ rows.length }} {{ title }}
+    </span>
Suggestion importance[1-10]: 6

__

Why: The inner v-if="!hideTopPagination" duplicates the slot condition, and removing it simplifies rendering without changing behavior; it's a minor but valid cleanup.

Low
Replace optional chaining in template

Using logStream?.length in templates can break in environments that don't support
optional chaining in inline strings, causing render errors. Replace with a computed
boolean like hasRows and reference it in the binding.

web/src/views/LogStream.vue [91-93]

-:style="logStream?.length
+:style="hasRows
       ? 'width: 100%; height: calc(100vh - 114px)' 
       : 'width: 100%'"
Suggestion importance[1-10]: 3

__

Why: While using a computed like hasRows is cleaner, Vue template expressions support optional chaining in modern builds; this is a minor stylistic change with limited impact and requires adding hasRows not shown in the PR.

Low
Ensure correct icon placement

The button uses both label and icon props without specifying icon-right, which may
place the icon before text unintentionally. If you need the icon after the label,
add icon-right="add"; otherwise, keep icon and remove label in favor of a slot for
precise layout.

web/src/components/common/sidebar/FolderList.vue [115-126]

 <q-btn
-    class="text-bold o2-secondary-button tw-mx-1 tw-w-full"
-    :class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
-    no-caps
-    flat
-    label="New Folder"
-    @click.stop="addFolder"
-    data-test="dashboard-new-folder-btn"
-    icon="add"
-  >
-</q-btn>
+  class="text-bold o2-secondary-button tw-mx-1 tw-w-full"
+  :class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
+  no-caps
+  flat
+  icon="add"
+  label="New Folder"
+  icon-right="add"
+  @click.stop="addFolder"
+  data-test="dashboard-new-folder-btn"
+/>
Suggestion importance[1-10]: 3

__

Why: Using label with icon is valid; adding icon-right changes the design intent and may duplicate the icon if not desired. This is optional UI adjustment with limited impact.

Low

@nikhilsaikethe nikhilsaikethe marked this pull request as draft August 20, 2025 07:45
@nikhilsaikethe nikhilsaikethe force-pushed the o2-ui-improvements branch 4 times, most recently from 18fcb1e to bd6bbb6 Compare August 28, 2025 04:20
@nikhilsaikethe nikhilsaikethe marked this pull request as ready for review August 28, 2025 06:34
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Summary

This PR implements a comprehensive UI overhaul across the OpenObserve application, focusing on standardizing table interfaces, design systems, and user experience patterns. The changes introduce a centralized design system through a new _variables.scss file containing color palettes and semantic tokens, along with extensive updates to app.scss that define reusable CSS classes for buttons, inputs, tables, and other UI components.

The core improvements include:

  • Sticky table headers and footers: All table components now implement sticky behavior using new CSS classes like o2-quasar-table-header-sticky, ensuring navigation controls remain visible during scrolling
  • Unified design system: Introduction of standardized button classes (o2-primary-button, o2-secondary-button) with theme-aware dark/light variants, search input styling (o2-search-input), and consistent toggle components
  • Client-side filtering: Migration from server-side table filtering to computed properties (visibleRows, hasVisibleRows) for better performance and real-time search across all table components
  • Enhanced AppTable component: Added new props like tableStyle, hideTopPagination, and showBottomPaginationWithTitle to support consistent table behavior
  • New reusable components: Introduction of GroupHeader.vue for standardized section headers and improved AppTabs integration
  • General Settings redesign: Complete UI overhaul with horizontal layouts, better visual hierarchy, and consistent form controls

The changes affect over 80 components across the application including AlertList, PipelinesList, ReportList, all IAM modules (Users, Groups, Roles, Service Accounts), Functions, Logs, and various settings pages. Height calculations have been adjusted throughout (typically from 57px to smaller values like 42px or 65px) to accommodate redesigned headers. The implementation maintains backward compatibility while significantly improving visual consistency and user experience patterns across the entire application.

Confidence score: 4/5

  • This PR introduces extensive UI improvements with well-structured design system patterns that should enhance user experience and maintainability
  • Score reflects some concerns about hardcoded height calculations, potential CSS conflicts, and missing error handling in a few components that could cause runtime issues
  • Pay close attention to FilterCreatorPopup.vue which references store without importing it, and _variables.scss which has duplicate color values that need correction

71 files reviewed, 20 comments

Edit Code Review Bot Settings | Greptile

})
"
<q-icon
data-test="add-role-close-dialog-btn"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: data-test attribute references 'add-role-close-dialog-btn' but this is for adding users - should be 'add-user-close-dialog-btn' for consistency

Suggested change
data-test="add-role-close-dialog-btn"
data-test="add-user-close-dialog-btn"

style="min-width: 0px !important;"
:class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Inline style min-width: 0px !important; conflicts with Tailwind classes - consider using Tailwind's tw-min-w-0 instead

Suggested change
style="min-width: 0px !important;"
:class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
class="pipeline-icons q-px-sm q-ml-sm hideOnPrintMode tw-h-[36px] tw-min-w-0 o2-secondary-button"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

padding="sm xl"
no-caps
flat
:class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Theme class binding uses conditional logic but both buttons have the same @click handler - router.back() is called twice on the Cancel button (v-close-popup and @click)

icon="close"
@click="router.replace({ name: 'organizations' })"
<q-icon
data-test="add-role-close-dialog-btn"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Inconsistent data-test attribute - uses 'add-role-close-dialog-btn' but this is for organizations, should be 'add-org-close-dialog-btn'

Suggested change
data-test="add-role-close-dialog-btn"
data-test="add-org-close-dialog-btn"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

<div class="q-table__title tw-font-[600]" data-test="pipeline-list-title">
{{ t("pipeline.header") }}
</div>
<div class="tw-flex tw-items-centertabs q-ml-auto">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: Typo in class name: 'tw-items-centertabs' should be 'tw-items-center'

Suggested change
<div class="tw-flex tw-items-centertabs q-ml-auto">
<div class="tw-flex tw-items-center q-ml-auto">

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Folders
<div>
<q-btn
class="text-bold o2-secondary-button tw-w-full tw-h-[28px] tw-w-[32px]"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Conflicting width classes - both tw-w-full and tw-w-[32px] are applied, with the latter taking precedence

Suggested change
class="text-bold o2-secondary-button tw-w-full tw-h-[28px] tw-w-[32px]"
class="text-bold o2-secondary-button tw-h-[28px] tw-w-[32px]"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed it

default: "",
}
},
setup(props, { emit }) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: The emit parameter in setup function is unused - consider removing it for cleaner code

Suggested change
setup(props, { emit }) {
setup(props) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is fine

Comment on lines 126 to 131
<div
class="row justify-center full-width q-px-xs q-pb-xs"
class="row full-width q-pb-xs"
style="position: sticky; bottom: 0px"
>
<q-btn
class="text-bold no-border full-width"
padding="sm lg"
color="secondary"
no-caps
label="New Folder"
@click.stop="addFolder"
data-test="dashboard-new-folder-btn"
/>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Empty div container at bottom serves no purpose - consider removing this section entirely

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed it

export default defineComponent({
name: "GroupHeader",
components: {},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Empty components object can be removed since no components are being registered

Suggested change
components: {},
export default defineComponent({
name: "GroupHeader",
props: {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine for future reference we kept that

Comment on lines 1091 to 1094
class="o2-secondary-button tw-h-[36px]"
color="negative"
flat
:class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: The delete button now uses both color="negative" and conditional theme classes. The color prop might conflict with the theme-specific classes - consider removing the color prop if the theme classes handle the negative styling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks and fixed

@github-actions
Copy link
Contributor

Persistent review updated to latest commit 56b9282

@nikhilsaikethe nikhilsaikethe marked this pull request as draft August 31, 2025 09:08
@nikhilsaikethe nikhilsaikethe marked this pull request as ready for review September 2, 2025 06:25
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Summary

This PR implements a comprehensive UI redesign across the OpenObserve application, introducing a new design system called "O2" that standardizes the visual appearance and user experience. The changes affect over 75 files and include:

Design System Implementation:

  • Added new SCSS variables file (_variables.scss) with comprehensive color palette and semantic CSS custom properties for light/dark themes
  • Introduced standardized component classes (o2-primary-button, o2-secondary-button, o2-search-input, o2-toggle-button, etc.)
  • Created consistent theming with proper dark/light mode support across all components

Table Component Overhaul:

  • Implemented sticky headers and footers across all list components (AlertList, PipelinesList, FunctionList, ReportList, etc.)
  • Replaced Quasar's built-in table filtering with computed properties (visibleRows/hasVisibleRows) for better control over display logic
  • Added dynamic height calculations that prevent empty table space when filters return no results
  • Standardized pagination from 25 to 20 items per page across components

UI Component Standardization:

  • Replaced filter buttons with AppTabs component for better UX in stream filtering
  • Updated all buttons to use consistent styling classes with theme-aware variants
  • Redesigned search inputs with borderless design and consistent icon placement
  • Standardized toggle components with size variants (sm/lg) and proper theming
  • Created GroupHeader component for consistent section headers

Layout Improvements:

  • Added sticky positioning for table headers and footers to improve navigation in large datasets
  • Implemented consistent spacing using Tailwind utility classes
  • Updated form layouts to use left-aligned buttons instead of center-aligned
  • Added proper responsive behavior with gap and wrap properties

The changes maintain all existing functionality while providing a more cohesive, professional, and maintainable design system. The new O2 classes enable centralized styling management and easier future updates across the entire application.

Confidence score: 4/5

  • This PR is generally safe to merge with careful review of specific implementation details
  • Score reflects the comprehensive nature of changes requiring thorough testing, but clean implementation patterns
  • Pay close attention to computed property implementations, hardcoded height calculations, and theme class consistency

72 files reviewed, 6 comments

Edit Code Review Bot Settings | Greptile

outlined
filled
dense
class="q-mt-sm o2-toggle-button-lg tw-mr-3 -tw-ml-4"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Negative left margin -tw-ml-4 seems unusual for a toggle button - verify this doesn't cause alignment issues with other form elements

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes ew kept it purposely

<template v-if="rows.length">
<app-table
:rows="rows"
:rows="visibleRows"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Using visibleRows computed property but also passing filter prop - this creates redundant filtering logic that could cause confusion

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

data-test="add-action-script-step2-back-btn"
@click="step = 1"
flat
class="o2-secondary-button tw-h-[36px] q-ml-sm"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Extra space in class name 'q-ml-sm' - should this be 'q-ml-md' to match line 386?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

Comment on lines 69 to 71
:class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
@click="$emit('cancel:hideform')"
data-test="add-alert-cancel-btn"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: Inconsistent event handling - line 70 uses $emit('cancel:hideform') while line 29 uses emits('cancel:hideform'). Should use emits consistently.

Suggested change
:class="store.state.theme === 'dark' ? 'o2-secondary-button-dark' : 'o2-secondary-button-light'"
@click="$emit('cancel:hideform')"
data-test="add-alert-cancel-btn"
@click="emits('cancel:hideform')"
data-test="add-alert-cancel-btn"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

</div>
</div>
<div class="flex justify-center q-mt-lg">
<div class="flex justify-start q-ml-md ">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax: Extra space in class string after 'q-ml-md'

Suggested change
<div class="flex justify-start q-ml-md ">
<div class="flex justify-start q-ml-md">

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

v-if="pipelineObj.isEditNode"
data-test="associate-function-delete-btn"
class="o2-secondary-button tw-h-[36px] q-mr-md"
color="negative"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Using color="negative" with theme-specific button classes may create styling conflicts - consider removing the color prop

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@github-actions
Copy link
Contributor

github-actions bot commented Sep 2, 2025

Persistent review updated to latest commit 5c3d466

@nikhilsaikethe nikhilsaikethe force-pushed the o2-ui-improvements branch 7 times, most recently from 2eaf629 to 2edf9b9 Compare September 11, 2025 10:02
fix: checkboxes as per design for alertlist

fix: radio button as per new design system added to add alert

fix: general setting , platform settings modified as per design

fix: numeric input in general settings as per design

fix: introduced all variables according to design

fix: secondarybtn , primary btn , tabs , search input added

fix: another major change related to tabs , sticky header and footer table
@nikhilsaikethe nikhilsaikethe merged commit 52e11d3 into main Sep 11, 2025
28 checks passed
@nikhilsaikethe nikhilsaikethe deleted the o2-ui-improvements branch September 11, 2025 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants