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

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/main by this push:
     new f24dab0030 chore(frontend): remove the unused 
UserWorkflowListItemComponent (#8463)
f24dab0030 is described below

commit f24dab0030bf4ee0620562ff0d186b3b04de7d51
Author: Xinyuan Lin <[email protected]>
AuthorDate: Thu Sep 24 04:00:11 2026 +0000

    chore(frontend): remove the unused UserWorkflowListItemComponent (#8463)
    
    ### What changes were proposed in this PR?
    
    Deletes `UserWorkflowListItemComponent`, which is declared in
    `AppModule` but whose selector `texera-user-workflow-list-item` appears
    in no template — so it is never rendered. `HighlightSearchTermsPipe`
    goes with it, because the component's own template is the pipe's last
    remaining consumer. So does the CSS that only that template ever
    matched. Pure deletion, no behaviour change: **−1,201 lines**.
    
    ### History
    
    | | |
    | --- | --- |
    | **Introduced by** | #1937 (2023-05-30) — "Refactored each workflow
    list item into its own component" |
    | **Usage removed by** | #2793 (2024-08-20) — "Generalize List Item"
    replaced it with the generic `ListItemComponent`, deleting the last two
    `texera-user-workflow-list-item` uses from
    `search-results.component.html` |
    
    Dead for about two years.
    
    > Reviewer note — why the pipe is in the same PR.
    `HighlightSearchTermsPipe` arrived in #2386 and kept a second consumer
    until #7463 (2026-08-29, "remove the deprecated project feature")
    dropped `entry.name | highlightSearchTerms` from that template. Since
    then its only use is this dead component's template (L43/L106). Removing
    the component alone would leave the pipe dead in the same commit, so
    they ship together; splitting them would just create a second PR for
    code this one already orphans.
    
    > Reviewer note — the CSS. The component's stylesheet `@use`d
    `section-style.scss`, and its template was the only one producing
    `.workflow-list-item` (plus every class nested under it) and
    `.metadata-container`. Those rules go, along with a second
    `.metadata-container` copy in `search-results.component.scss` that no
    template ever matched. The pipe was the only producer of the global
    `.highlight-search-terms` rule in `styles.scss`, so that goes too. The
    `itemSize` comment in `search-results.component.html` cited
    `.workflow-list-item`, and now cites `.list-item-card`, the rule that
    sizes each row today.
    
    > Nothing else needs cleaning: `WorkflowExecutionHistoryComponent`,
    `ShareAccessComponent`, `DownloadService`, `GuiConfigService` and
    `WorkflowPersistService` all keep other consumers.
    
    ### Any related issues, documentation, discussions?
    
    Closes #8460
    
    ### How was this PR tested?
    
    Existing tests only — this PR removes a component, a pipe, their two
    specs, and CSS that no remaining template matches.
    
    From `frontend/`:
    
    - `npx ng build` — **success**. This is the gate that matters here:
    removing an `AppModule` declaration can only be proven safe by an AOT
    build, since template diagnostics are AOT-only. A leftover use of either
    selector, or an `@extend` of a removed CSS rule, would fail it.
    - `npx ng test --watch=false
    --include='**/search-results.component.spec.ts'
    --include='**/user-workflow.component.spec.ts'` — 107 tests pass (2
    files).
    - `yarn --cwd frontend format:ci` — clean.
    
    Verification, re-runnable by a reviewer (all three return nothing):
    
    ```
    git grep -n "texera-user-workflow-list-item\|UserWorkflowListItemComponent"
    git grep -n "highlightSearchTerms\|HighlightSearchTermsPipe"
    git grep -n "workflow-list-item\|metadata-container\|highlight-search-terms"
    ```
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Claude Opus 5)
---
 frontend/src/app/app.module.ts                     |   4 -
 .../src/app/dashboard/component/section-style.scss |  84 ----
 .../search-results/search-results.component.html   |   4 +-
 .../search-results/search-results.component.scss   |   6 -
 .../highlight-search-terms.pipe.spec.ts            |  67 ---
 .../highlight-search-terms.pipe.ts                 |  40 --
 .../user-workflow-list-item.component.html         | 210 --------
 .../user-workflow-list-item.component.scss         |  21 -
 .../user-workflow-list-item.component.spec.ts      | 559 ---------------------
 .../user-workflow-list-item.component.ts           | 201 --------
 .../user-workflow/user-workflow.component.spec.ts  |   2 -
 frontend/src/styles.scss                           |   5 -
 12 files changed, 2 insertions(+), 1201 deletions(-)

diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts
index 6c96ab6ade..ca45b08289 100644
--- a/frontend/src/app/app.module.ts
+++ b/frontend/src/app/app.module.ts
@@ -120,7 +120,6 @@ import { MarkdownModule } from "ngx-markdown";
 import { FileSaverService } from 
"./dashboard/service/user/file/file-saver.service";
 import { DragDropModule } from "@angular/cdk/drag-drop";
 import { ScrollingModule } from "@angular/cdk/scrolling";
-import { UserWorkflowListItemComponent } from 
"./dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component";
 import { SortButtonComponent } from 
"./dashboard/component/user/sort-button/sort-button.component";
 import { FiltersComponent } from 
"./dashboard/component/user/filters/filters.component";
 import { FiltersInstructionsComponent } from 
"./dashboard/component/user/filters-instructions/filters-instructions.component";
@@ -139,7 +138,6 @@ import { TimeTravelComponent } from 
"./workspace/component/left-panel/time-trave
 import { NzModalModule } from "ng-zorro-antd/modal";
 import { NzDescriptionsModule } from "ng-zorro-antd/descriptions";
 import { OverlayModule } from "@angular/cdk/overlay";
-import { HighlightSearchTermsPipe } from 
"./dashboard/component/user/user-workflow/user-workflow-list-item/highlight-search-terms.pipe";
 import { en_US, provideNzI18n } from "ng-zorro-antd/i18n";
 import { FilesUploaderComponent } from 
"./dashboard/component/user/files-uploader/files-uploader.component";
 import { ConflictingFileModalContentComponent } from 
"./dashboard/component/user/files-uploader/conflicting-file-modal-content/conflicting-file-modal-content.component";
@@ -331,7 +329,6 @@ registerLocaleData(en);
     CollabWrapperComponent,
     AboutComponent,
     TexeraLoginComponent,
-    UserWorkflowListItemComponent,
     SortButtonComponent,
     FiltersComponent,
     FiltersInstructionsComponent,
@@ -339,7 +336,6 @@ registerLocaleData(en);
     PortPropertyEditFrameComponent,
     WorkflowRuntimeStatisticsComponent,
     FlarumComponent,
-    HighlightSearchTermsPipe,
     SearchBarComponent,
     ListItemComponent,
     CardItemComponent,
diff --git a/frontend/src/app/dashboard/component/section-style.scss 
b/frontend/src/app/dashboard/component/section-style.scss
index 784815fb4a..446187f502 100644
--- a/frontend/src/app/dashboard/component/section-style.scss
+++ b/frontend/src/app/dashboard/component/section-style.scss
@@ -94,7 +94,6 @@ $dashboard-navigation-height: 76px;
 
 /**
   * the third grid of the workflow/files list.
-  * including css shared by workflow/file item
   **/
 .section-list-container {
   grid-row-start: 3;
@@ -119,83 +118,6 @@ $dashboard-navigation-height: 76px;
     border: 1px solid #e8e8e8;
     border-radius: 4px;
   }
-
-  .metadata-container {
-    span {
-      margin: 0 1rem 0 0;
-    }
-  }
-}
-
-/**
-  * css specifically for each workflow item in the list (not shared by file 
items)
-  **/
-.workflow-list-item {
-  margin-bottom: 10px;
-  min-height: 70px;
-  padding: 5px 0 5px 0;
-
-  .workflow-item-checkbox {
-    margin: 8px;
-  }
-
-  .workflow-item-meta-title {
-    display: flex;
-    align-items: center;
-
-    .workflow-name {
-      font-size: 20px;
-      font-family: -apple-system, BlinkMacSystemFont, sans-serif;
-      text-align: center;
-      margin-bottom: 0;
-      color: inherit;
-      text-decoration: none;
-    }
-
-    .workflow-name:hover {
-      cursor: pointer;
-    }
-
-    i {
-      position: relative;
-      font-size: 17px;
-    }
-
-    i.workflow-is-owner-icon {
-      margin-left: 7px;
-    }
-  }
-
-  .workflow-item-meta-description {
-    display: flex;
-    align-items: center;
-    padding: 2px 8px 2px 10px;
-    margin-bottom: 5px;
-
-    .workflow-description {
-      font-size: 13px;
-      font-family: -apple-system, BlinkMacSystemFont, sans-serif;
-
-      display: inline-block;
-      min-width: 17ch;
-      border: 0 none;
-      outline: none;
-
-      &:hover {
-        cursor: pointer;
-        box-shadow: 0 0 0 1px rgb(202, 202, 202);
-      }
-    }
-
-    .workflow-editable-description {
-      margin-bottom: 5px;
-      display: inline-block;
-      min-width: 17ch;
-      border: 0 none;
-      outline: none;
-      box-shadow: 0 0 0 2px #007bff;
-    }
-  }
 }
 
 // Shared look of one resource row (the computing-unit and warehouse list
