mirror of
https://github.com/apache/superset.git
synced 2024-09-19 20:19:37 -04:00
18658f45be
* Initial commit of new filters badge. * refactor applied/rejected filters code * finished filter indicators * filter badge tested * unnecessary imports * formatting and types * fixes * license * code quality tweaks * state management for showing focused filter scope * clean up filter key extraction code * remove unnecessary styles * temp css to demonstrate highlighting * fix focused filter logic * no more color badges * new toys for highlighting dash components (#11144) * tweak style for the filter chart when filter is focused * style: Filters p0 css2 (#11151) * nixing background tweak * src paths * another quick theme color * src paths, adjusting pill icon color, changing icons, showing applied/busted counts * linting stuff * fixing and tweaking tests * show filter indicator when filters are not active * chart title bar cleanup * open the right panel when popover opens * unused import * fix EditableTitle tests * margin on dashboard header * show the chart dropdown menu * fix blur filter breaking dropdowns * style tweak - no pointer events when irrelevant charts are blurred * fix box shadow on filter highlight * it's an array * attempt fixing e2e * style: filters p0 icon churn (#11215) * new filters icon * icon styling * bigger icons in list views * better sizing of table actions and favStars * more icon sizing... * fixing more button size jankiness * linting * Filters performance (#11255) * fixing time filter "ok" button * making unset filter menu collapsible * sort alphabetically * fix highlighting when removing items * try a flex layout (for browser render perf) * more specific transitioning * temp: comment out some code as a test * temp: comment out more code * temp: remove possibly expensive computations from ChartHolder * Revert "temp: comment out some code as a test" This reverts commit309b880e90
. * Revert "temp: comment out more code" This reverts commit64c88b2cba
. * Revert "temp: remove possibly expensive computations from ChartHolder" This reverts commit37ce0214f0
. * experiment: upgrade react-select to v3 * Revert "experiment: upgrade react-select to v3" This reverts commitc3972ba486
. * fix the damn problem * remove code used for testing purposes * awful hack to avoid adding a class to a container * approaching infinity... and not beyond! * fix ref forwarding * add theme to tests as necessary * fix(extra-filters): add logic for identifying applied extra filters (#11325) * fix: use dashboard id for stable cache key (#11293) * fix: button translations missing (#11187) * button translations missing * blank space before text * feat: update time_compare description and choices (#11294) * feat: update time_compare description and choices * Update sections.jsx * fix(extra-filters): add logic for identifying applied extra filters * lint Co-authored-by: Jesse Yang <jesse.yang@airbnb.com> Co-authored-by: rubenSastre <ruben.sastre@decathlon.com> Co-authored-by: Erik Ritter <erik.ritter@airbnb.com> * address design feedback * slight tweak to panel logic, keep panels open that user has opened * rearrange code to be more graceful * fix: bump superset-ui/core (#11385) * use is_dttm instead of is_temporal * types, names * only show unset filter panel if there are unset filters * fix highlighting the filter control * fix filterbox layout * translations * fix cypress * actually add the test attribute * Update superset-frontend/src/dashboard/components/DashboardBuilder.jsx Co-authored-by: Evan Rusackas <evan@preset.io> * Update superset-frontend/src/dashboard/components/DashboardBuilder.jsx Co-authored-by: Evan Rusackas <evan@preset.io> * formatting * add link comment to hack * Update superset-frontend/src/dashboard/components/gridComponents/ChartHolder.jsx Co-authored-by: Evan Rusackas <evan@preset.io> * stop importing lodash * Update superset-frontend/src/dashboard/components/gridComponents/ChartHolder.jsx Co-authored-by: Evan Rusackas <evan@preset.io> * Update superset-frontend/src/dashboard/components/FiltersBadge/Styles.tsx Co-authored-by: Evan Rusackas <evan@preset.io> * Update superset-frontend/src/dashboard/components/FiltersBadge/Styles.tsx Co-authored-by: Evan Rusackas <evan@preset.io> * Update superset-frontend/src/dashboard/components/FiltersBadge/Styles.tsx Co-authored-by: Evan Rusackas <evan@preset.io> * Update superset-frontend/src/dashboard/components/FiltersBadge/Styles.tsx Co-authored-by: Evan Rusackas <evan@preset.io> * skip broken test * Update superset-frontend/src/dashboard/components/FiltersBadge/Styles.tsx Co-authored-by: Evan Rusackas <evan@preset.io> * Update superset-frontend/src/dashboard/components/FiltersBadge/Styles.tsx Co-authored-by: Evan Rusackas <evan@preset.io> * adjust colors of titles * linting * no indicators when chart is loading * support all time fields * fix lock file Co-authored-by: Natalie Ruhe <natalie@preset.io> Co-authored-by: Evan Rusackas <evan@preset.io> Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com> Co-authored-by: Jesse Yang <jesse.yang@airbnb.com> Co-authored-by: rubenSastre <ruben.sastre@decathlon.com> Co-authored-by: Erik Ritter <erik.ritter@airbnb.com> Co-authored-by: Ville Brofeldt <ville.v.brofeldt@gmail.com>
213 lines
5.8 KiB
TypeScript
213 lines
5.8 KiB
TypeScript
/**
|
|
* 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, { useEffect, useState, useRef } from 'react';
|
|
import cx from 'classnames';
|
|
import { t } from '@superset-ui/core';
|
|
import TooltipWrapper from './TooltipWrapper';
|
|
|
|
interface EditableTitleProps {
|
|
canEdit?: boolean;
|
|
emptyText?: string;
|
|
extraClasses?: Array<string> | string;
|
|
multiLine?: boolean;
|
|
noPermitTooltip?: string;
|
|
onSaveTitle: (arg0: string) => {};
|
|
showTooltip?: boolean;
|
|
style?: object;
|
|
title: string;
|
|
}
|
|
|
|
export default function EditableTitle({
|
|
canEdit = false,
|
|
emptyText,
|
|
extraClasses,
|
|
multiLine = false,
|
|
noPermitTooltip,
|
|
onSaveTitle,
|
|
showTooltip = true,
|
|
style,
|
|
title,
|
|
}: EditableTitleProps) {
|
|
const [isEditing, setIsEditing] = useState(false);
|
|
const [currentTitle, setCurrentTitle] = useState(title);
|
|
const [lastTitle, setLastTitle] = useState(title);
|
|
const [
|
|
contentBoundingRect,
|
|
setContentBoundingRect,
|
|
] = useState<DOMRect | null>(null);
|
|
// Used so we can access the DOM element if a user clicks on this component.
|
|
|
|
const contentRef = useRef<any | HTMLInputElement | HTMLTextAreaElement>();
|
|
|
|
useEffect(() => {
|
|
if (title !== currentTitle) {
|
|
setLastTitle(currentTitle);
|
|
setCurrentTitle(title);
|
|
}
|
|
}, [title]);
|
|
|
|
function handleClick() {
|
|
if (!canEdit || isEditing) {
|
|
return;
|
|
}
|
|
|
|
// For multi-line values, save the actual rendered size of the displayed text.
|
|
// Later, if a textarea is constructed for editing the value, we'll need this.
|
|
const contentBounding = contentRef.current
|
|
? contentRef.current.getBoundingClientRect()
|
|
: null;
|
|
setIsEditing(true);
|
|
setContentBoundingRect(contentBounding);
|
|
}
|
|
|
|
function handleBlur() {
|
|
const formattedTitle = currentTitle.trim();
|
|
|
|
if (!canEdit) {
|
|
return;
|
|
}
|
|
|
|
setIsEditing(false);
|
|
|
|
if (!formattedTitle.length) {
|
|
setCurrentTitle(lastTitle);
|
|
return;
|
|
}
|
|
|
|
if (lastTitle !== formattedTitle) {
|
|
setLastTitle(formattedTitle);
|
|
}
|
|
|
|
if (title !== formattedTitle) {
|
|
onSaveTitle(formattedTitle);
|
|
}
|
|
}
|
|
|
|
// this entire method exists to support using EditableTitle as the title of a
|
|
// react-bootstrap Tab, as a workaround for this line in react-bootstrap https://goo.gl/ZVLmv4
|
|
//
|
|
// tl;dr when a Tab EditableTitle is being edited, typically the Tab it's within has been
|
|
// clicked and is focused/active. for accessibility, when focused the Tab <a /> intercepts
|
|
// the ' ' key (among others, including all arrows) and onChange() doesn't fire. somehow
|
|
// keydown is still called so we can detect this and manually add a ' ' to the current title
|
|
function handleKeyDown(event: any) {
|
|
if (event.key === ' ') {
|
|
event.stopPropagation();
|
|
}
|
|
}
|
|
|
|
function handleChange(ev: any) {
|
|
if (!canEdit) {
|
|
return;
|
|
}
|
|
setCurrentTitle(ev.target.value);
|
|
}
|
|
|
|
function handleKeyPress(ev: any) {
|
|
if (ev.key === 'Enter') {
|
|
ev.preventDefault();
|
|
handleBlur();
|
|
}
|
|
}
|
|
|
|
let value: string | undefined;
|
|
if (currentTitle) {
|
|
value = currentTitle;
|
|
} else if (!isEditing) {
|
|
value = emptyText;
|
|
}
|
|
|
|
// Construct an inline style based on previously-saved height of the rendered label. Only
|
|
// used in multi-line contexts.
|
|
const editStyle =
|
|
isEditing && contentBoundingRect
|
|
? { height: `${contentBoundingRect.height}px` }
|
|
: undefined;
|
|
|
|
// Create a textarea when we're editing a multi-line value, otherwise create an input (which may
|
|
// be text or a button).
|
|
let titleComponent =
|
|
multiLine && isEditing ? (
|
|
<textarea
|
|
data-test="editable-title-input"
|
|
ref={contentRef}
|
|
required
|
|
value={value}
|
|
className={!title ? 'text-muted' : undefined}
|
|
onKeyDown={handleKeyDown}
|
|
onChange={handleChange}
|
|
onBlur={handleBlur}
|
|
onClick={handleClick}
|
|
onKeyPress={handleKeyPress}
|
|
style={editStyle}
|
|
/>
|
|
) : (
|
|
<input
|
|
data-test="editable-title-input"
|
|
ref={contentRef}
|
|
required
|
|
type={isEditing ? 'text' : 'button'}
|
|
value={value}
|
|
className={!title ? 'text-muted' : undefined}
|
|
onKeyDown={handleKeyDown}
|
|
onChange={handleChange}
|
|
onBlur={handleBlur}
|
|
onClick={handleClick}
|
|
onKeyPress={handleKeyPress}
|
|
/>
|
|
);
|
|
if (showTooltip && !isEditing) {
|
|
titleComponent = (
|
|
<TooltipWrapper
|
|
label="title"
|
|
tooltip={
|
|
canEdit
|
|
? t('click to edit')
|
|
: noPermitTooltip ||
|
|
t("You don't have the rights to alter this title.")
|
|
}
|
|
>
|
|
{titleComponent}
|
|
</TooltipWrapper>
|
|
);
|
|
}
|
|
if (!canEdit) {
|
|
// don't actually want an input in this case
|
|
titleComponent = (
|
|
<span data-test="editable-title-input" title={value}>
|
|
{value}
|
|
</span>
|
|
);
|
|
}
|
|
return (
|
|
<span
|
|
data-test="editable-title"
|
|
className={cx(
|
|
'editable-title',
|
|
extraClasses,
|
|
canEdit && 'editable-title--editable',
|
|
isEditing && 'editable-title--editing',
|
|
)}
|
|
style={style}
|
|
>
|
|
{titleComponent}
|
|
</span>
|
|
);
|
|
}
|