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

zhoujinsong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/amoro.git


The following commit(s) were added to refs/heads/master by this push:
     new 4ed2e91e3 [AMORO-4236]  Splitting the “Optimizing” tab into the 
“Optimizing” tab,“Cleanup” tab and “Profiling” tab (#4238)
4ed2e91e3 is described below

commit 4ed2e91e3f70f3f3c0f8ca2b0cda5e187608041e
Author: WenLingzhang <[email protected]>
AuthorDate: Tue Jun 9 17:04:59 2026 +0800

    [AMORO-4236]  Splitting the “Optimizing” tab into the “Optimizing” 
tab,“Cleanup” tab and “Profiling” tab (#4238)
    
    * Add Maintenance tab for table process management
    
    * fix optimizing types in PaimonTableDescriptor
    
    * Refactor OPTIMIZING tab from OPTIMIZING to OPTIMIZING/CLEANUP/PROFILING 
tab
    
    * Replace static resolveCategoryTypes/matchProcessCategory with instance 
method getProcessTypesByCategory, moving routing logic into each descriptor.
    
    * fixup style
    
    ---------
    
    Co-authored-by: 张文领 <[email protected]>
---
 .../amoro/server/dashboard/DashboardServer.java    |   4 +-
 .../dashboard/MixedAndIcebergTableDescriptor.java  |  88 +++++++++++++++-
 .../server/dashboard/ServerTableDescriptor.java    |  14 ++-
 .../dashboard/controller/TableController.java      |  25 ++++-
 .../persistence/mapper/TableProcessMapper.java     |   2 +
 .../TestIcebergServerTableDescriptor.java          | 117 ++++++++++++++++++++-
 .../server/optimizing/BaseOptimizingChecker.java   |   6 +-
 .../inline/TestProcessDataExpiringExecutor.java    |   3 +-
 .../table/descriptor/FormatTableDescriptor.java    |  21 +++-
 .../amoro/table/descriptor/ProcessCategory.java    |  55 ++++++++++
 .../amoro/formats/hudi/HudiTableDescriptor.java    |  25 ++++-
 .../formats/paimon/PaimonTableDescriptor.java      |  34 +++++-
 amoro-web/mock/modules/table.js                    |  33 ++++--
 amoro-web/src/language/en.ts                       |   5 +
 amoro-web/src/language/zh.ts                       |   5 +
 amoro-web/src/services/table.service.ts            |  14 +--
 amoro-web/src/views/tables/components/Cleanup.vue  |  26 +++++
 .../src/views/tables/components/Optimizing.vue     |  41 +++++---
 .../src/views/tables/components/Profiling.vue      |  26 +++++
 amoro-web/src/views/tables/index.vue               |   6 ++
 20 files changed, 493 insertions(+), 57 deletions(-)

diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/DashboardServer.java
 
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/DashboardServer.java
index 2246cf68b..f6e1ab29d 100644
--- 
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/DashboardServer.java
+++ 
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/DashboardServer.java
@@ -268,8 +268,8 @@ public class DashboardServer {
                 
"/catalogs/{catalog}/dbs/{db}/tables/{table}/optimizing-processes",
                 tableController::getOptimizingProcesses);
             get(
-                "/catalogs/{catalog}/dbs/{db}/tables/{table}/optimizing-types",
-                tableController::getOptimizingTypes);
+                "/catalogs/{catalog}/dbs/{db}/tables/{table}/process-types",
+                tableController::getProcessTypes);
             get(
                 
"/catalogs/{catalog}/dbs/{db}/tables/{table}/optimizing-processes/{processId}/tasks",
                 tableController::getOptimizingProcessTasks);
diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/MixedAndIcebergTableDescriptor.java
 
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/MixedAndIcebergTableDescriptor.java
index 7f3a49d0c..f6c1dd8d3 100644
--- 
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/MixedAndIcebergTableDescriptor.java
+++ 
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/MixedAndIcebergTableDescriptor.java
@@ -22,6 +22,7 @@ import com.github.pagehelper.Page;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import org.apache.amoro.AmoroTable;
+import org.apache.amoro.IcebergActions;
 import org.apache.amoro.ServerTableIdentifier;
 import org.apache.amoro.TableFormat;
 import org.apache.amoro.api.CommitMetaProducer;
@@ -67,12 +68,14 @@ import 
org.apache.amoro.table.descriptor.OptimizingProcessInfo;
 import org.apache.amoro.table.descriptor.OptimizingTaskInfo;
 import org.apache.amoro.table.descriptor.PartitionBaseInfo;
 import org.apache.amoro.table.descriptor.PartitionFileBaseInfo;
+import org.apache.amoro.table.descriptor.ProcessCategory;
 import org.apache.amoro.table.descriptor.ServerTableMeta;
 import org.apache.amoro.table.descriptor.TableSummary;
 import org.apache.amoro.table.descriptor.TagOrBranchInfo;
 import org.apache.amoro.utils.MixedDataFiles;
 import org.apache.amoro.utils.MixedTableUtil;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.iceberg.ContentFile;
 import org.apache.iceberg.FileScanTask;
@@ -118,6 +121,19 @@ public class MixedAndIcebergTableDescriptor extends 
PersistentBase
 
   private static final Logger LOG = 
LoggerFactory.getLogger(MixedAndIcebergTableDescriptor.class);
 
+  private static final List<String> OPTIMIZING_TYPE_LIST =
+      
Arrays.stream(OptimizingType.values()).map(Enum::name).collect(Collectors.toList());
+
+  private static final List<String> CLEANUP_TYPE_LIST =
+      ImmutableList.of(
+          IcebergActions.EXPIRE_SNAPSHOTS.getName(),
+          IcebergActions.CLEAN_ORPHAN.getName(),
+          IcebergActions.CLEAN_DANGLING_DELETE.getName(),
+          IcebergActions.EXPIRE_DATA.getName());
+
+  private static final List<String> PROFILING_TYPE_LIST =
+      ImmutableList.of(IcebergActions.AUTO_CREATE_TAGS.getName());
+
   private ExecutorService executorService;
 
   @Override
@@ -655,7 +671,12 @@ public class MixedAndIcebergTableDescriptor extends 
PersistentBase
 
   @Override
   public Pair<List<OptimizingProcessInfo>, Integer> getOptimizingProcessesInfo(
-      AmoroTable<?> amoroTable, String type, ProcessStatus status, int limit, 
int offset) {
+      AmoroTable<?> amoroTable,
+      String type,
+      String processCategory,
+      ProcessStatus status,
+      int limit,
+      int offset) {
     TableIdentifier tableIdentifier = amoroTable.id();
     ServerTableIdentifier identifier =
         getAs(
@@ -671,12 +692,33 @@ public class MixedAndIcebergTableDescriptor extends 
PersistentBase
     int total = 0;
     // page helper is 1-based
     int pageNumber = (offset / limit) + 1;
+
+    // Only apply category filtering when type is not specified
+    final List<String> includeTypes;
+
+    if (StringUtils.isBlank(type)) {
+      if (processCategory == null) {
+        // No category specified: return empty results
+        return Pair.of(Collections.emptyList(), 0);
+      } else {
+        List<String> categoryTypes = 
getProcessTypesByCategory(processCategory);
+        if (categoryTypes.isEmpty()) {
+          // Unknown category: return empty results to avoid exposing all 
processes
+          return Pair.of(Collections.emptyList(), 0);
+        }
+
+        includeTypes = categoryTypes;
+      }
+    } else {
+      includeTypes = null;
+    }
+
     List<TableProcessMeta> processMetaList = Collections.emptyList();
     try (Page<?> ignored = PageHelper.startPage(pageNumber, limit, true)) {
       processMetaList =
           getAs(
               TableProcessMapper.class,
-              mapper -> mapper.listProcessMeta(identifier.getId(), type, 
status));
+              mapper -> mapper.listProcessMeta(identifier.getId(), type, 
includeTypes, status));
       PageInfo<TableProcessMeta> pageInfo = new PageInfo<>(processMetaList);
       total = (int) pageInfo.getTotal();
       LOG.info(
@@ -716,6 +758,48 @@ public class MixedAndIcebergTableDescriptor extends 
PersistentBase
     return types;
   }
 
+  @Override
+  public Map<String, String> getTableProcessTypes(
+      AmoroTable<?> amoroTable, String processCategory) {
+    if 
(ProcessCategory.OPTIMIZING.getName().equalsIgnoreCase(processCategory)) {
+      return getTableOptimizingTypes(amoroTable);
+    }
+
+    if (ProcessCategory.CLEANUP.getName().equalsIgnoreCase(processCategory)) {
+      Map<String, String> types = Maps.newHashMap();
+      types.put(IcebergActions.EXPIRE_SNAPSHOTS.getName(), "Expire Snapshots");
+      types.put(IcebergActions.CLEAN_ORPHAN.getName(), "Clean Orphan Files");
+      types.put(IcebergActions.CLEAN_DANGLING_DELETE.getName(), "Clean 
Dangling Delete Files");
+      types.put(IcebergActions.EXPIRE_DATA.getName(), "Expire Data");
+      return types;
+    }
+
+    if (ProcessCategory.PROFILING.getName().equalsIgnoreCase(processCategory)) 
{
+      Map<String, String> types = Maps.newHashMap();
+      types.put(IcebergActions.AUTO_CREATE_TAGS.getName(), "Auto Create Tags");
+      return types;
+    }
+
+    return Collections.emptyMap();
+  }
+
+  @Override
+  public List<String> getProcessTypesByCategory(String processCategory) {
+    if 
(ProcessCategory.OPTIMIZING.getName().equalsIgnoreCase(processCategory)) {
+      return OPTIMIZING_TYPE_LIST;
+    }
+
+    if (ProcessCategory.CLEANUP.getName().equalsIgnoreCase(processCategory)) {
+      return CLEANUP_TYPE_LIST;
+    }
+
+    if (ProcessCategory.PROFILING.getName().equalsIgnoreCase(processCategory)) 
{
+      return PROFILING_TYPE_LIST;
+    }
+
+    return Collections.emptyList();
+  }
+
   @Override
   public List<OptimizingTaskInfo> getOptimizingTaskInfos(
       AmoroTable<?> amoroTable, String processId) {
diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/ServerTableDescriptor.java
 
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/ServerTableDescriptor.java
index 4e2b1aef8..bbd68bf69 100644
--- 
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/ServerTableDescriptor.java
+++ 
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/ServerTableDescriptor.java
@@ -129,11 +129,16 @@ public class ServerTableDescriptor extends PersistentBase 
{
   }
 
   public Pair<List<OptimizingProcessInfo>, Integer> getOptimizingProcessesInfo(
-      TableIdentifier tableIdentifier, String type, ProcessStatus status, int 
limit, int offset) {
+      TableIdentifier tableIdentifier,
+      String type,
+      String processCategory,
+      ProcessStatus status,
+      int limit,
+      int offset) {
     AmoroTable<?> amoroTable = loadTable(tableIdentifier);
     FormatTableDescriptor formatTableDescriptor = 
formatDescriptorMap.get(amoroTable.format());
     return formatTableDescriptor.getOptimizingProcessesInfo(
-        amoroTable, type, status, limit, offset);
+        amoroTable, type, processCategory, status, limit, offset);
   }
 
   public List<OptimizingTaskInfo> getOptimizingProcessTaskInfos(
@@ -143,10 +148,11 @@ public class ServerTableDescriptor extends PersistentBase 
{
     return formatTableDescriptor.getOptimizingTaskInfos(amoroTable, processId);
   }
 
-  public Map<String, String> getTableOptimizingTypes(TableIdentifier 
tableIdentifier) {
+  public Map<String, String> getTableProcessTypes(
+      TableIdentifier tableIdentifier, String processCategory) {
     AmoroTable<?> amoroTable = loadTable(tableIdentifier);
     FormatTableDescriptor formatTableDescriptor = 
formatDescriptorMap.get(amoroTable.format());
-    return formatTableDescriptor.getTableOptimizingTypes(amoroTable);
+    return formatTableDescriptor.getTableProcessTypes(amoroTable, 
processCategory);
   }
 
   private AmoroTable<?> loadTable(TableIdentifier identifier) {
diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/TableController.java
 
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/TableController.java
index 8b4acba44..81d29a425 100644
--- 
a/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/TableController.java
+++ 
b/amoro-ams/src/main/java/org/apache/amoro/server/dashboard/controller/TableController.java
@@ -71,6 +71,7 @@ import 
org.apache.amoro.table.descriptor.OptimizingProcessInfo;
 import org.apache.amoro.table.descriptor.OptimizingTaskInfo;
 import org.apache.amoro.table.descriptor.PartitionBaseInfo;
 import org.apache.amoro.table.descriptor.PartitionFileBaseInfo;
+import org.apache.amoro.table.descriptor.ProcessCategory;
 import org.apache.amoro.table.descriptor.ServerTableMeta;
 import org.apache.amoro.table.descriptor.TableSummary;
 import org.apache.amoro.table.descriptor.TagOrBranchInfo;
@@ -332,6 +333,11 @@ public class TableController {
       type = null;
     }
 
+    String processCategory = ctx.queryParam("processCategory");
+    if (StringUtils.isBlank(processCategory)) {
+      processCategory = null;
+    }
+
     String status = ctx.queryParam("status");
     Integer page = ctx.queryParamAsClass("page", 
Integer.class).getOrDefault(1);
     Integer pageSize = ctx.queryParamAsClass("pageSize", 
Integer.class).getOrDefault(20);
@@ -346,21 +352,32 @@ public class TableController {
         StringUtils.isBlank(status) ? null : ProcessStatus.valueOf(status);
     Pair<List<OptimizingProcessInfo>, Integer> optimizingProcessesInfo =
         tableDescriptor.getOptimizingProcessesInfo(
-            tableIdentifier.buildTableIdentifier(), type, processStatus, 
limit, offset);
+            tableIdentifier.buildTableIdentifier(),
+            type,
+            processCategory,
+            processStatus,
+            limit,
+            offset);
     List<OptimizingProcessInfo> result = optimizingProcessesInfo.getLeft();
     int total = optimizingProcessesInfo.getRight();
 
     ctx.json(OkResponse.of(PageResult.of(result, total)));
   }
 
-  public void getOptimizingTypes(Context ctx) {
+  public void getProcessTypes(Context ctx) {
     String catalog = ctx.pathParam("catalog");
     String db = ctx.pathParam("db");
     String table = ctx.pathParam("table");
+    String processCategory =
+        ctx.queryParamAsClass("processCategory", 
String.class).getOrDefault(null);
+    if (StringUtils.isBlank(processCategory)) {
+      processCategory = ProcessCategory.OPTIMIZING.getName();
+    }
     TableIdentifier tableIdentifier = TableIdentifier.of(catalog, db, table);
 
     Map<String, String> values =
-        
tableDescriptor.getTableOptimizingTypes(tableIdentifier.buildTableIdentifier());
+        tableDescriptor.getTableProcessTypes(
+            tableIdentifier.buildTableIdentifier(), processCategory);
     ctx.json(OkResponse.of(values));
   }
 
@@ -671,7 +688,7 @@ public class TableController {
   }
 
   /**
-   * cancel the running optimizing process of one certain table.
+   * Cancel the running process of one certain table.
    *
    * @param ctx - context for handling the request and response
    */
diff --git 
a/amoro-ams/src/main/java/org/apache/amoro/server/persistence/mapper/TableProcessMapper.java
 
b/amoro-ams/src/main/java/org/apache/amoro/server/persistence/mapper/TableProcessMapper.java
index bbf4019c7..ba21e01ff 100644
--- 
a/amoro-ams/src/main/java/org/apache/amoro/server/persistence/mapper/TableProcessMapper.java
+++ 
b/amoro-ams/src/main/java/org/apache/amoro/server/persistence/mapper/TableProcessMapper.java
@@ -131,6 +131,7 @@ public interface TableProcessMapper {
           + "create_time, finish_time, fail_message, process_parameters, 
summary "
           + "FROM table_process WHERE table_id = #{tableId} "
           + " <if test='processType != null'> AND process_type = 
#{processType}</if>"
+          + " <if test='processType == null and includeTypes != null and 
includeTypes.size() > 0'> AND process_type IN <foreach 
collection='includeTypes' item='type' open='(' separator=',' 
close=')'>#{type}</foreach></if>"
           + " <if test='status != null'> AND status = #{status}</if>"
           + " ORDER BY process_id desc"
           + "</script>")
@@ -138,6 +139,7 @@ public interface TableProcessMapper {
   List<TableProcessMeta> listProcessMeta(
       @Param("tableId") long tableId,
       @Param("processType") String processType,
+      @Param("includeTypes") List<String> includeTypes,
       @Param("status") ProcessStatus optimizingStatus);
 
   @Select(
diff --git 
a/amoro-ams/src/test/java/org/apache/amoro/server/dashboard/TestIcebergServerTableDescriptor.java
 
b/amoro-ams/src/test/java/org/apache/amoro/server/dashboard/TestIcebergServerTableDescriptor.java
index 4b9d6b296..cf2a856fe 100644
--- 
a/amoro-ams/src/test/java/org/apache/amoro/server/dashboard/TestIcebergServerTableDescriptor.java
+++ 
b/amoro-ams/src/test/java/org/apache/amoro/server/dashboard/TestIcebergServerTableDescriptor.java
@@ -21,7 +21,9 @@ package org.apache.amoro.server.dashboard;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
+import org.apache.amoro.Action;
 import org.apache.amoro.AmoroTable;
+import org.apache.amoro.IcebergActions;
 import org.apache.amoro.ServerTableIdentifier;
 import org.apache.amoro.TableFormat;
 import org.apache.amoro.formats.AmoroCatalogTestHelper;
@@ -301,21 +303,25 @@ public class TestIcebergServerTableDescriptor extends 
TestServerTableDescriptor
     doReturn(tableIdentifier).when(table).id();
 
     Pair<List<OptimizingProcessInfo>, Integer> res =
-        descriptor.getOptimizingProcessesInfo(table, null, null, 4, 4);
+        descriptor.getOptimizingProcessesInfo(table, null, "OPTIMIZING", null, 
4, 4);
     Integer expectReturnItemSizeForNoTypeNoStatusOffset0Limit5 = 4;
     Integer expectTotalForNoTypeNoStatusOffset0Limit5 = 10;
     Assert.assertEquals(
         expectReturnItemSizeForNoTypeNoStatusOffset0Limit5, (Integer) 
res.getLeft().size());
     Assert.assertEquals(expectTotalForNoTypeNoStatusOffset0Limit5, 
res.getRight());
 
-    res = descriptor.getOptimizingProcessesInfo(table, null, 
ProcessStatus.SUCCESS, 5, 0);
+    res =
+        descriptor.getOptimizingProcessesInfo(
+            table, null, "OPTIMIZING", ProcessStatus.SUCCESS, 5, 0);
     Integer expectReturnItemSizeForOnlyStatusOffset0limit5 = 5;
     Integer expectedTotalForOnlyStatusOffset0Limit5 = 7;
     Assert.assertEquals(
         expectReturnItemSizeForOnlyStatusOffset0limit5, (Integer) 
res.getLeft().size());
     Assert.assertEquals(expectedTotalForOnlyStatusOffset0Limit5, 
res.getRight());
 
-    res = descriptor.getOptimizingProcessesInfo(table, 
OptimizingType.MINOR.name(), null, 5, 0);
+    res =
+        descriptor.getOptimizingProcessesInfo(
+            table, OptimizingType.MINOR.name(), "OPTIMIZING", null, 5, 0);
     Integer expectedRetItemsSizeForOnlyTypeOffset0Limit5 = 4;
     Integer expectedRetTotalForOnlyTypeOffset0Limit5 = 4;
     Assert.assertEquals(
@@ -324,7 +330,7 @@ public class TestIcebergServerTableDescriptor extends 
TestServerTableDescriptor
 
     res =
         descriptor.getOptimizingProcessesInfo(
-            table, OptimizingType.MINOR.name(), ProcessStatus.SUCCESS, 2, 2);
+            table, OptimizingType.MINOR.name(), "OPTIMIZING", 
ProcessStatus.SUCCESS, 2, 2);
     Integer expectedRetItemSizeForBothTypeAndStatusOffset2Limit2 = 2;
     Integer expectedRetTotalForBothTypeAndStatusOffset2Limit2 = 4;
     Assert.assertEquals(
@@ -332,6 +338,85 @@ public class TestIcebergServerTableDescriptor extends 
TestServerTableDescriptor
     Assert.assertEquals(expectedRetTotalForBothTypeAndStatusOffset2Limit2, 
res.getRight());
   }
 
+  @Test
+  public void testProcessCategoryFiltering() {
+    TestMixedAndIcebergTableDescriptor descriptor = new 
TestMixedAndIcebergTableDescriptor();
+
+    String catalogName = "catalog1";
+    String dbName = "db1";
+    String tableName = "table1";
+
+    ServerTableIdentifier identifier =
+        ServerTableIdentifier.of(1L, catalogName, dbName, tableName, 
TableFormat.ICEBERG);
+    descriptor.insertTable(identifier);
+    MetricsSummary dummySummary = new MetricsSummary();
+    dummySummary.setNewDeleteFileCnt(1);
+    dummySummary.setNewDataFileCnt(1);
+    dummySummary.setNewDataSize(1);
+    dummySummary.setNewDeleteSize(1);
+
+    // Insert OPTIMIZING processes: MAJOR, MINOR
+    descriptor.insertOptimizingProcess(
+        identifier,
+        1L,
+        1,
+        1,
+        ProcessStatus.SUCCESS,
+        OptimizingType.MAJOR,
+        1L,
+        dummySummary,
+        Collections.emptyMap(),
+        Collections.emptyMap());
+    descriptor.insertOptimizingProcess(
+        identifier,
+        2L,
+        2L,
+        2L,
+        ProcessStatus.SUCCESS,
+        OptimizingType.MINOR,
+        2L,
+        dummySummary,
+        Collections.emptyMap(),
+        Collections.emptyMap());
+
+    // Insert CLEANUP processes: EXPIRE_SNAPSHOTS, CLEAN_ORPHAN
+    descriptor.insertIcebergActionProcess(
+        identifier, 3L, ProcessStatus.SUCCESS, 
IcebergActions.EXPIRE_SNAPSHOTS, 3L, dummySummary);
+    descriptor.insertIcebergActionProcess(
+        identifier, 4L, ProcessStatus.SUCCESS, IcebergActions.CLEAN_ORPHAN, 
4L, dummySummary);
+
+    // Insert PROFILING process: AUTO_CREATE_TAGS
+    descriptor.insertIcebergActionProcess(
+        identifier, 5L, ProcessStatus.SUCCESS, 
IcebergActions.AUTO_CREATE_TAGS, 5L, dummySummary);
+
+    AmoroTable<?> table = mock(IcebergTable.class);
+    TableIdentifier tableIdentifier =
+        TableIdentifier.of(
+            identifier.getCatalog(), identifier.getDatabase(), 
identifier.getTableName());
+    doReturn(tableIdentifier).when(table).id();
+
+    // Test OPTIMIZING category: should return only MAJOR and MINOR
+    Pair<List<OptimizingProcessInfo>, Integer> res =
+        descriptor.getOptimizingProcessesInfo(table, null, "OPTIMIZING", null, 
10, 0);
+    Assert.assertEquals(2, (int) res.getRight());
+    Assert.assertEquals(2, res.getLeft().size());
+
+    // Test CLEANUP category: should return EXPIRE_SNAPSHOTS and CLEAN_ORPHAN
+    res = descriptor.getOptimizingProcessesInfo(table, null, "CLEANUP", null, 
10, 0);
+    Assert.assertEquals(2, (int) res.getRight());
+    Assert.assertEquals(2, res.getLeft().size());
+
+    // Test PROFILING category: should return only AUTO_CREATE_TAGS
+    res = descriptor.getOptimizingProcessesInfo(table, null, "PROFILING", 
null, 10, 0);
+    Assert.assertEquals(1, (int) res.getRight());
+    Assert.assertEquals(1, res.getLeft().size());
+
+    // Test null category: should return empty results
+    res = descriptor.getOptimizingProcessesInfo(table, null, null, null, 10, 
0);
+    Assert.assertEquals(0, (int) res.getRight());
+    Assert.assertEquals(0, res.getLeft().size());
+  }
+
   @Override
   protected void tableOperationsRenameColumns() {
     getTable().updateSchema().renameColumn("new_col", "renamed_col").commit();
@@ -418,5 +503,29 @@ public class TestIcebergServerTableDescriptor extends 
TestServerTableDescriptor
                   fromSequence,
                   toSequence));
     }
+
+    public void insertIcebergActionProcess(
+        ServerTableIdentifier identifier,
+        long processId,
+        ProcessStatus status,
+        Action action,
+        long planTime,
+        MetricsSummary summary) {
+      doAs(
+          TableProcessMapper.class,
+          mapper ->
+              mapper.insertProcess(
+                  identifier.getId(),
+                  processId,
+                  "",
+                  status,
+                  action.getName(),
+                  action.getName(),
+                  "AMORO",
+                  0,
+                  planTime,
+                  new HashMap<>(),
+                  summary.summaryAsMap(false)));
+    }
   }
 }
diff --git 
a/amoro-ams/src/test/java/org/apache/amoro/server/optimizing/BaseOptimizingChecker.java
 
b/amoro-ams/src/test/java/org/apache/amoro/server/optimizing/BaseOptimizingChecker.java
index 06ae381a5..d440b9e54 100644
--- 
a/amoro-ams/src/test/java/org/apache/amoro/server/optimizing/BaseOptimizingChecker.java
+++ 
b/amoro-ams/src/test/java/org/apache/amoro/server/optimizing/BaseOptimizingChecker.java
@@ -124,7 +124,7 @@ public class BaseOptimizingChecker extends PersistentBase {
                 List<TableProcessMeta> tableOptimizingProcesses =
                     getAs(
                         TableProcessMapper.class,
-                        mapper -> mapper.listProcessMeta(identifier.getId(), 
null, null));
+                        mapper -> mapper.listProcessMeta(identifier.getId(), 
null, null, null));
                 if (tableOptimizingProcesses == null || 
tableOptimizingProcesses.isEmpty()) {
                   LOG.info("optimize history is empty");
                   return Status.RUNNING;
@@ -157,7 +157,7 @@ public class BaseOptimizingChecker extends PersistentBase {
       List<TableProcessMeta> result =
           getAs(
                   TableProcessMapper.class,
-                  mapper -> mapper.listProcessMeta(identifier.getId(), null, 
null))
+                  mapper -> mapper.listProcessMeta(identifier.getId(), null, 
null, null))
               .stream()
               .filter(p -> p.getProcessId() > lastProcessId)
               .filter(p -> p.getStatus().equals(ProcessStatus.SUCCESS))
@@ -190,7 +190,7 @@ public class BaseOptimizingChecker extends PersistentBase {
     List<TableProcessMeta> tableOptimizingProcesses =
         getAs(
                 TableProcessMapper.class,
-                mapper -> mapper.listProcessMeta(identifier.getId(), null, 
null))
+                mapper -> mapper.listProcessMeta(identifier.getId(), null, 
null, null))
             .stream()
             .filter(p -> p.getProcessId() > lastProcessId)
             .collect(Collectors.toList());
diff --git 
a/amoro-ams/src/test/java/org/apache/amoro/server/scheduler/inline/TestProcessDataExpiringExecutor.java
 
b/amoro-ams/src/test/java/org/apache/amoro/server/scheduler/inline/TestProcessDataExpiringExecutor.java
index bd251b02d..8e2139ba6 100644
--- 
a/amoro-ams/src/test/java/org/apache/amoro/server/scheduler/inline/TestProcessDataExpiringExecutor.java
+++ 
b/amoro-ams/src/test/java/org/apache/amoro/server/scheduler/inline/TestProcessDataExpiringExecutor.java
@@ -184,7 +184,8 @@ public class TestProcessDataExpiringExecutor extends 
AMSServiceTestBase {
     }
 
     public List<TableProcessMeta> listProcesses(long tableId) {
-      return getAs(TableProcessMapper.class, mapper -> 
mapper.listProcessMeta(tableId, null, null));
+      return getAs(
+          TableProcessMapper.class, mapper -> mapper.listProcessMeta(tableId, 
null, null, null));
     }
 
     public void cleanAll(long tableId) {
diff --git 
a/amoro-common/src/main/java/org/apache/amoro/table/descriptor/FormatTableDescriptor.java
 
b/amoro-common/src/main/java/org/apache/amoro/table/descriptor/FormatTableDescriptor.java
index 1e8bc62c2..40261fc87 100644
--- 
a/amoro-common/src/main/java/org/apache/amoro/table/descriptor/FormatTableDescriptor.java
+++ 
b/amoro-common/src/main/java/org/apache/amoro/table/descriptor/FormatTableDescriptor.java
@@ -23,6 +23,7 @@ import org.apache.amoro.TableFormat;
 import org.apache.amoro.process.ProcessStatus;
 import org.apache.commons.lang3.tuple.Pair;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
@@ -63,11 +64,29 @@ public interface FormatTableDescriptor {
 
   /** Get the paged optimizing process information of the {@link AmoroTable} 
and total size. */
   Pair<List<OptimizingProcessInfo>, Integer> getOptimizingProcessesInfo(
-      AmoroTable<?> amoroTable, String type, ProcessStatus status, int limit, 
int offset);
+      AmoroTable<?> amoroTable,
+      String type,
+      String processCategory,
+      ProcessStatus status,
+      int limit,
+      int offset);
 
   /** Return the optimizing types of the {@link AmoroTable} is supported. */
   Map<String, String> getTableOptimizingTypes(AmoroTable<?> amoroTable);
 
+  /** Return the process types for the given category of the {@link 
AmoroTable}. */
+  default Map<String, String> getTableProcessTypes(
+      AmoroTable<?> amoroTable, String processCategory) {
+    if 
(ProcessCategory.OPTIMIZING.getName().equalsIgnoreCase(processCategory)) {
+      return getTableOptimizingTypes(amoroTable);
+    }
+
+    return Collections.emptyMap();
+  }
+
+  /** Returns the list of process type names belonging to the given category. 
*/
+  List<String> getProcessTypesByCategory(String processCategory);
+
   /** Get the paged optimizing process tasks information of the {@link 
AmoroTable}. */
   List<OptimizingTaskInfo> getOptimizingTaskInfos(AmoroTable<?> amoroTable, 
String processId);
 
diff --git 
a/amoro-common/src/main/java/org/apache/amoro/table/descriptor/ProcessCategory.java
 
b/amoro-common/src/main/java/org/apache/amoro/table/descriptor/ProcessCategory.java
new file mode 100644
index 000000000..070a5bc2f
--- /dev/null
+++ 
b/amoro-common/src/main/java/org/apache/amoro/table/descriptor/ProcessCategory.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+package org.apache.amoro.table.descriptor;
+
+import java.util.Arrays;
+
+/**
+ * Categories for table processes displayed in the dashboard.
+ * <li>OPTIMIZING: Performance optimization processes (e.g., compaction, 
clustering).
+ * <li>CLEANUP: Space reclamation and lifecycle management processes (e.g., 
expire snapshots, clean
+ *     orphan files).
+ * <li>PROFILING: Information enrichment and metadata augmentation processes 
(e.g., auto create
+ *     tags).
+ */
+public enum ProcessCategory {
+  OPTIMIZING("OPTIMIZING"),
+  CLEANUP("CLEANUP"),
+  PROFILING("PROFILING");
+
+  private final String name;
+
+  ProcessCategory(String name) {
+    this.name = name;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public static ProcessCategory fromString(String value) {
+    if (value == null) {
+      return null;
+    }
+    return Arrays.stream(values())
+        .filter(c -> c.name.equalsIgnoreCase(value))
+        .findFirst()
+        .orElse(null);
+  }
+}
diff --git 
a/amoro-format-hudi/src/main/java/org/apache/amoro/formats/hudi/HudiTableDescriptor.java
 
b/amoro-format-hudi/src/main/java/org/apache/amoro/formats/hudi/HudiTableDescriptor.java
index 04d089233..7f1a35880 100644
--- 
a/amoro-format-hudi/src/main/java/org/apache/amoro/formats/hudi/HudiTableDescriptor.java
+++ 
b/amoro-format-hudi/src/main/java/org/apache/amoro/formats/hudi/HudiTableDescriptor.java
@@ -37,6 +37,7 @@ import 
org.apache.amoro.table.descriptor.OptimizingProcessInfo;
 import org.apache.amoro.table.descriptor.OptimizingTaskInfo;
 import org.apache.amoro.table.descriptor.PartitionBaseInfo;
 import org.apache.amoro.table.descriptor.PartitionFileBaseInfo;
+import org.apache.amoro.table.descriptor.ProcessCategory;
 import org.apache.amoro.table.descriptor.ServerTableMeta;
 import org.apache.amoro.table.descriptor.TableSummary;
 import org.apache.amoro.table.descriptor.TagOrBranchInfo;
@@ -79,6 +80,7 @@ import javax.annotation.Nullable;
 import java.io.IOException;
 import java.text.ParseException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -97,6 +99,7 @@ public class HudiTableDescriptor implements 
FormatTableDescriptor {
   private static final Logger LOG = 
LoggerFactory.getLogger(HudiTableDescriptor.class);
   private static final String COMPACTION = "compaction";
   private static final String CLUSTERING = "clustering";
+  private static final List<String> OPTIMIZING_TYPES = 
Arrays.asList(COMPACTION, CLUSTERING);
   // table comment
   private static final String COMMENT = "comment";
 
@@ -340,7 +343,12 @@ public class HudiTableDescriptor implements 
FormatTableDescriptor {
 
   @Override
   public Pair<List<OptimizingProcessInfo>, Integer> getOptimizingProcessesInfo(
-      AmoroTable<?> amoroTable, String type, ProcessStatus status, int limit, 
int offset) {
+      AmoroTable<?> amoroTable,
+      String type,
+      String processCategory,
+      ProcessStatus status,
+      int limit,
+      int offset) {
     HoodieJavaTable hoodieTable = (HoodieJavaTable) amoroTable.originalTable();
     HoodieDefaultTimeline timeline = new 
HoodieActiveTimeline(hoodieTable.getMetaClient(), false);
     List<HoodieInstant> instants = timeline.getInstants();
@@ -381,12 +389,18 @@ public class HudiTableDescriptor implements 
FormatTableDescriptor {
                 })
             .filter(Objects::nonNull)
             .collect(Collectors.toList());
+    List<String> categoryTypes = getProcessTypesByCategory(processCategory);
     infos =
         infos.stream()
             .filter(
                 i ->
                     StringUtils.isNullOrEmpty(type) || 
type.equalsIgnoreCase(i.getOptimizingType()))
             .filter(i -> status == null || status == i.getStatus())
+            .filter(
+                i ->
+                    i.getOptimizingType() != null
+                        && categoryTypes.stream()
+                            .anyMatch(t -> 
t.equalsIgnoreCase(i.getOptimizingType())))
             .collect(Collectors.toList());
     int total = infos.size();
     infos = 
infos.stream().skip(offset).limit(limit).collect(Collectors.toList());
@@ -401,6 +415,15 @@ public class HudiTableDescriptor implements 
FormatTableDescriptor {
     return types;
   }
 
+  @Override
+  public List<String> getProcessTypesByCategory(String processCategory) {
+    if 
(ProcessCategory.OPTIMIZING.getName().equalsIgnoreCase(processCategory)) {
+      return OPTIMIZING_TYPES;
+    }
+
+    return Collections.emptyList();
+  }
+
   protected OptimizingProcessInfo getOptimizingInfo(
       String instantTimestamp, Map<String, HoodieInstant> instantMap, 
HoodieTimeline timeline)
       throws IOException {
diff --git 
a/amoro-format-paimon/src/main/java/org/apache/amoro/formats/paimon/PaimonTableDescriptor.java
 
b/amoro-format-paimon/src/main/java/org/apache/amoro/formats/paimon/PaimonTableDescriptor.java
index 566da688a..7263dc8a5 100644
--- 
a/amoro-format-paimon/src/main/java/org/apache/amoro/formats/paimon/PaimonTableDescriptor.java
+++ 
b/amoro-format-paimon/src/main/java/org/apache/amoro/formats/paimon/PaimonTableDescriptor.java
@@ -41,6 +41,7 @@ import 
org.apache.amoro.table.descriptor.OptimizingProcessInfo;
 import org.apache.amoro.table.descriptor.OptimizingTaskInfo;
 import org.apache.amoro.table.descriptor.PartitionBaseInfo;
 import org.apache.amoro.table.descriptor.PartitionFileBaseInfo;
+import org.apache.amoro.table.descriptor.ProcessCategory;
 import org.apache.amoro.table.descriptor.ServerTableMeta;
 import org.apache.amoro.table.descriptor.TableSummary;
 import org.apache.amoro.table.descriptor.TagOrBranchInfo;
@@ -89,6 +90,9 @@ import java.util.stream.Collectors;
 public class PaimonTableDescriptor implements FormatTableDescriptor {
 
   public static final String PAIMON_MAIN_BRANCH_NAME = "main";
+  private static final String FULL_TYPE = "FULL";
+  private static final String MINOR_TYPE = "MINOR";
+  private static final List<String> OPTIMIZING_TYPES = 
Arrays.asList(FULL_TYPE, MINOR_TYPE);
 
   private ExecutorService executor;
 
@@ -372,7 +376,12 @@ public class PaimonTableDescriptor implements 
FormatTableDescriptor {
 
   @Override
   public Pair<List<OptimizingProcessInfo>, Integer> getOptimizingProcessesInfo(
-      AmoroTable<?> amoroTable, String type, ProcessStatus status, int limit, 
int offset) {
+      AmoroTable<?> amoroTable,
+      String type,
+      String processCategory,
+      ProcessStatus status,
+      int limit,
+      int offset) {
     // Temporary solution for Paimon. TODO: Get compaction info from Paimon 
compaction task
     List<OptimizingProcessInfo> processInfoList;
     TableIdentifier tableIdentifier = amoroTable.id();
@@ -428,9 +437,9 @@ public class PaimonTableDescriptor implements 
FormatTableDescriptor {
                       }
                     }
                     if (isPrimaryTable && hasMaxLevels) {
-                      optimizingProcessInfo.setOptimizingType("FULL");
+                      optimizingProcessInfo.setOptimizingType(FULL_TYPE);
                     } else {
-                      optimizingProcessInfo.setOptimizingType("MINOR");
+                      optimizingProcessInfo.setOptimizingType(MINOR_TYPE);
                     }
                     optimizingProcessInfo.setSuccessTasks(buckets.size());
                     optimizingProcessInfo.setTotalTasks(buckets.size());
@@ -445,10 +454,16 @@ public class PaimonTableDescriptor implements 
FormatTableDescriptor {
     } catch (IOException e) {
       throw new RuntimeException(e);
     }
+    List<String> categoryTypes = getProcessTypesByCategory(processCategory);
     processInfoList =
         processInfoList.stream()
             .filter(p -> StringUtils.isBlank(type) || 
type.equalsIgnoreCase(p.getOptimizingType()))
             .filter(p -> status == null || status == p.getStatus())
+            .filter(
+                p ->
+                    p.getOptimizingType() != null
+                        && categoryTypes.stream()
+                            .anyMatch(t -> 
t.equalsIgnoreCase(p.getOptimizingType())))
             .collect(Collectors.toList());
     int total = processInfoList.size();
     processInfoList =
@@ -459,11 +474,20 @@ public class PaimonTableDescriptor implements 
FormatTableDescriptor {
   @Override
   public Map<String, String> getTableOptimizingTypes(AmoroTable<?> amoroTable) 
{
     Map<String, String> types = Maps.newHashMap();
-    types.put("FULL", "full");
-    types.put("MINOR", "MINOR");
+    types.put(FULL_TYPE, "full");
+    types.put(MINOR_TYPE, "MINOR");
     return types;
   }
 
+  @Override
+  public List<String> getProcessTypesByCategory(String processCategory) {
+    if 
(ProcessCategory.OPTIMIZING.getName().equalsIgnoreCase(processCategory)) {
+      return OPTIMIZING_TYPES;
+    }
+
+    return Collections.emptyList();
+  }
+
   @Override
   public List<OptimizingTaskInfo> getOptimizingTaskInfos(
       AmoroTable<?> amoroTable, String processId) {
diff --git a/amoro-web/mock/modules/table.js b/amoro-web/mock/modules/table.js
index 372e81fd9..119cf7b3f 100644
--- a/amoro-web/mock/modules/table.js
+++ b/amoro-web/mock/modules/table.js
@@ -307,17 +307,32 @@ export default [
     }),
   },
   {
-    url: 
'/mock/api/ams/v1/tables/catalogs/test_catalog/dbs/db/tables/user/optimizing-types',
+    url: 
'/mock/api/ams/v1/tables/catalogs/test_catalog/dbs/db/tables/user/process-types',
     method: 'get',
-    response: () => ({
-      "message": "success",
-      "code": 200,
-      "result": {
-        "MINOR": "minor",
-        "MAJOR": "major",
-        "FULL": "full",
+    response: ({ query }) => {
+      const processCategory = query?.processCategory || 'OPTIMIZING'
+      const result = {
+        OPTIMIZING: {
+          'MINOR': 'minor',
+          'MAJOR': 'major',
+          'FULL': 'full',
+        },
+        CLEANUP: {
+          'EXPIRE-SNAPSHOTS': 'Expire Snapshots',
+          'CLEAN-ORPHAN-FILES': 'Clean Orphan Files',
+          'CLEAN-DANGLING-DELETE-FILES': 'Clean Dangling Delete Files',
+          'EXPIRE-DATA': 'Expire Data',
+        },
+        PROFILING: {
+          'AUTO-CREATE-TAGS': 'Auto Create Tags',
+        },
       }
-    }),
+      return {
+        'message': 'success',
+        'code': 200,
+        'result': result[processCategory] || result.OPTIMIZING,
+      }
+    },
   },
   {
     url: 
'/mock/api/ams/v1/tables/catalogs/test_catalog/dbs/db/tables/user/operations',
diff --git a/amoro-web/src/language/en.ts b/amoro-web/src/language/en.ts
index d28c05cfd..b0be90e2d 100644
--- a/amoro-web/src/language/en.ts
+++ b/amoro-web/src/language/en.ts
@@ -28,6 +28,8 @@ export default {
   catalog: 'Catalog',
   tables: 'Tables',
   optimizing: 'Optimizing',
+  cleanup: 'Cleanup',
+  profiling: 'Profiling',
   terminal: 'Terminal',
   settings: 'Settings',
   systemSetting: 'System Settings',
@@ -124,6 +126,9 @@ export default {
   resourceGroup: 'Resource Group',
   releaseOptModalTitle: 'Release this optimizer?',
   cancelOptimizingProcessOptModalTitle: 'Cancel the optimizing process of this 
table?',
+  cancelCleanupProcessOptModalTitle: 'Cancel the cleanup process of this 
table?',
+  cancelProfilingProcessOptModalTitle: 'Cancel the profiling process of this 
table?',
+  loadProcessTypesFailed: 'Failed to load process types',
   welcomeTip: 'Welcome to Amoro!',
   signIn: 'Sign in',
   username: 'Username',
diff --git a/amoro-web/src/language/zh.ts b/amoro-web/src/language/zh.ts
index 33087d9b1..cf20bcefc 100644
--- a/amoro-web/src/language/zh.ts
+++ b/amoro-web/src/language/zh.ts
@@ -28,6 +28,8 @@ export default {
   catalog: '目录',
   tables: '表',
   optimizing: '优化',
+  cleanup: '清理',
+  profiling: '剖析',
   terminal: '终端',
   settings: '设置',
   systemSetting: '系统设置',
@@ -124,6 +126,9 @@ export default {
   resourceGroup: '资源组',
   releaseOptModalTitle: '释放此优化器?',
   cancelOptimizingProcessOptModalTitle: '取消该表的优化过程?',
+  cancelCleanupProcessOptModalTitle: '取消该表的清理过程?',
+  cancelProfilingProcessOptModalTitle: '取消该表的剖析过程?',
+  loadProcessTypesFailed: '加载流程类型失败',
   welcomeTip: '欢迎访问 Amoro!',
   signIn: '登入',
   username: '用户名',
diff --git a/amoro-web/src/services/table.service.ts 
b/amoro-web/src/services/table.service.ts
index 08f046cca..0ff5ba928 100644
--- a/amoro-web/src/services/table.service.ts
+++ b/amoro-web/src/services/table.service.ts
@@ -158,27 +158,29 @@ export function getOptimizingProcesses(
     db: string
     table: string
     type: string
+    processCategory?: string
     status: string
     page: number
     pageSize: number
     token?: string
   },
 ) {
-  const { catalog, db, table, type, status, page, pageSize, token } = params
-  return 
request.get(`api/ams/v1/tables/catalogs/${catalog}/dbs/${db}/tables/${table}/optimizing-processes`,
 { params: { page, pageSize, token, type, status } })
+  const { catalog, db, table, type, processCategory, status, page, pageSize, 
token } = params
+  return 
request.get(`api/ams/v1/tables/catalogs/${catalog}/dbs/${db}/tables/${table}/optimizing-processes`,
 { params: { page, pageSize, token, type, processCategory, status } })
 }
 
-// get optimizing process types
-export function getTableOptimizingTypes(
+// get process types by category
+export function getTableProcessTypes(
   params: {
     catalog: string
     db: string
     table: string
+    processCategory: string
     token?: string
   },
 ) {
-  const { catalog, db, table, token } = params
-  return 
request.get(`api/ams/v1/tables/catalogs/${catalog}/dbs/${db}/tables/${table}/optimizing-types`,
 { params: { token } })
+  const { catalog, db, table, processCategory, token } = params
+  return 
request.get(`api/ams/v1/tables/catalogs/${catalog}/dbs/${db}/tables/${table}/process-types`,
 { params: { processCategory, token } })
 }
 
 // get optimizing tasks
diff --git a/amoro-web/src/views/tables/components/Cleanup.vue 
b/amoro-web/src/views/tables/components/Cleanup.vue
new file mode 100644
index 000000000..4bb29700d
--- /dev/null
+++ b/amoro-web/src/views/tables/components/Cleanup.vue
@@ -0,0 +1,26 @@
+<!--
+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.
+/ -->
+
+<script lang="ts" setup>
+import Optimizing from './Optimizing.vue'
+</script>
+
+<template>
+  <Optimizing process-category="CLEANUP" 
cancel-modal-title-key="cancelCleanupProcessOptModalTitle" />
+</template>
diff --git a/amoro-web/src/views/tables/components/Optimizing.vue 
b/amoro-web/src/views/tables/components/Optimizing.vue
index c7ccc0b50..8aa424456 100644
--- a/amoro-web/src/views/tables/components/Optimizing.vue
+++ b/amoro-web/src/views/tables/components/Optimizing.vue
@@ -20,13 +20,21 @@ limitations under the License.
 import { onMounted, reactive, ref, shallowReactive } from 'vue'
 import { useI18n } from 'vue-i18n'
 import { useRoute } from 'vue-router'
-import { Modal } from 'ant-design-vue'
+import { Modal, message } from 'ant-design-vue'
 import { usePagination } from '@/hooks/usePagination'
 import type { BreadcrumbOptimizingItem, IColumns, ILableAndValue } from 
'@/types/common.type'
-import { cancelOptimizingProcess, getOptimizingProcesses, 
getTableOptimizingTypes, getTasksByOptimizingProcessId } from 
'@/services/table.service'
+import { cancelOptimizingProcess, getOptimizingProcesses, 
getTableProcessTypes, getTasksByOptimizingProcessId } from 
'@/services/table.service'
 import { bytesToSize, dateFormat, formatMS2Time } from '@/utils/index'
 import { canManageTable } from '@/utils/permission'
 
+const props = withDefaults(defineProps<{
+  processCategory?: string
+  cancelModalTitleKey?: string
+}>(), {
+  processCategory: 'OPTIMIZING',
+  cancelModalTitleKey: 'cancelOptimizingProcessOptModalTitle',
+})
+
 const hasBreadcrumb = ref<boolean>(false)
 
 const statusMap = {
@@ -95,12 +103,18 @@ const statusType = ref<ILableAndValue>()
 const statusTypeList = ref<ILableAndValue[]>([])
 
 async function getQueryDataDictList() {
-  const tableProcessTypes = await getTableOptimizingTypes({ ...sourceData })
-  const typesList = Object.entries(tableProcessTypes).map(([typeName, 
displayName]) => ({ label: displayName as string, value: typeName }))
   const status = Object.entries(statusMap).map(([key, value]) => ({ label: 
value.title, value: key }))
-
-  actionTypeList.value = typesList
   statusTypeList.value = status
+
+  try {
+    const rawTypes = await getTableProcessTypes({ ...sourceData, 
processCategory: props.processCategory })
+    actionTypeList.value = Object.entries(rawTypes).map(([typeName, 
displayName]) => ({ label: displayName as string, value: typeName }))
+  }
+  catch (error) {
+    console.error('Failed to load process types:', error)
+    message.error(t('loadProcessTypesFailed'))
+    actionTypeList.value = []
+  }
 }
 
 async function refreshOptimizingProcesses() {
@@ -109,14 +123,15 @@ async function refreshOptimizingProcesses() {
     dataSource.length = 0
     const result = await getOptimizingProcesses({
       ...sourceData,
-      type: actionType.value || '',
-      status: statusType.value || '',
+      type: String(actionType.value || ''),
+      processCategory: props.processCategory,
+      status: String(statusType.value || ''),
       page: pagination.current,
       pageSize: pagination.pageSize,
-    } as any)
+    })
     const { list, total = 0 } = result
     pagination.total = total
-    dataSource.push(...[...list || []].map((item) => {
+    dataSource.push(...[...list || []].map((item: any) => {
       const { inputFiles = {}, outputFiles = {} } = item
       return {
         ...item,
@@ -142,7 +157,7 @@ async function refreshOptimizingProcesses() {
 
 async function cancel() {
   Modal.confirm({
-    title: t('cancelOptimizingProcessOptModalTitle'),
+    title: t(props.cancelModalTitleKey),
     onOk: async () => {
       try {
         loading.value = true
@@ -421,10 +436,6 @@ onMounted(() => {
     padding: 4px 16px !important;
   }
 
-  :deep(.ant-table-thead > tr > th) {
-    padding: 4px 16px !important;
-  }
-
   :deep(.ant-table-row-expand-icon) {
     border-radius: 0 !important;
   }
diff --git a/amoro-web/src/views/tables/components/Profiling.vue 
b/amoro-web/src/views/tables/components/Profiling.vue
new file mode 100644
index 000000000..704b55b3c
--- /dev/null
+++ b/amoro-web/src/views/tables/components/Profiling.vue
@@ -0,0 +1,26 @@
+<!--
+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.
+/ -->
+
+<script lang="ts" setup>
+import Optimizing from './Optimizing.vue'
+</script>
+
+<template>
+  <Optimizing process-category="PROFILING" 
cancel-modal-title-key="cancelProfilingProcessOptModalTitle" />
+</template>
diff --git a/amoro-web/src/views/tables/index.vue 
b/amoro-web/src/views/tables/index.vue
index f3704dbe2..b3413d982 100644
--- a/amoro-web/src/views/tables/index.vue
+++ b/amoro-web/src/views/tables/index.vue
@@ -24,6 +24,8 @@ import UFiles from './components/Files.vue'
 import UOperations from './components/Operations.vue'
 import USnapshots from './components/Snapshots.vue'
 import UOptimizing from './components/Optimizing.vue'
+import UCleanup from './components/Cleanup.vue'
+import UProfiling from './components/Profiling.vue'
 import UHealthScore from './components/HealthScoreDetails.vue'
 import TableExplorer from './components/TableExplorer.vue'
 import useStore from '@/store/index'
@@ -38,6 +40,8 @@ export default defineComponent({
     UOperations,
     USnapshots,
     UOptimizing,
+    UCleanup,
+    UProfiling,
     UHealthScore,
     TableExplorer,
   },
@@ -106,6 +110,8 @@ export default defineComponent({
     const tabConfigs = shallowReactive([
       { key: 'Snapshots', label: 'snapshots' },
       { key: 'Optimizing', label: 'optimizing' },
+      { key: 'Cleanup', label: 'cleanup' },
+      { key: 'Profiling', label: 'profiling' },
       { key: 'Operations', label: 'operations' },
     ])
 

Reply via email to