@@ -241,9 +163,3 @@ $dashboard-navigation-height: 76px;
   margin-left: 5px;
   margin-right: 5px;
 }
-
-.metadata-container {
-  span {
-    margin: 0 1rem 0 0; // add space to the right
-  }
-}
diff --git 
a/frontend/src/app/dashboard/component/user/search-results/search-results.component.html
 
b/frontend/src/app/dashboard/component/user/search-results/search-results.component.html
index 084ccb0d9f..13ff93847e 100644
--- 
a/frontend/src/app/dashboard/component/user/search-results/search-results.component.html
+++ 
b/frontend/src/app/dashboard/component/user/search-results/search-results.component.html
@@ -23,8 +23,8 @@
   <!-- LIST VIEW -->
   <ng-container *ngIf="viewMode === 'list'">
     <!-- itemSize: the height (px) of each list item,
-        this MUST be approximately the same as list item size set in CSS,
-        .workflow-list-item sets the item size to be 70px, with additional 
paddings/margins it's approximately 80px
+        this MUST be approximately the same as the list item height set in CSS
+        (.list-item-card in list-item.component.scss)
       -->
     <cdk-virtual-scroll-viewport
       itemSize="70"
diff --git 
a/frontend/src/app/dashboard/component/user/search-results/search-results.component.scss
 
b/frontend/src/app/dashboard/component/user/search-results/search-results.component.scss
index 32f4de9513..a2c66114a9 100644
--- 
a/frontend/src/app/dashboard/component/user/search-results/search-results.component.scss
+++ 
b/frontend/src/app/dashboard/component/user/search-results/search-results.component.scss
@@ -125,12 +125,6 @@ nz-content {
   margin-right: 5px;
 }
 
