This is an automated email from the ASF dual-hosted git repository.

chanholee pushed a commit to branch branch-0.12
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/branch-0.12 by this push:
     new 108cb6eb03 [ZEPPELIN-6162] Implement revisions comparator for New UI
108cb6eb03 is described below

commit 108cb6eb03ad662ea8e293f15e9b78b08629d079
Author: Prabhjyot Singh <[email protected]>
AuthorDate: Sun Mar 1 08:54:45 2026 -0500

    [ZEPPELIN-6162] Implement revisions comparator for New UI
    
    ### What is this PR for?
    Port the revision comparison feature from the legacy AngularJS UI to the 
new Angular 13 frontend. Users can now select two revisions and view 
paragraph-by-paragraph diffs with color-coded additions and deletions.
    
    ### What type of PR is it?
    Improvement
    
    ### What is the Jira issue?
    * https://issues.apache.org/jira/browse/ZEPPELIN-6162
    
    ### How should this be tested?
    * Strongly recommended: add automated unit tests for any new or changed 
behavior
    * Outline any manual steps to test the PR here.
    
    ### Screenshots (if appropriate)
    
![ZEPPELIN-6162](https://github.com/user-attachments/assets/483c05e1-9fa0-4347-8f50-21d0fbd90db2)
    
    ### Questions:
    * Does the license files need to update? no
    * Is there breaking changes for older versions? no
    * Does this needs documentation? no
    
    Closes #5155 from prabhjyotsingh/ZEPPELIN-6162.
    
    Signed-off-by: ChanHo Lee <[email protected]>
    (cherry picked from commit c3ccd9b4dd40eac2fc7500ae15b71cbee9384cd5)
    Signed-off-by: ChanHo Lee <[email protected]>
---
 .../interfaces/message-data-type-map.interface.ts  |   2 +
 .../src/interfaces/message-notebook.interface.ts   |   7 +
 .../workspace/notebook/notebook.component.html     |   6 +-
 .../pages/workspace/notebook/notebook.module.ts    |   6 +-
 .../revisions-comparator.component.html            | 111 +++++++++++-
 .../revisions-comparator.component.less            | 146 +++++++++++++++
 .../revisions-comparator.component.ts              | 198 ++++++++++++++++++++-
 .../src/styles/theme/dark-theme-overrides.css      |  15 ++
 8 files changed, 479 insertions(+), 12 deletions(-)

diff --git 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts
 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts
index 2578655269..6c6088c73a 100644
--- 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts
+++ 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts
@@ -34,6 +34,7 @@ import {
   NoteRename,
   NoteRevision,
   NoteRevisionForCompare,
+  NoteRevisionForCompareReceived,
   NoteRunningStatus,
   NoteUpdate,
   NoteUpdated,
@@ -118,6 +119,7 @@ export interface MessageReceiveDataTypeMap {
   [OP.ANGULAR_OBJECT_UPDATE]: AngularObjectUpdate;
   [OP.ANGULAR_OBJECT_REMOVE]: AngularObjectRemove;
   [OP.PARAS_INFO]: ParasInfo;
+  [OP.NOTE_REVISION_FOR_COMPARE]: NoteRevisionForCompareReceived;
 }
 
 export interface MessageSendDataTypeMap {
diff --git 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
index a07d52d372..986aed0b91 100644
--- 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
+++ 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts
@@ -125,6 +125,13 @@ export interface NoteRevisionForCompare {
   position: string;
 }
 
+export interface NoteRevisionForCompareReceived {
+  noteId: string;
+  revisionId: string;
+  position: string;
+  note: Note['note'];
+}
+
 export interface CollaborativeModeStatus {
   status: boolean;
   users: string[];
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html
index ed0bddd2f2..8541afc964 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html
@@ -56,7 +56,11 @@
           [(activatedExtension)]="activatedExtension"
           [permissions]="permissions"
         ></zeppelin-notebook-permissions>
-        <zeppelin-notebook-revisions-comparator 
*ngSwitchCase="'revisions'"></zeppelin-notebook-revisions-comparator>
+        <zeppelin-notebook-revisions-comparator
+          *ngSwitchCase="'revisions'"
+          [noteRevisions]="noteRevisions"
+          [noteId]="note.id"
+        ></zeppelin-notebook-revisions-comparator>
       </div>
       <div class="paragraph-area">
         <zeppelin-note-form-block
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
index 78581aef7e..62899c39b5 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
@@ -33,6 +33,8 @@ import { NzRadioModule } from 'ng-zorro-antd/radio';
 import { NzResizableModule } from 'ng-zorro-antd/resizable';
 import { NzSelectModule } from 'ng-zorro-antd/select';
 import { NzSwitchModule } from 'ng-zorro-antd/switch';
+import { NzTableModule } from 'ng-zorro-antd/table';
+import { NzTagModule } from 'ng-zorro-antd/tag';
 import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
 
 import { ShareModule } from '@zeppelin/share';
@@ -98,7 +100,9 @@ import { NotebookSidebarComponent } from 
'./sidebar/sidebar.component';
     DragDropModule,
     NzCodeEditorModule,
     NzCheckboxModule,
-    NzResizableModule
+    NzResizableModule,
+    NzTableModule,
+    NzTagModule
   ]
 })
 export class NotebookModule {}
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html
 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html
index c8099d6f33..17dda5a0ff 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html
@@ -10,10 +10,111 @@
   ~ limitations under the License.
   -->
 
-<div class="revisions-comarator">
-  <div>
-    <h2>Revisions comparator</h2>
+<div class="revisions-comparator" nz-row [nzGutter]="16">
+  <div nz-col [nzSpan]="8">
+    <div class="commit-tree">
+      <nz-table
+        #revisionTable
+        [nzData]="sortedRevisions"
+        [nzShowPagination]="false"
+        [nzScroll]="{ y: '25vh' }"
+        nzSize="small"
+      >
+        <thead>
+          <tr>
+            <th>Revision name</th>
+            <th>Date</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr
+            *ngFor="let revision of revisionTable.data; let i = index; let 
last = last"
+            [class.cursor-hand]="!last"
+            [class.selected-revision]="revision.message === 
currentSecondRevisionLabel"
+            (click)="!last && onRevisionRowClick(i)"
+          >
+            <td>{{ revision.message }}</td>
+            <td>{{ formatRevisionDate(revision.time) }}</td>
+          </tr>
+        </tbody>
+      </nz-table>
+    </div>
+
+    <div class="revisions-comparator-bar">
+      <nz-select
+        *ngIf="noteRevisions.length > 0"
+        class="revision-select"
+        [ngModel]="selectedFirstRevisionId"
+        nzPlaceHolder="Choose..."
+        (ngModelChange)="onFirstRevisionSelect($event)"
+      >
+        <nz-option
+          *ngFor="let revision of sortedRevisions"
+          [nzValue]="revision.id"
+          [nzLabel]="revision.message + (revision.time ? ' - ' + 
formatRevisionDate(revision.time) : '')"
+        ></nz-option>
+      </nz-select>
+      <span class="compare-label">compare with</span>
+      <nz-select
+        *ngIf="noteRevisions.length > 0"
+        class="revision-select"
+        [ngModel]="selectedSecondRevisionId"
+        [nzDisabled]="firstNoteRevisionForCompare === null"
+        nzPlaceHolder="Choose..."
+        (ngModelChange)="onSecondRevisionSelect($event)"
+      >
+        <nz-option
+          *ngFor="let revision of sortedRevisions"
+          [nzValue]="revision.id"
+          [nzLabel]="revision.message + (revision.time ? ' - ' + 
formatRevisionDate(revision.time) : '')"
+        ></nz-option>
+      </nz-select>
+    </div>
+
+    <div class="diff-panel">
+      <div class="paragraphs-div">
+        <div
+          *ngFor="let p of mergeNoteRevisionsDiff"
+          class="paragraph-item"
+          
[class.paragraph-item-selected]="currentParagraphDiffDisplay?.paragraph?.id === 
p.paragraph.id"
+          (click)="changeCurrentParagraphDiffDisplay(p.paragraph.id)"
+        >
+          <div class="paragraph-item-heading">
+            <span class="paragraph-id">{{ p.paragraph.id }}</span>
+            <strong *ngIf="p.paragraph.title" class="paragraph-title">({{ 
p.paragraph.title }})</strong>
+            <nz-tag *ngIf="p.type === 'added'" nzColor="green">added</nz-tag>
+            <nz-tag *ngIf="p.type === 'deleted'" nzColor="red">deleted</nz-tag>
+            <nz-tag *ngIf="p.type === 'compared' && !p.identical" 
nzColor="orange">differences</nz-tag>
+            <nz-tag *ngIf="p.type === 'compared' && p.identical" 
nzColor="default">identical</nz-tag>
+            <span class="paragraph-first-string">{{ p.firstString }}</span>
+          </div>
+        </div>
+        <div *ngIf="currentSecondRevisionLabel === 'Choose...'" 
class="empty-paragraph-message">
+          Please select a revision
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <div nz-col [nzSpan]="16" class="code-panel-col">
+    <span class="code-panel-title">
+      Revision:
+      <strong>{{ currentFirstRevisionLabel }} --> {{ 
currentSecondRevisionLabel }}</strong>
+    </span>
+    <pre *ngIf="currentParagraphDiffDisplay?.type === 'added'" 
class="code-panel color-green-row">{{
+      currentParagraphDiffDisplay?.paragraph?.text
+    }}</pre>
+    <pre *ngIf="currentParagraphDiffDisplay?.type === 'deleted'" 
class="code-panel color-red-row">{{
+      currentParagraphDiffDisplay?.paragraph?.text
+    }}</pre>
+    <pre *ngIf="currentParagraphDiffDisplay?.type === 'compared'" 
class="code-panel"><span
+        *ngFor="let seg of currentParagraphDiffDisplay?.segments"
+        [class.color-green-row]="seg.type === 'insert'"
+        [class.color-red-row]="seg.type === 'delete'"
+        [class.color-black]="seg.type === 'equal'"
+      >{{ seg.text }}</span></pre>
+    <pre *ngIf="currentParagraphDiffDisplay === null" class="code-panel 
empty-code-panel">
+      <div>Nothing to display</div>
+    </pre>
   </div>
