Superset二次开发之源码DependencyList.tsx 分析

news2024/11/18 15:49:43

功能点

路径

superset-frontend\src\dashboard\components\nativeFilters\FiltersConfigModal\FiltersConfigForm\DependencyList.tsx

/**
 * 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 React, { useState } from 'react';
import { styled, t } from '@superset-ui/core';
import Icons from 'src/components/Icons';
import { Select } from 'src/components';
import { CollapsibleControl } from './CollapsibleControl';
import { INPUT_WIDTH } from './constants';
 
interface DependencyListProps {
  availableFilters: {
    label: string;
    value: string;
    type: string | undefined;
  }[];
  dependencies: string[];
  onDependenciesChange: (dependencies: string[]) => void;
  getDependencySuggestion: () => string;
  children?: JSX.Element;
}
 
const MainPanel = styled.div`
  display: flex;
  flex-direction: column;
`;
 
const AddFilter = styled.div`
  ${({ theme }) => `
    display: inline-flex;
    flex-direction: row;
    align-items: center;
    cursor: pointer;
    color: ${theme.colors.primary.base};
    &:hover {
      color: ${theme.colors.primary.dark1};
    }
  `}
`;
 
const DeleteFilter = styled(Icons.Trash)`
  ${({ theme }) => `
    cursor: pointer;
    margin-left: ${theme.gridUnit * 2}px;
    color: ${theme.colors.grayscale.base};
    &:hover {
      color: ${theme.colors.grayscale.dark1};
    }
  `}
`;
 
const RowPanel = styled.div`
  ${({ theme }) => `
    display: flex;
    flex-direction: row;
    align-items: center;
    margin-bottom: ${theme.gridUnit}px;
 
    & > div {
      width: ${INPUT_WIDTH}px;
    }
  `}
`;
 
const Label = styled.div`
  text-transform: uppercase;
  font-size: ${({ theme }) => theme.typography.sizes.s}px;
  color: ${({ theme }) => theme.colors.grayscale.base};
  margin-bottom: ${({ theme }) => theme.gridUnit}px;
`;
 
const Row = ({
  availableFilters,
  selection,
  onChange,
  onDelete,
}: {
  availableFilters: { label: string; value: string }[];
  selection: string;
  onChange: (id: string, value: string) => void;
  onDelete: (id: string) => void;
}) => {
  let value = availableFilters.find(e => e.value === selection);
  let options = availableFilters;
  if (!value) {
    value = { label: t('(deleted or invalid type)'), value: selection };
    options = [value, ...options];
  }
  return (
    <RowPanel>
      <Select
        ariaLabel={t('Limit type')}
        labelInValue
        options={options}
        onChange={option =>
          onChange(selection, (option as { value: string }).value)
        }
        value={value}
      />
      <DeleteFilter iconSize="xl" onClick={() => onDelete(selection)} />
    </RowPanel>
  );
};
 
const List = ({
  availableFilters = [],
  dependencies = [],
  onDependenciesChange,
}: DependencyListProps) => {
  const [rows, setRows] = useState<string[]>(dependencies);
 
  const updateRows = (newRows: string[]) => {
    setRows(newRows);
    onDependenciesChange(newRows);
  };
 
  const onAdd = () => {
    const filter = availableFilters.find(
      availableFilter => !rows.includes(availableFilter.value),
    );
    if (filter) {
      const newRows = [...rows];
      newRows.push(filter.value);
      updateRows(newRows);
    }
  };
 
  const onChange = (id: string, value: string) => {
    const indexOf = rows.findIndex(row => row === id);
    const newRows = [...rows];
    newRows[indexOf] = value;
    updateRows(newRows);
  };
 
  const onDelete = (id: string) => {
    const newRows = [...rows];
    newRows.splice(rows.indexOf(id), 1);
    updateRows(newRows);
  };
 
  if (availableFilters.length === 0) {
    return <span>{t('No available filters.')}</span>;
  }
 
  return (
    <>
      {rows.map(row => (
        <Row
          key={row}
          selection={row}
          availableFilters={availableFilters.filter(
            e => e.value === row || !rows.includes(e.value),
          )}
          onChange={onChange}
          onDelete={onDelete}
        />
      ))}
      {availableFilters.length > rows.length && (
        <AddFilter onClick={onAdd}>
          <Icons.PlusSmall />
          {t('Add filter')}
        </AddFilter>
      )}
    </>
  );
};
 
const DependencyList = ({
  availableFilters = [],
  dependencies = [],
  onDependenciesChange,
  getDependencySuggestion,
  children,
}: DependencyListProps) => {
  const hasAvailableFilters = availableFilters.length > 0;
  const hasDependencies = dependencies.length > 0;
 
  const onCheckChanged = (value: boolean) => {
    const newDependencies: string[] = [];
    if (value && !hasDependencies && hasAvailableFilters) {
      newDependencies.push(getDependencySuggestion());
    }
    onDependenciesChange(newDependencies);
  };
 
  return (
    <MainPanel>
      <CollapsibleControl
        title={t('Values are dependent on other filters')}
        initialValue={hasDependencies}
        onChange={onCheckChanged}
        tooltip={t(
          'Values selected in other filters will affect the filter options to only show relevant values',
        )}
      >
        {hasDependencies && <Label>{t('Values dependent on')}</Label>}
        <List
          availableFilters={availableFilters}
          dependencies={dependencies}
          onDependenciesChange={onDependenciesChange}
          getDependencySuggestion={getDependencySuggestion}
        />
        {children}
      </CollapsibleControl>
    </MainPanel>
  );
};
 
export default DependencyList;

组件功能:

  • 显示当前过滤器所依赖的其他过滤器列表
  • 允许用户添加或删除依赖关系
  • 提供依赖关系的可视化展示

 主要组件结构:

export const DependencyList: React.FC<DependencyListProps> = ({
  dependencies = [],
  onRemove,
  onAdd,
  getFilterTitle,
}) => {
  // ... 组件实现
}

这个组件接收依赖列表、删除和添加依赖的回调函数,以及获取过滤器标题的函数作为props。

依赖项渲染:

{dependencies.map(dependency => (
  <StyledItem key={dependency}>
    <StyledItemContent>
      <FilterValue>{getFilterTitle(dependency)}</FilterValue>
    </StyledItemContent>
    <StyledTrashIcon
      name="trash"
      onClick={() => onRemove(dependency)}
    />
  </StyledItem>
))}

这段代码遍历依赖列表,为每个依赖项渲染一个包含标题和删除图标的项目。

添加依赖功能

<StyledAdd onClick={onAdd}>
<PlusOutlined />
<span>{t('Add Dependent')}</span>
</StyledAdd>

这部分代码渲染了一个"添加依赖"按钮,点击时触发onAdd回调。

样式和布局

文件中使用了多个样式化组件(如StyledItem, StyledItemContent等)来定制组件的外观。

国际化

使用t函数进行文本国际化,支持多语言

类型定义

type DependencyListProps = {

    dependencies?: string[];
    onRemove: (id: string) => void;
    onAdd: () => void;
    getFilterTitle: (id: string) => string;
};

总结

这个DependencyList组件是实现"Values are dependent on other filters"逻辑的重要部分。它提供了一个用户界面,允许配置和管理过滤器之间的依赖关系。通过这个组件,用户可以直观地看到和修改过滤器的依赖结构,从而实现动态且相互关联的过滤系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2136468.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenCV结构分析与形状描述符(24)检测两个旋转矩形之间是否相交的一个函数rotatedRectangleIntersection()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 测两个旋转矩形之间是否存在交集。 如果存在交集&#xff0c;则还返回交集区域的顶点。 下面是一些交集配置的例子。斜线图案表示交集区域&#…

C++《类和对象》(下)

在之前类和对象&#xff08;中&#xff09;我们学习了类当中的6大默认成员函数&#xff0c;我们了解了6大成员函数的结构特征和特点以及在不同情况各个成员函数是如何调用的&#xff0c;那么接下来我们在本篇当中将继续学习之前在学习构造函数中未了解的初始化列表&#xff0c;…

MySql基础-单表操作

1. MYSQL概述 1.1 数据模型 关系型数据库 关系型数据库(RDBMS)&#xff1a;建立在关系模型基础上&#xff0c;由多张相互连接的二维表组成的数据库。 特点&#xff1a; 使用表存储数据&#xff0c;格式统一&#xff0c;便于维护 使用SQL语言操作&#xff0c;标准统一&…

高性能微服务架构:Spring Boot 集成 gRPC 实现用户与订单服务即时交互

gRPC 是一种由 Google 开发的高性能、开源的远程过程调用&#xff08;Remote Procedure Call, RPC&#xff09;框架。它允许在不同的计算机系统或进程之间进行通信&#xff0c;使得分布式系统和微服务架构中的服务之间能够轻松地相互调用方法。gRPC 基于 HTTP/2 协议&#xff0…

django-admin自定义功能按钮样式

位置在原来的django-admin 栏中的上方【会因为屏幕大小而变换位置】 <!-- 这里是不会替换掉旧的 添加按钮 &#xff0c;而是添加多一个按钮【点击Crawl Data】--> <!-- /home/luichun/lc/Pyfile/Pywebback/app/paqu/templates/admin/yourmodel_changelist.html -->…

基于k8s手动部署rabbitmq集群(Manually Deploying RabbitMQ Cluster Based on k8s)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

安全基础设施如何形成统一生态标准?OASA 硬件安全合作计划启动 | 2024 龙蜥大会

近日&#xff0c;2024 龙蜥操作系统大会&#xff08;OpenAnolis Conference&#xff09;在北京盛大召开。 与此同时&#xff0c;由龙蜥社区运营委员会副主席、龙腾计划生态负责人金美琴&#xff0c;阿里云智能集团高级技术专家张天佳&#xff0c;海光信息技术生态技术总监李伟&…

系统架构设计师教程 第5章 5.2需求工程 笔记

5.2 需求工程 ★★★★★ 软件需求是指用户对系统在功能、行为、性能、设计约束等方面的期望。 软件需求包括3个不同的层次&#xff1a;业务需求、用户需求和功能需求(也包括非功能需求)。 (1)业务需求 (business requirement) 反映了组织机构或客户对系统、产品高层次的目标…

用SpringBoot进行阿里云大模型接口调用同步方法和异步方法

同步效果就不展示了,这里展示更常用的异步,多轮异步流式效果展示如下: 结果内容组合 1、同步版本环境准备以及代码 需要开通阿里大模型服务,如果没有开通服务,单独的去生成 key 是无效的。 阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台 生成你需要的 key 1、…

PHP智慧家政同城服务家政系统小程序源码

智慧家政&#xff0c;同城服务新篇章 —— 探索家政系统的无限可能 开篇&#xff1a;走进智慧家政时代 在这个快节奏的生活中&#xff0c;每一分每一秒都显得尤为珍贵。当忙碌成为常态&#xff0c;如何让家成为真正的避风港&#xff1f;答案或许就藏在“智慧家政同城服务家政…

【JavaScript】数据结构之链表

什么是链表&#xff1f; 多个元素存储的列表链表中的元素在内存中不是顺序存储的&#xff0c;而是通过“next”指针联系在一起的&#xff0c;这个“next”可以自定义。JS中的原型链原理就是链表结构&#xff0c;是通过__proto__指针联系在一起的。 链表和数组的区别 数组是…

c++207 运算重载

调入 op #include<iostream> using namespace std;class Complex { public:int a;int b; public:Complex(int a 0, int b 0){this->a a;this->b b;}void printfCom(){cout << a << "" << b << "i" << endl…

Django视图:构建动态Web页面的核心技术

Django&#xff0c;作为一个强大的Python Web框架&#xff0c;提供了一套完整的工具来构建这些动态页面。在Django的架构中&#xff0c;视图&#xff08;Views&#xff09;是处理用户请求并生成响应的关键组件。本文将深入探讨Django视图的工作原理&#xff0c;以及如何使用它们…

科技与艺术完美融合的LED异形创意圆形(饼/盘)显示屏横空出世

随着LED技术的飞速发展&#xff0c;这款集科技与艺术于一体的异形创意圆形&#xff08;饼/盘&#xff09;显示屏&#xff0c;不仅以其独特的形态打破了传统显示屏的界限&#xff0c;更在视觉呈现上开启了前所未有的新篇章。它不再仅仅是信息传递的载体&#xff0c;而是成为了空…

外观模式详解:如何为复杂系统构建简洁的接口

&#x1f3af; 设计模式专栏&#xff0c;持续更新中 欢迎订阅&#xff1a;JAVA实现设计模式 &#x1f6e0;️ 希望小伙伴们一键三连&#xff0c;有问题私信都会回复&#xff0c;或者在评论区直接发言 外观模式 外观模式&#xff08;Facade Pattern&#xff09;为子系统中的一组…

AI重塑视觉体验:将图像与视频转化为逼真可编辑的3D虚拟场景

在这个数字化飞速发展的时代&#xff0c;AI技术正以前所未有的方式重塑我们的视觉体验。特别是当AI能够轻松将普通的照片和视频转化为高度逼真、可交互的3D虚拟场景时&#xff0c;它不仅简化了3D内容创作的复杂性&#xff0c;还极大地拓宽了应用场景的边界。今天&#xff0c;我…

医学数据分析实训 项目二 数据预处理作业

文章目录 项目二 数据预处理一、实践目的二、实践平台三、实践内容任务一&#xff1a;合并数据集任务二&#xff1a;独热编码任务三&#xff1a;数据预处理任务四&#xff1a;针对“项目一 医学数据采集”中“3. 通过 UCI 机器学习库下载数据集”任务所下载的数据集进行预处理。…

如何判断硬盘是不是固态硬盘?介绍几种简单有效方法

随着科技的发展&#xff0c;固态硬盘&#xff08;SSD&#xff09;因其读写速度快、噪音小、抗震能力强等优点&#xff0c;逐渐取代了传统的机械硬盘&#xff08;HDD&#xff09;。然而&#xff0c;对于普通用户来说&#xff0c;如何判断自己的硬盘是否为固态硬盘可能是一个难题…

10分钟在网站上增加一个AI助手

只需 10 分钟&#xff0c;为您的网站添加一个 AI 助手&#xff0c;以便全天候&#xff08;7x24&#xff09;回应客户咨询&#xff0c;提升用户体验、增强业务竞争力。 方案概览 在网站中引入一个 AI 助手&#xff0c;只需 4 步&#xff1a; 创建大模型问答应用&#xff1a;我们…

prometheus监控k8s1.24以上版本pod实时数据指标

8s组件本身提供组件自身运行的监控指标以及容器相关的监控指标。通过cAdvisor 是一个开源的分析容器资源使用率和性能特性的代理工具&#xff0c;集成到 Kubelet中&#xff0c;当Kubelet启动时会同时启动cAdvisor&#xff0c;且一个cAdvisor只监控一个Node节点的信息。cAdvisor…