-.metadata-container {
-  span {
-    margin: 0 1rem 0 0; // add space to the right
-  }
-}
-
 .card-scroll-container {
   height: 100%;
   overflow-y: auto;
diff --git 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/highlight-search-terms.pipe.spec.ts
 
b/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/highlight-search-terms.pipe.spec.ts
deleted file mode 100644
index 653cab0b54..0000000000
--- 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/highlight-search-terms.pipe.spec.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { TestBed } from "@angular/core/testing";
-import { SafeHtml } from "@angular/platform-browser";
-
-import { HighlightSearchTermsPipe } from "./highlight-search-terms.pipe";
-
-describe("HighlightSearchTermsPipe", () => {
-  let pipe: HighlightSearchTermsPipe;
-
-  // Recover the raw HTML string that was wrapped by bypassSecurityTrustHtml.
-  const raw = (safe: SafeHtml): string => (safe as 
any).changingThisBreaksApplicationSecurity;
-
-  beforeEach(() => {
-    TestBed.configureTestingModule({ providers: [HighlightSearchTermsPipe] });
-    pipe = TestBed.inject(HighlightSearchTermsPipe);
-  });
-
-  it("returns an empty string when the value is undefined", () => {
-    expect(raw(pipe.transform(undefined, ["x"]))).toBe("");
-  });
-
-  it("returns the value unchanged when there are no terms to highlight", () => 
{
-    expect(raw(pipe.transform("hello", []))).toBe("hello");
-  });
-
-  it("wraps a single matching token in a highlight span", () => {
-    expect(raw(pipe.transform("hello world", ["world"]))).toBe(
-      'hello <span class="highlight-search-terms">world</span>'
-    );
-  });
-
-  it("matches case-insensitively and preserves the original casing inside the 
span", () => {
-    expect(raw(pipe.transform("Hello", ["hello"]))).toBe('<span 
class="highlight-search-terms">Hello</span>');
-  });
-
-  it("wraps every occurrence of a token (global flag)", () => {
-    expect(raw(pipe.transform("a a a", ["a"]))).toBe(
-      '<span class="highlight-search-terms">a</span> ' +
-        '<span class="highlight-search-terms">a</span> ' +
-        '<span class="highlight-search-terms">a</span>'
-    );
-  });
-
-  it("wraps each token independently when multiple terms are given", () => {
-    expect(raw(pipe.transform("hello world", ["hello", "world"]))).toBe(
-      '<span class="highlight-search-terms">hello</span> ' + '<span 
class="highlight-search-terms">world</span>'
-    );
-  });
-});
diff --git 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/highlight-search-terms.pipe.ts
 
b/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/highlight-search-terms.pipe.ts
deleted file mode 100644
index 44953b1f8a..0000000000
--- 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/highlight-search-terms.pipe.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { Pipe, PipeTransform } from "@angular/core";
-import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
-
-@Pipe({ name: "highlightSearchTerms" })
-export class HighlightSearchTermsPipe implements PipeTransform {
-  constructor(private sanitizer: DomSanitizer) {}
-
-  transform(value: string | undefined, terms: string[]): SafeHtml {
-    if (!terms || !terms.length || !value) {
-      // Return the original value if there's nothing to highlight or if the 
value is undefined
-      return this.sanitizer.bypassSecurityTrustHtml(value || "");
-    }
-
-    // Escape the terms to be used in a RegExp
-    const regex = new RegExp(`(${terms.join("|")})`, "gi");
-
-    const highlightedString = value.replace(regex, '<span 
class="highlight-search-terms">$1</span>');
-    // Use the sanitizer to avoid security risks
-    return this.sanitizer.bypassSecurityTrustHtml(highlightedString);
-  }
-}
diff --git 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.html
 
b/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.html
deleted file mode 100644
index 273cb55d3a..0000000000
--- 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.html
+++ /dev/null
@@ -1,210 +0,0 @@
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements.  See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership.  The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied.  See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-
-<nz-list-item class="workflow-list-item">
-  <nz-list-item-meta>
-    <!-- Margin need only when the checkbox is not visible -->
-    <nz-list-item-meta-avatar [ngStyle]="{ 'margin-left': editable ? 'none' : 
'16px' }">
-      <label
-        *ngIf="editable"
-        class="workflow-item-checkbox"
-        id="{{workflow.wid}}"
-        ngDefaultControl
-        [(ngModel)]="entry.checked"></label>
-      <nz-avatar
-        [ngStyle]="{ 'background-color': 'grey', 'vertical-align': 'middle' }"
-        [nzGap]="4"
-        [nzText]="'' + workflow.wid"
-        nzSize="default"></nz-avatar>
-    </nz-list-item-meta-avatar>
-
-    <!-- editable name of saved workflow -->
-    <nz-list-item-meta-title class="meta-title-container">
-      <div class="workflow-item-meta-title">
-        <div
-          *ngIf="!editingName; else customWorkflowTitle "
-          [routerLink]="USER_WORKSPACE + '/' + workflow.wid"
-          [innerHTML]="workflow.name | highlightSearchTerms : keywords"
-          class="workflow-name"></div>
-        <ng-template #customWorkflowTitle>
-          <input
-            #customName
-            (focusout)="confirmUpdateWorkflowCustomName(customName.value)"
-            (keyup.enter)="confirmUpdateWorkflowCustomName(customName.value)"
-            placeholder="{{ workflow.name }}"
-            value="{{ workflow.name }}" />
-        </ng-template>
-        <button
-          *ngIf="editable"
-          (click)="editingName = true"
-          nz-button
-          nz-tooltip="Customize Workflow Name"
-          nzSize="small"
-          nzTooltipPlacement="bottom"
-          nzType="text">
-          <i
-            nz-icon
-            nzTheme="outline"
-            nzType="edit"></i>
-        </button>
-        <button
-          *ngIf="editable"
-          (click)="editingDescription = true"
-          nz-button
-          nz-tooltip="Add Description"
-          nzSize="small"
-          nzTooltipPlacement="bottom"
-          nzType="text"
-          class="add-description-btn">
-          <i
-            nz-icon
-            nzTheme="outline"
-            nzType="plus-square"></i>
-        </button>
-        <i
-          class="workflow-is-owner-icon"
-          *ngIf="entry.workflow.isOwner"
-          nz-tooltip="You are the owner"
-          nzTooltipPlacement="bottom"
-          nz-icon
-          nzTheme="outline"
-          nzType="user"></i>
-        <i
-          *ngIf="!entry.workflow.isOwner"
-          nz-tooltip="{{
-                          entry.workflow.accessLevel
-                      }} access shared by {{ entry.workflow.ownerName }}"
-          nzTooltipPlacement="bottom"
-          nz-icon
-          nzTheme="outline"
-          nzType="team"></i>
-      </div>
-    </nz-list-item-meta-title>
-
-    <!-- editable description of saved workflow -->
-    <nz-list-item-meta-description>
-      <div class="workflow-item-meta-description">
-        <label
-          *ngIf="!editingDescription; else customWorkflowDescription "
-          (click)="editingDescription = editable"
-          [innerHTML]="workflow.description | highlightSearchTerms : keywords"
-          class="workflow-description">
-        </label>
-        <ng-template #customWorkflowDescription>
-          <input
-            title="Description"
-            #customDescription
-            
(focusout)="confirmUpdateWorkflowCustomDescription(customDescription.value)"
-            
(keyup.enter)="confirmUpdateWorkflowCustomDescription(customDescription.value)"
-            class="workflow-editable-description"
-            value="{{ workflow.description }}"
-            maxlength="500" />
-        </ng-template>
-      </div>
-    </nz-list-item-meta-description>
-
-    <!-- last access and created date of saved workflow -->
-    <nz-list-item-meta-description class="metadata-container">
-      <span>Last Modified: {{ workflow.lastModifiedTime | date: "yyyy-MM-dd 
HH:mm" }}</span>
-      <span>Created: {{ workflow.creationTime | date: "yyyy-MM-dd HH:mm" 
}}</span>
-    </nz-list-item-meta-description>
-  </nz-list-item-meta>
-
-  <ul nz-list-item-actions>
-    <nz-list-item-action>
-      <button
-        (click)="onClickOpenShareAccess()"
-        nz-button
-        nz-tooltip="Share the workflow {{
-                      workflow.name
-                  }} to others"
-        nzTooltipPlacement="bottom"
-        type="button">
-        <i
-          nz-icon
-          nzTheme="outline"
-          nzType="share-alt"></i>
-      </button>
-    </nz-list-item-action>
-    <nz-list-item-action *ngIf="editable">
-      <button
-        (click)="duplicated.emit()"
-        class="duplicate-workflow-btn"
-        nz-button
-        nz-tooltip="Duplicate the workflow {{
-                      workflow.name
-                  }}"
-        nzTooltipPlacement="bottom"
-        type="button">
-        <i
-          nz-icon
-          nzTheme="outline"
-          nzType="copy"></i>
-      </button>
-    </nz-list-item-action>
-    <nz-list-item-action>
-      <button
-        (click)="onClickDownloadWorkfllow()"
-        nz-button
-        nz-tooltip="Download the workflow {{
-                      workflow.name
-                  }}"
-        nzTooltipPlacement="bottom"
-        type="button">
-        <i
-          nz-icon
-          nzType="cloud-download"
-          nzTheme="outline"></i>
-      </button>
-    </nz-list-item-action>
-    <nz-list-item-action *ngIf="editable">
-      <button
-        (nzOnConfirm)="deleted.emit()"
-        nz-popconfirm
-        nzPopconfirmTitle="Confirm to delete this workflow."
-        [disabled]="!entry.workflow.isOwner"
-        class="delete-workflow-btn"
-        nz-button
-        nz-tooltip="Delete the workflow {{
-                      workflow.name
-                  }}"
-        nzTooltipPlacement="bottom">
-        <i
-          nz-icon
-          nzTheme="outline"
-          nzType="delete"></i>
-      </button>
-    </nz-list-item-action>
-    <nz-list-item-action 
*ngIf="this.config.env.workflowExecutionsTrackingEnabled">
-      <button
-        (click)="onClickGetWorkflowExecutions()"
-        nz-button
-        nz-tooltip="Executions of the workflow {{
-                      workflow.name
-                  }}"
-        nzTooltipPlacement="bottom"
-        type="button">
-        <i
-          nz-icon
-          nzTheme="outline"
-          nzType="history"></i>
-      </button>
-    </nz-list-item-action>
-  </ul>
-</nz-list-item>
diff --git 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.scss
 