-  <nz-divider></nz-divider>
-  <div></div>
 </div>
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less
 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less
index 019b5ca53b..8eae3f0cc4 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less
@@ -9,4 +9,150 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+@import "theme-mixin";
 
+.themeMixin({
+  .revisions-comparator {
+    padding: 10px 15px 15px;
+  }
+
+  .commit-tree {
+    margin-bottom: 10px;
+
+    ::ng-deep .ant-table-body {
+      overflow-y: auto !important;
+    }
+  }
+
+  .cursor-hand {
+    cursor: pointer;
+  }
+
+  .selected-revision {
+    background-color: fade(@primary-6, 15%) !important;
+  }
+
+  .revisions-comparator-bar {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    padding-bottom: 12px;
+    flex-wrap: wrap;
+
+    .revision-select {
+      flex: 1;
+      min-width: 100px;
+      display: block;
+    }
+
+    .compare-label {
+      white-space: nowrap;
+    }
+  }
+
+  .diff-panel {
+    border: 1px solid @border-color-base;
+    border-radius: 4px;
+  }
+
+  .paragraphs-div {
+    overflow: auto;
+    max-height: 35vh;
+  }
+
+  .paragraph-item {
+    transition: background-color 200ms ease-out;
+    border-bottom: 1px solid @border-color-split;
+    cursor: pointer;
+
+    &:hover {
+      background-color: fade(@primary-6, 8%);
+    }
+
+    &.paragraph-item-selected {
+      background-color: fade(@primary-6, 15%);
+    }
+  }
+
+  .paragraph-item-heading {
+    padding: 8px 12px;
+  }
+
+  .paragraph-id {
+    font-family: monospace;
+    font-size: 12px;
+    color: @text-color-secondary;
+  }
+
+  .paragraph-title {
+    padding: 0 5px;
+  }
+
+  .paragraph-first-string {
+    display: block;
+    height: 1.8em;
+    overflow: hidden;
+    padding-top: 4px;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    font-size: 12px;
+    color: @text-color-secondary;
+  }
+
+  .empty-paragraph-message {
+    font-size: 1.5em;
+    color: @text-color-secondary;
+    text-align: center;
+    padding: 40px 0;
+  }
+
+  .code-panel-col {
+    display: flex;
+    flex-direction: column;
+  }
+
+  .code-panel-title {
+    font-size: 14px;
+    padding: 5px 0 8px;
+  }
+
+  .code-panel {
+    flex: 1;
+    width: 100%;
+    min-height: 50vh;
+    max-height: 70vh;
+    overflow-y: auto;
+    border: 1px solid @border-color-base;
+    border-radius: 4px;
+    padding: 8px;
+    margin: 0;
+    font-size: 13px;
+  }
+
+  .empty-code-panel {
+    text-align: center;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 24px;
+    color: @text-color-secondary;
+  }
+
+  ::ng-deep {
+    .color-green-row {
+      background-color: fade(@green-6, 15%);
+      display: block;
+      color: @green-6;
+    }
+
+    .color-red-row {
+      background-color: fade(@red-6, 15%);
+      display: block;
+      color: @red-6;
+    }
+
+    .color-black {
+      color: inherit;
+    }
+  }
+});
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts
 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts
index 1876b3cbbd..3b45e77d44 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts
@@ -10,16 +10,204 @@
  * limitations under the License.
  */
 
-import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
+import { DatePipe } from '@angular/common';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, 
OnDestroy, OnInit } from '@angular/core';
+import * as DiffMatchPatch from 'diff-match-patch';
+import { Subscription } from 'rxjs';
+
+import { NoteRevisionForCompareReceived, OP, ParagraphItem, RevisionListItem } 
from '@zeppelin/sdk';
+import { MessageService } from '@zeppelin/services';
+
+interface DiffSegment {
+  type: 'insert' | 'delete' | 'equal';
+  text: string;
+}
+
+interface MergedParagraphDiff {
+  paragraph: ParagraphItem;
+  firstString: string;
+  type: 'added' | 'deleted' | 'compared';
+  segments?: DiffSegment[];
+  identical?: boolean;
+}
 
 @Component({
   selector: 'zeppelin-notebook-revisions-comparator',
   templateUrl: './revisions-comparator.component.html',
   styleUrls: ['./revisions-comparator.component.less'],
-  changeDetection: ChangeDetectionStrategy.OnPush
+  changeDetection: ChangeDetectionStrategy.OnPush,
+  providers: [DatePipe]
 })
-export class NotebookRevisionsComparatorComponent implements OnInit {
-  constructor() {}
+export class NotebookRevisionsComparatorComponent implements OnInit, OnDestroy 
{
+  @Input() noteRevisions: RevisionListItem[] = [];
+  @Input() noteId!: string;
+
+  firstNoteRevisionForCompare: NoteRevisionForCompareReceived | null = null;
+  secondNoteRevisionForCompare: NoteRevisionForCompareReceived | null = null;
+  currentFirstRevisionLabel = 'Choose...';
+  currentSecondRevisionLabel = 'Choose...';
+  mergeNoteRevisionsDiff: MergedParagraphDiff[] = [];
+  currentParagraphDiffDisplay: MergedParagraphDiff | null = null;
+  selectedFirstRevisionId: string | null = null;
+  selectedSecondRevisionId: string | null = null;
+  private subscription: Subscription | null = null;
+  private dmp = new DiffMatchPatch();
+
+  get sortedRevisions(): RevisionListItem[] {
+    return [...this.noteRevisions].sort((a, b) => (b.time || 0) - (a.time || 
0));
+  }
+
+  constructor(
+    private messageService: MessageService,
+    private cdr: ChangeDetectorRef,
+    private datePipe: DatePipe
+  ) {}
+
+  ngOnInit(): void {
+    this.subscription = this.messageService
+      .receive(OP.NOTE_REVISION_FOR_COMPARE)
+      .subscribe((data: NoteRevisionForCompareReceived) => {
+        if (data.note && data.position) {
+          if (data.position === 'first') {
+            this.firstNoteRevisionForCompare = data;
+          } else {
+            this.secondNoteRevisionForCompare = data;
+          }
+
+          if (
+            this.firstNoteRevisionForCompare !== null &&
+            this.secondNoteRevisionForCompare !== null &&
+            this.firstNoteRevisionForCompare.revisionId !== 
this.secondNoteRevisionForCompare.revisionId
+          ) {
+            this.compareRevisions();
+          }
+          this.cdr.markForCheck();
+        }
+      });
+  }
+
+  getNoteRevisionForReview(revision: RevisionListItem, position: 'first' | 
'second'): void {
+    if (!revision) {
+      return;
+    }
+    if (position === 'first') {
+      this.currentFirstRevisionLabel = revision.message;
+      this.selectedFirstRevisionId = revision.id;
+    } else {
+      this.currentSecondRevisionLabel = revision.message;
+      this.selectedSecondRevisionId = revision.id;
+    }
+    this.messageService.noteRevisionForCompare(this.noteId, revision.id, 
position);
+  }
+
+  onFirstRevisionSelect(revisionId: string): void {
+    const revision = this.noteRevisions.find(r => r.id === revisionId);
+    if (revision) {
+      this.getNoteRevisionForReview(revision, 'first');
+    }
+  }
+
+  onSecondRevisionSelect(revisionId: string): void {
+    const revision = this.noteRevisions.find(r => r.id === revisionId);
+    if (revision) {
+      this.getNoteRevisionForReview(revision, 'second');
+    }
+  }
+
+  onRevisionRowClick(index: number): void {
+    const sorted = this.sortedRevisions;
+    if (index < sorted.length - 1) {
+      this.getNoteRevisionForReview(sorted[index + 1], 'first');
+      this.getNoteRevisionForReview(sorted[index], 'second');
+    }
+  }
+
+  compareRevisions(): void {
+    if (!this.firstNoteRevisionForCompare || 
!this.secondNoteRevisionForCompare) {
+      return;
+    }
+    const baseParagraphs = this.secondNoteRevisionForCompare.note?.paragraphs 
|| [];
+    const compareParagraphs = 
this.firstNoteRevisionForCompare.note?.paragraphs || [];
+    const paragraphDiffs: MergedParagraphDiff[] = [];
+
+    for (const p1 of baseParagraphs) {
+      const p2 = compareParagraphs.find((p: ParagraphItem) => p.id === p1.id) 
|| null;
+      if (p2 === null) {
+        paragraphDiffs.push({
+          paragraph: p1,
+          firstString: (p1.text || '').split('\n')[0],
+          type: 'added'
+        });
+      } else {
+        const text1 = p1.text || '';
+        const text2 = p2.text || '';
+        const diffResult = this.buildLineDiff(text1, text2);
+        paragraphDiffs.push({
+          paragraph: p1,
+          segments: diffResult.segments,
+          identical: diffResult.identical,
+          firstString: (p1.text || '').split('\n')[0],
+          type: 'compared'
+        });
+      }
+    }
+
+    for (const p2 of compareParagraphs) {
+      const p1 = baseParagraphs.find((p: ParagraphItem) => p.id === p2.id) || 
null;
+      if (p1 === null) {
+        paragraphDiffs.push({
+          paragraph: p2,
+          firstString: (p2.text || '').split('\n')[0],
+          type: 'deleted'
+        });
+      }
+    }
+
+    this.mergeNoteRevisionsDiff = paragraphDiffs;
+
+    if (this.currentParagraphDiffDisplay !== null) {
+      
this.changeCurrentParagraphDiffDisplay(this.currentParagraphDiffDisplay.paragraph.id);
+    }
+  }
+
+  changeCurrentParagraphDiffDisplay(paragraphId: string): void {
+    const found = this.mergeNoteRevisionsDiff.find(p => p.paragraph.id === 
paragraphId);
+    this.currentParagraphDiffDisplay = found || null;
+  }
+
+  formatRevisionDate(time: number | undefined): string {
+    if (!time) {
+      return '';
+    }
+    return this.datePipe.transform(time * 1000, 'MMMM d yyyy, h:mm:ss a') || 
'';
+  }
+
+  private buildLineDiff(text1: string, text2: string): { segments: 
DiffSegment[]; identical: boolean } {
+    const { chars1, chars2, lineArray } = this.dmp.diff_linesToChars_(text1, 
text2);
+    const diffs = this.dmp.diff_main(chars1, chars2, false);
+    this.dmp.diff_charsToLines_(diffs, lineArray);
+
+    let identical = true;
+    const segments: DiffSegment[] = [];
+
+    for (const [op, text] of diffs) {
+      if (op === DiffMatchPatch.DIFF_INSERT) {
+        segments.push({ type: 'insert', text });
+        identical = false;
+      } else if (op === DiffMatchPatch.DIFF_DELETE) {
+        segments.push({ type: 'delete', text });
+        identical = false;
+      } else {
+        segments.push({ type: 'equal', text });
+      }
+    }
+
+    return { segments, identical };
+  }
 
-  ngOnInit() {}
+  ngOnDestroy(): void {
+    if (this.subscription) {
+      this.subscription.unsubscribe();
+    }
+  }
 }
diff --git a/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css 
b/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css
index 6b762b2315..df1106ec29 100644
--- a/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css
+++ b/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css
@@ -166,6 +166,21 @@ html.dark .ant-menu-submenu-title:hover {
   color: rgba(255, 255, 255, 0.95) !important;
 }
 
+html.dark .ant-select-selector {
+  background-color: #262626 !important;
+  border-color: #434343 !important;
+  color: rgba(255, 255, 255, 0.85) !important;
+}
+
+html.dark .ant-select-selector:hover,
+html.dark .ant-select-selector:focus {
+  border-color: #177ddc !important;
+}
+
+html.dark .ant-select-item-option-active:not(html.dark 
.ant-select-item-option-disabled) {
+  background-color: #262626 !important;
+}
+
 html.dark .ant-dropdown-menu-item-selected,
 html.dark .ant-dropdown-menu-submenu-title-selected,
 html.dark .ant-dropdown-menu-item-selected > a,

Reply via email to