b/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.scss
deleted file mode 100644
index 630cd34d91..0000000000
--- 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-@use "../../../section-style" as *;
-@use "../../../dashboard.component.scss" as *;
diff --git 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.spec.ts
 
b/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.spec.ts
deleted file mode 100644
index ad3d296445..0000000000
--- 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.spec.ts
+++ /dev/null
@@ -1,559 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { Component, ViewChild } from "@angular/core";
-import { ComponentFixture, TestBed, waitForAsync } from 
"@angular/core/testing";
-import { UserWorkflowListItemComponent } from 
"./user-workflow-list-item.component";
-import { FileSaverService } from 
"../../../../service/user/file/file-saver.service";
-import { testWorkflow1, testWorkflowEntries } from 
"../../../user-dashboard-test-fixtures";
-import { By } from "@angular/platform-browser";
-import { StubWorkflowPersistService } from 
"../../../../../common/service/workflow-persist/stub-workflow-persist.service";
-import {
-  DEFAULT_WORKFLOW_NAME,
-  WorkflowPersistService,
-} from 
"../../../../../common/service/workflow-persist/workflow-persist.service";
-import { DownloadService } from 
"../../../../service/user/download/download.service";
-import { WorkflowExecutionHistoryComponent } from 
"../ngbd-modal-workflow-executions/workflow-execution-history.component";
-import { ShareAccessComponent } from 
"../../share-access/share-access.component";
-import { Workflow } from "../../../../../common/type/workflow";
-import { of } from "rxjs";
-import { NzListComponent } from "ng-zorro-antd/list";
-import { NzModalModule, NzModalService } from "ng-zorro-antd/modal";
-import { HttpClientTestingModule } from "@angular/common/http/testing";
-import { provideRouter } from "@angular/router";
-import { DashboardEntry } from "../../../../type/dashboard-entry";
-import { NzTooltipDirective, NzTooltipModule } from "ng-zorro-antd/tooltip";
-import { commonTestProviders } from "../../../../../common/testing/test-utils";
-import type { Mocked } from "vitest";
-import { GuiConfigService } from 
"../../../../../common/service/gui-config.service";
-import { MockGuiConfigService } from 
"../../../../../common/service/gui-config.service.mock";
-
-// UserWorkflowListItemComponent is rooted at <nz-list-item>; instantiating it
-// outside an <nz-list> host throws "No provider found for NzListComponent".
-@Component({
-  standalone: true,
-  imports: [NzListComponent, UserWorkflowListItemComponent],
-  template: `
-    <nz-list>
-      <texera-user-workflow-list-item
-        [entry]="entry"
-        [editable]="editable"></texera-user-workflow-list-item>
-    </nz-list>
-  `,
-})
-class TestHostComponent {
-  entry!: DashboardEntry;
-  editable = true;
-  @ViewChild(UserWorkflowListItemComponent, { static: true }) inner!: 
UserWorkflowListItemComponent;
-}
-
-// A fresh DashboardEntry per call so methods that mutate the workflow (rename)
-// cannot leak into the shared testWorkflowEntries fixture.
-function makeWorkflowEntry(workflowOverrides: Partial<Workflow> = {}): 
DashboardEntry {
-  return new DashboardEntry({
-    workflow: { ...testWorkflow1, ...workflowOverrides },
-    isOwner: true,
-    ownerName: "Texera",
-    accessLevel: "Write",
-    ownerId: 1,
-    coverImage: null,
-  });
-}
-
-describe("UserWorkflowListItemComponent", () => {
-  let component: UserWorkflowListItemComponent;
-  let fixture: ComponentFixture<TestHostComponent>;
-  const fileSaverServiceSpy = { saveAs: vi.fn() } as unknown as 
Mocked<FileSaverService>;
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      imports: [TestHostComponent, NzModalModule, HttpClientTestingModule, 
NzTooltipModule],
-      providers: [
-        { provide: WorkflowPersistService, useValue: new 
StubWorkflowPersistService(testWorkflowEntries) },
-        { provide: FileSaverService, useValue: fileSaverServiceSpy },
-        provideRouter([]),
-        ...commonTestProviders,
-      ],
-    }).compileComponents();
-  });
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(TestHostComponent);
-    fixture.componentInstance.entry = testWorkflowEntries[0];
-    fixture.componentInstance.editable = true;
-    fixture.detectChanges();
-    component = fixture.componentInstance.inner;
-  });
-
-  it("should create", () => {
-    expect(component).toBeTruthy();
-  });
-
-  it("sends http request to backend to retrieve export json", () => {
-    // Test the workflow download button.
-    component.onClickDownloadWorkfllow();
-    expect(fileSaverServiceSpy.saveAs).toHaveBeenCalledExactlyOnceWith(
-      new 
Blob([JSON.stringify(testWorkflowEntries[0].workflow.workflow.content)], {
-        type: "text/plain;charset=utf-8",
-      }),
-      "workflow 1.json"
-    );
-  });
-
-  it("adding a workflow description adds a description to the workflow", 
waitForAsync(() => {
-    fixture.whenStable().then(() => {
-      let addWorkflowDescriptionBtn = 
fixture.debugElement.query(By.css(".add-description-btn"));
-      expect(addWorkflowDescriptionBtn).toBeTruthy();
-      addWorkflowDescriptionBtn.triggerEventHandler("click", null);
-      fixture.detectChanges();
-      let editableDescriptionInput = 
fixture.debugElement.nativeElement.querySelector(".workflow-editable-description");
-      expect(editableDescriptionInput).toBeTruthy();
-      vi.spyOn(component, "confirmUpdateWorkflowCustomDescription");
-      sendInput(editableDescriptionInput, "dummy description added by focusing 
out the input element.").then(() => {
-        fixture.detectChanges();
-        editableDescriptionInput.dispatchEvent(new Event("focusout"));
-        fixture.detectChanges();
-        
expect(component.confirmUpdateWorkflowCustomDescription).toHaveBeenCalledTimes(1);
-      });
-    });
-  }));
-
-  it("Editing a workflow description edits a description to the workflow", 
waitForAsync(() => {
-    fixture.whenStable().then(() => {
-      const workflowDescriptionLabel = 
fixture.debugElement.query(By.css(".workflow-description"));
-      expect(workflowDescriptionLabel).toBeTruthy();
-      workflowDescriptionLabel.triggerEventHandler("click", null);
-      fixture.detectChanges();
-      let editableDescriptionInput1 = 
fixture.debugElement.nativeElement.querySelector(
-        ".workflow-editable-description"
-      );
-      expect(editableDescriptionInput1).toBeTruthy();
-      vi.spyOn(component, "confirmUpdateWorkflowCustomDescription");
-      sendInput(editableDescriptionInput1, "dummy description added by 
focusing out the input element.").then(() => {
-        fixture.detectChanges();
-        editableDescriptionInput1.dispatchEvent(new Event("focusout"));
-        fixture.detectChanges();
-        
expect(component.confirmUpdateWorkflowCustomDescription).toHaveBeenCalledTimes(1);
-      });
-    });
-  }));
-
-  describe("method coverage", () => {
-    afterEach(() => {
-      vi.restoreAllMocks();
-    });
-
-    describe("confirmUpdateWorkflowCustomName", () => {
-      it("persists the new name, updates the workflow, and stops editing", () 
=> {
-        const persist = TestBed.inject(WorkflowPersistService);
-        // The stub lacks updateWorkflowName; give this fresh-per-test 
instance a spy.
-        const spy = ((persist as any).updateWorkflowName = 
vi.fn().mockReturnValue(of(undefined)));
-        component.entry = makeWorkflowEntry({ wid: 5, name: "old" });
-        component.editingName = true;
-
-        component.confirmUpdateWorkflowCustomName("new name");
-
-        expect(spy).toHaveBeenCalledWith(5, "new name");
-        expect(component.workflow.name).toBe("new name");
-        expect(component.editingName).toBe(false);
-      });
-
-      it("falls back to the default name when the input is empty", () => {
-        const persist = TestBed.inject(WorkflowPersistService);
-        const spy = ((persist as any).updateWorkflowName = 
vi.fn().mockReturnValue(of(undefined)));
-        component.entry = makeWorkflowEntry({ wid: 5 });
-
-        component.confirmUpdateWorkflowCustomName("");
-
-        expect(spy).toHaveBeenCalledWith(5, DEFAULT_WORKFLOW_NAME);
-        expect(component.workflow.name).toBe(DEFAULT_WORKFLOW_NAME);
-      });
-
-      it("is a no-op when the workflow has no id", () => {
-        const persist = TestBed.inject(WorkflowPersistService);
-        const spy = ((persist as any).updateWorkflowName = vi.fn());
-        component.entry = makeWorkflowEntry({ wid: undefined });
-
-        component.confirmUpdateWorkflowCustomName("x");
-
-        expect(spy).not.toHaveBeenCalled();
-      });
-    });
-
-    describe("confirmUpdateWorkflowCustomDescription", () => {
-      it("persists the new description and stops editing", () => {
-        const persist = TestBed.inject(WorkflowPersistService);
-        const spy = ((persist as any).updateWorkflowDescription = 
vi.fn().mockReturnValue(of(undefined)));
-        component.entry = makeWorkflowEntry({ wid: 5 });
-        component.editingDescription = true;
-
-        component.confirmUpdateWorkflowCustomDescription("new desc");
-
-        expect(spy).toHaveBeenCalledWith(5, "new desc");
-        expect(component.workflow.description).toBe("new desc");
-        expect(component.editingDescription).toBe(false);
-      });
-
-      it("is a no-op when the workflow has no id", () => {
-        const persist = TestBed.inject(WorkflowPersistService);
-        const spy = ((persist as any).updateWorkflowDescription = vi.fn());
-        component.entry = makeWorkflowEntry({ wid: undefined });
-
-        component.confirmUpdateWorkflowCustomDescription("x");
-
-        expect(spy).not.toHaveBeenCalled();
-      });
-    });
-
-    it("onClickGetWorkflowExecutions opens the execution-history modal for the 
workflow", () => {
-      const modal = TestBed.inject(NzModalService);
-      const spy = vi.spyOn(modal, "create").mockReturnValue({} as any);
-      component.entry = makeWorkflowEntry({ wid: 9, name: "wf" });
-
-      component.onClickGetWorkflowExecutions();
-
-      expect(spy).toHaveBeenCalledWith(
-        expect.objectContaining({
-          nzContent: WorkflowExecutionHistoryComponent,
-          nzData: { wid: 9 },
-          nzTitle: "Execution results of Workflow: wf",
-        })
-      );
-    });
-
-    describe("onClickDownloadWorkfllow", () => {
-      it("delegates to the download service with the workflow id and name", () 
=> {
-        const download = TestBed.inject(DownloadService);
-        const spy = vi.spyOn(download, 
"downloadWorkflow").mockReturnValue(of(undefined) as any);
-        component.entry = makeWorkflowEntry({ wid: 9, name: "wf" });
-
-        component.onClickDownloadWorkfllow();
-
-        expect(spy).toHaveBeenCalledWith(9, "wf");
-      });
-
-      it("does nothing when the workflow has no id", () => {
-        const download = TestBed.inject(DownloadService);
-        const spy = vi.spyOn(download, "downloadWorkflow");
-        component.entry = makeWorkflowEntry({ wid: undefined });
-
-        component.onClickDownloadWorkfllow();
-
-        expect(spy).not.toHaveBeenCalled();
-      });
-    });
-
-    it("opens the share modal for this row's workflow, carrying its write 
access and the owner list", async () => {
-      const entry = makeWorkflowEntry({ wid: 21, name: "wf" });
-      entry.workflow.accessLevel = "WRITE";
-      component.entry = entry;
-      const persist = TestBed.inject(WorkflowPersistService);
-      // The owner list is the autocomplete the dialog exists to offer; it is 
the one awaited
-      // value in the method, so nothing else proves it is resolved before the 
modal opens.
-      vi.spyOn(persist, 
"retrieveOwners").mockReturnValue(of(["[email protected]", "[email protected]"]));
-      const modal = TestBed.inject(NzModalService);
-      const spy = vi.spyOn(modal, "create").mockReturnValue({} as any);
-
-      await component.onClickOpenShareAccess();
-
-      expect(spy).toHaveBeenCalledWith(
-        expect.objectContaining({
-          nzContent: ShareAccessComponent,
-          nzData: expect.objectContaining({
-            writeAccess: true,
-            type: "workflow",
-            id: 21,
-            allOwners: ["[email protected]", "[email protected]"],
-          }),
-        })
-      );
-    });
-
-    it("marks the share modal read-only for a row the viewer can only read", 
async () => {
-      const entry = makeWorkflowEntry({ wid: 21 });
-      entry.workflow.accessLevel = "READ";
-      component.entry = entry;
-      const modal = TestBed.inject(NzModalService);
-      const spy = vi.spyOn(modal, "create").mockReturnValue({} as any);
-
-      await component.onClickOpenShareAccess();
-
-      expect(spy).toHaveBeenCalledWith(
-        expect.objectContaining({ nzData: expect.objectContaining({ 
writeAccess: false }) })
-      );
-    });
-
-    describe("mis-wired inputs", () => {
-      // Both accessors are read from the template on every change-detection 
pass, so a silent
-      // undefined would surface as an unrelated crash deep in ng-zorro 
instead of here.
-      it("refuses to read the entry before one has been provided", () => {
-        component.entry = undefined as any;
-
-        expect(() => component.entry).toThrowError("entry property must be 
provided to UserWorkflowListItemComponent.");
-      });
-
-      it("refuses to read a workflow off an entry that carries no workflow 
payload", () => {
-        // The guard tests for the payload, not for entry.type: an entry of 
any kind that does
-        // carry a workflow passes it, so this must not claim to be a kind 
check.
-        component.entry = { name: "ds" } as unknown as DashboardEntry;
-
-        expect(() => component.workflow).toThrowError(/Entry must be 
workflow/);
-      });
-    });
-  });
-
-  function sendInput(editableDescriptionInput: HTMLInputElement, text: string) 
{
-    // Helper function to change the workflow description textbox.
-    editableDescriptionInput.value = text;
-    editableDescriptionInput.dispatchEvent(new Event("input"));
-    fixture.detectChanges();
-    return fixture.whenStable();
-  }
-});
-/**
- * The list item's template carries decisions the class does not: which 
control a click reaches, what
- * value an edit forwards, whether a read-only row may still be edited inline, 
and which actions the
- * row offers. The suite above calls the component's methods directly, so none 
of that was rendered.
- */
-describe("UserWorkflowListItemComponent rendering", () => {
-  let fixture: ComponentFixture<TestHostComponent>;
-  let component: UserWorkflowListItemComponent;
-  let persistService: { updateWorkflowName: ReturnType<typeof vi.fn> };
-
-  async function setup(opts: { executionsTracking?: boolean } = {}) {
-    // StubWorkflowPersistService does not declare updateWorkflowName, so it 
cannot be spied on.
-    persistService = { updateWorkflowName: vi.fn(() => of({} as Response)) };
-    TestBed.resetTestingModule();
-    await TestBed.configureTestingModule({
-      imports: [TestHostComponent, NzModalModule, HttpClientTestingModule, 
NzTooltipModule],
-      providers: [
-        { provide: WorkflowPersistService, useValue: persistService },
-        { provide: FileSaverService, useValue: { saveAs: vi.fn() } },
-        provideRouter([]),
-        ...commonTestProviders,
-      ],
-    }).compileComponents();
-    if (opts.executionsTracking) {
-      (TestBed.inject(GuiConfigService) as unknown as 
MockGuiConfigService).setConfig({
-        workflowExecutionsTrackingEnabled: true,
-      });
-    }
-  }
-
-  /** Renders one row. */
-  function render(entry: DashboardEntry, editable = true): HTMLElement {
-    fixture = TestBed.createComponent(TestHostComponent);
-    fixture.componentInstance.entry = entry;
-    fixture.componentInstance.editable = editable;
-    fixture.detectChanges();
-    component = fixture.componentInstance.inner;
-    return fixture.nativeElement as HTMLElement;
-  }
-
-  /**
-   * Tooltip titles on the row, read off the directive: ng-zorro consumes the 
nz-tooltip attribute,
-   * and an interpolated title is a property binding that never appears in the 
DOM at all.
-   */
-  function tooltipTitles(): unknown[] {
-    return fixture.debugElement
-      .queryAll(By.directive(NzTooltipDirective))
-      .map(d => (d.injector.get(NzTooltipDirective) as 
NzTooltipDirective).directiveTitle);
-  }
-
-  /** The elements whose tooltip title satisfies the predicate, in document 
order. */
-  function byTooltip(pred: (title: string) => boolean): HTMLElement[] {
-    return fixture.debugElement
-      .queryAll(By.directive(NzTooltipDirective))
-      .filter(d => {
-        const t = (d.injector.get(NzTooltipDirective) as 
NzTooltipDirective).directiveTitle;
-        return typeof t === "string" && pred(t);
-      })
-      .map(d => d.nativeElement as HTMLElement);
-  }
-
-  /**
-   * The one element whose tooltip title satisfies the predicate. Indexing 
byTooltip() directly
-   * reports a missing or duplicated action as a TypeError on 
`undefined.click()` — or, worse,
-   * silently clicks the first of several; asserting the match is unique names 
the real problem.
-   */
-  function onlyByTooltip(pred: (title: string) => boolean): HTMLElement {
-    const matches = byTooltip(pred);
-    expect(matches).toHaveLength(1);
-    return matches[0];
-  }
-
-  beforeEach(async () => {
-    await setup();
-  });
-
-  describe("renaming", () => {
-    it("forwards the text that was typed, not the name it started with", () => 
{
-      // The input is seeded with the current name, so binding workflow.name 
instead of the input's
-      // value would still look right on screen while silently discarding 
every rename.
-      render(makeWorkflowEntry({ wid: 7, name: "before" }));
-
-      component.editingName = true;
-      fixture.detectChanges();
-
-      const input = (fixture.nativeElement as 
HTMLElement).querySelector<HTMLInputElement>("input")!;
-      expect(input.value).toBe("before");
-      input.value = "after";
-      input.dispatchEvent(new Event("focusout"));
-
-      expect(persistService.updateWorkflowName).toHaveBeenCalledWith(7, 
"after");
-    });
-  });
-
-  describe("inline description editing", () => {
-    it("opens for a viewer who may edit", () => {
-      const el = render(makeWorkflowEntry(), true);
-
-      el.querySelector<HTMLElement>(".workflow-description")?.click();
-      fixture.detectChanges();
-
-      expect(component.editingDescription).toBe(true);
-    });
-
-    it("stays shut for a read-only viewer", () => {
-      // The gate is the template expression editingDescription = editable; 
without it a shared
-      // read-only row opens an editor whose save the backend then rejects.
-      const el = render(makeWorkflowEntry(), false);
-
-      el.querySelector<HTMLElement>(".workflow-description")?.click();
-      fixture.detectChanges();
-
-      expect(component.editingDescription).toBe(false);
-    });
-  });
-
-  describe("ownership", () => {
-    it("tells a non-owner what access they have and who shared it", () => {
-      const entry = makeWorkflowEntry();
-      entry.workflow.isOwner = false;
-      entry.workflow.accessLevel = "READ";
-      entry.workflow.ownerName = "Bob";
-      render(entry);
-
-      // Pins the order of the two interpolations.
-      expect(tooltipTitles()).toContain("READ access shared by Bob");
-    });
-
-    it("shows no shared-access marker to the owner", () => {
-      const entry = makeWorkflowEntry();
-      entry.workflow.isOwner = true;
-      render(entry);
-
-      expect(tooltipTitles().some(t => typeof t === "string" && 
t.includes("access shared by"))).toBe(false);
-    });
-
-    it("disables deleting a workflow the viewer does not own", () => {
-      const entry = makeWorkflowEntry();
-      entry.workflow.isOwner = false;
-      const el = render(entry);
-
-      
expect(el.querySelector<HTMLButtonElement>("button[nz-popconfirm]")?.disabled).toBe(true);
-    });
-  });
-
-  describe("row actions", () => {
-    it("withholds the executions action while execution tracking is off", () 
=> {
-      render(makeWorkflowEntry());
-
-      expect(tooltipTitles().some(t => typeof t === "string" && 
t.startsWith("Executions of the workflow"))).toBe(
-        false
-      );
-    });
-
-    it("offers the executions action once execution tracking is on", async () 
=> {
-      await setup({ executionsTracking: true });
-      render(makeWorkflowEntry());
-
-      expect(tooltipTitles().some(t => typeof t === "string" && 
t.startsWith("Executions of the workflow"))).toBe(true);
-    });
-
-    it("keeps duplicate and delete on their own outputs", () => {
-      // Adjacent icon buttons; emitting the wrong one of these would be 
destructive.
-      render(makeWorkflowEntry());
-      const duplicated = vi.fn();
-      const deleted = vi.fn();
-      component.duplicated.subscribe(duplicated);
-      component.deleted.subscribe(deleted);
-
-      const dup = byTooltip(t => t.startsWith("Duplicate"));
-      expect(dup.length).toBe(1);
-      dup[0].click();
-      expect(duplicated).toHaveBeenCalledTimes(1);
-      expect(deleted).not.toHaveBeenCalled();
-
-      
fixture.debugElement.query(By.css("button[nz-popconfirm]")).triggerEventHandler("nzOnConfirm",
 null);
-      expect(deleted).toHaveBeenCalledTimes(1);
-      expect(duplicated).toHaveBeenCalledTimes(1);
-    });
-
-    it("opens the executions modal from the history action", async () => {
-      await setup({ executionsTracking: true });
-      render(makeWorkflowEntry({ wid: 11, name: "wf" }));
-      const modal = TestBed.inject(NzModalService);
-      const create = vi.spyOn(modal, "create").mockReturnValue({} as any);
-
-      onlyByTooltip(t => t.startsWith("Executions of the workflow")).click();
-
-      expect(create).toHaveBeenCalledWith(
-        expect.objectContaining({ nzContent: 
WorkflowExecutionHistoryComponent, nzData: { wid: 11 } })
-      );
-    });
-  });
-
-  describe("inline name and description editors", () => {
-    it("puts name editing behind the pencil and description editing behind the 
plus", () => {
-      // Two adjacent icon buttons on the same toolbar; swapping them would 
open the wrong editor.
-      render(makeWorkflowEntry());
-      expect(component.editingName).toBe(false);
-      expect(component.editingDescription).toBe(false);
-
-      onlyByTooltip(t => t === "Customize Workflow Name").click();
-
-      expect(component.editingName).toBe(true);
-      expect(component.editingDescription).toBe(false);
-
-      onlyByTooltip(t => t === "Add Description").click();
-
-      expect(component.editingDescription).toBe(true);
-    });
-  });
-
-  describe("selection checkbox", () => {
-    it("indents the avatar only when the checkbox is absent", () => {
-      const withBox = render(makeWorkflowEntry(), 
true).querySelector<HTMLElement>("nz-list-item-meta-avatar")!;
-      expect(withBox.style.marginLeft).not.toBe("16px");
-
-      const withoutBox = render(makeWorkflowEntry(), 
false).querySelector<HTMLElement>("nz-list-item-meta-avatar")!;
-      expect(withoutBox.style.marginLeft).toBe("16px");
-      expect(withoutBox.querySelector(".workflow-item-checkbox")).toBeNull();
-    });
-
-    it("records the selection on the entry", () => {
-      const entry = makeWorkflowEntry();
-      render(entry, true);
-
-      
fixture.debugElement.query(By.css(".workflow-item-checkbox")).triggerEventHandler("ngModelChange",
 true);
-
-      expect(entry.checked).toBe(true);
-    });
-  });
-});
diff --git 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.ts
 
b/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.ts
deleted file mode 100644
index f16ae54da9..0000000000
--- 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow-list-item/user-workflow-list-item.component.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { Component, EventEmitter, Input, Output } from "@angular/core";
-import { NzModalService } from "ng-zorro-antd/modal";
-import { WorkflowExecutionHistoryComponent } from 
"../ngbd-modal-workflow-executions/workflow-execution-history.component";
-import {
-  DEFAULT_WORKFLOW_NAME,
-  WorkflowPersistService,
-} from 
"../../../../../common/service/workflow-persist/workflow-persist.service";
-import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy";
-import { ShareAccessComponent } from 
"../../share-access/share-access.component";
-import { Workflow } from "../../../../../common/type/workflow";
-import { DashboardEntry } from "../../../../type/dashboard-entry";
-import { firstValueFrom } from "rxjs";
-import { DownloadService } from 
"src/app/dashboard/service/user/download/download.service";
-import { USER_WORKSPACE } from "../../../../../app-routing.constant";
-import { GuiConfigService } from 
"../../../../../common/service/gui-config.service";
-import {
-  NzListItemComponent,
-  NzListItemMetaComponent,
-  NzListItemMetaAvatarComponent,
-  NzListItemMetaTitleComponent,
-  NzListItemMetaDescriptionComponent,
-  NzListItemActionsComponent,
-  NzListItemActionComponent,
-} from "ng-zorro-antd/list";
-import { NgStyle, NgIf, DatePipe } from "@angular/common";
-import { FormsModule } from "@angular/forms";
-import { NzAvatarComponent } from "ng-zorro-antd/avatar";
-import { RouterLink } from "@angular/router";
-import { NzSpaceCompactItemDirective } from "ng-zorro-antd/space";
-import { NzButtonComponent } from "ng-zorro-antd/button";
-import { ɵNzTransitionPatchDirective } from 
"ng-zorro-antd/core/transition-patch";
-import { NzTooltipDirective } from "ng-zorro-antd/tooltip";
-import { NzIconDirective } from "ng-zorro-antd/icon";
-import { NzWaveDirective } from "ng-zorro-antd/core/wave";
-import { NzPopconfirmDirective } from "ng-zorro-antd/popconfirm";
-import { HighlightSearchTermsPipe } from "./highlight-search-terms.pipe";
-
-@UntilDestroy()
-@Component({
-  selector: "texera-user-workflow-list-item",
-  templateUrl: "./user-workflow-list-item.component.html",
-  styleUrls: ["./user-workflow-list-item.component.scss"],
-  imports: [
-    NzListItemComponent,
-    NzListItemMetaComponent,
-    NzListItemMetaAvatarComponent,
-    NgStyle,
-    NgIf,
-    FormsModule,
-    NzAvatarComponent,
-    NzListItemMetaTitleComponent,
-    RouterLink,
-    NzSpaceCompactItemDirective,
-    NzButtonComponent,
-    ɵNzTransitionPatchDirective,
-    NzTooltipDirective,
-    NzIconDirective,
-    NzListItemMetaDescriptionComponent,
-    NzListItemActionsComponent,
-    NzListItemActionComponent,
-    NzWaveDirective,
-    NzPopconfirmDirective,
-    DatePipe,
-    HighlightSearchTermsPipe,
-  ],
-})
-export class UserWorkflowListItemComponent {
-  protected readonly USER_WORKSPACE = USER_WORKSPACE;
-  private _entry?: DashboardEntry;
-  @Input() public keywords: string[] = [];
-
-  @Input()
-  get entry(): DashboardEntry {
-    if (!this._entry) {
-      throw new Error("entry property must be provided to 
UserWorkflowListItemComponent.");
-    }
-    return this._entry;
-  }
-
-  set entry(value: DashboardEntry) {
-    this._entry = value;
-  }
-
-  get workflow(): Workflow {
-    if (!this.entry.workflow) {
-      throw new Error(
-        "Incorrect type of DashboardEntry provided to 
UserWorkflowListItemComponent. Entry must be workflow."
-      );
-    }
-    return this.entry.workflow.workflow;
-  }
-
-  @Input() editable = false;
-  @Output() deleted = new EventEmitter<void>();
-  @Output() duplicated = new EventEmitter<void>();
-
-  editingName = false;
-  editingDescription = false;
-
-  constructor(
-    private workflowPersistService: WorkflowPersistService,
-    private modalService: NzModalService,
-    protected config: GuiConfigService,
-    private downloadService: DownloadService
-  ) {}
-
-  /**
-   * open the workflow executions page
-   */
-  public onClickGetWorkflowExecutions(): void {
-    this.modalService.create({
-      nzContent: WorkflowExecutionHistoryComponent,
-      nzData: { wid: this.workflow.wid },
-      nzTitle: "Execution results of Workflow: " + this.workflow.name,
-      nzFooter: null,
-      nzWidth: "80%",
-      nzCentered: true,
-    });
-  }
-
-  public confirmUpdateWorkflowCustomName(name: string): void {
-    if (this.workflow.wid === undefined) {
-      return;
-    }
-
-    this.workflowPersistService
-      .updateWorkflowName(this.workflow.wid, name || DEFAULT_WORKFLOW_NAME)
-      .pipe(untilDestroyed(this))
-      .subscribe(() => {
-        this.workflow.name = name || DEFAULT_WORKFLOW_NAME;
-      })
-      .add(() => {
-        this.editingName = false;
-      });
-  }
-
-  public confirmUpdateWorkflowCustomDescription(description: string): void {
-    if (this.workflow.wid === undefined) {
-      return;
-    }
-
-    this.workflowPersistService
-      .updateWorkflowDescription(this.workflow.wid, description)
-      .pipe(untilDestroyed(this))
-      .subscribe(() => {
-        this.workflow.description = description;
-      })
-      .add(() => {
-        this.editingDescription = false;
-      });
-  }
-
-  /**
-   * open the Modal based on the workflow clicked on
-   */
-  public async onClickOpenShareAccess(): Promise<void> {
-    this.modalService.create({
-      nzContent: ShareAccessComponent,
-      nzData: {
-        writeAccess: this.entry.workflow.accessLevel === "WRITE",
-        type: "workflow",
-        id: this.workflow.wid,
-        allOwners: await 
firstValueFrom(this.workflowPersistService.retrieveOwners()),
-      },
-      nzFooter: null,
-      nzTitle: "Share this workflow with others",
-      nzCentered: true,
-    });
-  }
-
-  /**
-   * Download the workflow as a json file
-   */
-  public onClickDownloadWorkfllow(): void {
-    if (this.workflow.wid) {
-      this.downloadService
-        .downloadWorkflow(this.workflow.wid, this.workflow.name)
-        .pipe(untilDestroyed(this))
-        .subscribe();
-    }
-  }
-}
diff --git 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow.component.spec.ts
 
b/frontend/src/app/dashboard/component/user/user-workflow/user-workflow.component.spec.ts
index 764b4bdc11..cd6ecc446c 100644
--- 
a/frontend/src/app/dashboard/component/user/user-workflow/user-workflow.component.spec.ts
+++ 
b/frontend/src/app/dashboard/component/user/user-workflow/user-workflow.component.spec.ts
@@ -57,7 +57,6 @@ import {
   testWorkflowFileNameConflictEntries,
 } from "../../user-dashboard-test-fixtures";
 import { FiltersComponent } from "../filters/filters.component";
-import { UserWorkflowListItemComponent } from 
"./user-workflow-list-item/user-workflow-list-item.component";
 import { SearchService } from "../../../service/user/search.service";
 import { StubSearchService } from "../../../service/user/stub-search.service";
 import { SearchResultsComponent } from 
"../search-results/search-results.component";
@@ -104,7 +103,6 @@ describe("SavedWorkflowSectionComponent", () => {
         UserWorkflowComponent,
         ShareAccessComponent,
         FiltersComponent,
-        UserWorkflowListItemComponent,
         SearchResultsComponent,
         FormsModule,
         RouterTestingModule,
diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss
index 129826fa3d..3625505f95 100644
--- a/frontend/src/styles.scss
+++ b/frontend/src/styles.scss
@@ -65,11 +65,6 @@ hr {
   border: 0;
 }
 
-// due to innerHTML, this rule has to be global
-.highlight-search-terms {
-  color: blue;
-}
-
 .box {
   border-radius: 5px;
   box-shadow:

Reply via email to