refactor(monorepo): move superset-ui to superset(stage 2) (#17552)

This commit is contained in:
Yongjie Zhao
2021-11-30 08:29:57 +08:00
committed by GitHub
parent bfba4f1689
commit 3c41ff68a4
1315 changed files with 27755 additions and 15167 deletions

View File

@@ -0,0 +1,82 @@
/**
* 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, { ComponentType, ChangeEventHandler } from 'react';
import { Row, FilterValue } from 'react-table';
import useAsyncState from '../utils/useAsyncState';
export interface SearchInputProps {
count: number;
value: string;
onChange: ChangeEventHandler<HTMLInputElement>;
}
export interface GlobalFilterProps<D extends object> {
preGlobalFilteredRows: Row<D>[];
// filter value cannot be `undefined` otherwise React will report component
// control type undefined error
filterValue: string;
setGlobalFilter: (filterValue: FilterValue) => void;
searchInput?: ComponentType<SearchInputProps>;
}
function DefaultSearchInput({ count, value, onChange }: SearchInputProps) {
return (
<span className="dt-global-filter">
Search{' '}
<input
className="form-control input-sm"
placeholder={`${count} records...`}
value={value}
onChange={onChange}
/>
</span>
);
}
export default (React.memo as <T>(fn: T) => T)(function GlobalFilter<
D extends object,
>({
preGlobalFilteredRows,
filterValue = '',
searchInput,
setGlobalFilter,
}: GlobalFilterProps<D>) {
const count = preGlobalFilteredRows.length;
const [value, setValue] = useAsyncState(
filterValue,
(newValue: string) => {
setGlobalFilter(newValue || undefined);
},
200,
);
const SearchInput = searchInput || DefaultSearchInput;
return (
<SearchInput
count={count}
value={value}
onChange={e => {
const target = e.target as HTMLInputElement;
e.preventDefault();
setValue(target.value);
}}
/>
);
});

View File

@@ -0,0 +1,121 @@
/**
* 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, { CSSProperties } from 'react';
export interface PaginationProps {
pageCount: number; // number of pages
currentPage?: number; // index of current page, zero-based
maxPageItemCount?: number;
ellipsis?: string; // content for ellipsis item
onPageChange: (page: number) => void; // `page` is zero-based
style?: CSSProperties;
}
// first, ..., prev, current, next, ..., last
const MINIMAL_PAGE_ITEM_COUNT = 7;
/**
* Generate numeric page items around current page.
* - Always include first and last page
* - Add ellipsis if needed
*/
export function generatePageItems(
total: number,
current: number,
width: number,
) {
if (width < MINIMAL_PAGE_ITEM_COUNT) {
throw new Error(
`Must allow at least ${MINIMAL_PAGE_ITEM_COUNT} page items`,
);
}
if (width % 2 === 0) {
throw new Error(`Must allow odd number of page items`);
}
if (total < width) {
return [...new Array(total).keys()];
}
const left = Math.max(
0,
Math.min(total - width, current - Math.floor(width / 2)),
);
const items: (string | number)[] = new Array(width);
for (let i = 0; i < width; i += 1) {
items[i] = i + left;
}
// replace non-ending items with placeholders
if (items[0] > 0) {
items[0] = 0;
items[1] = 'prev-more';
}
if (items[items.length - 1] < total - 1) {
items[items.length - 1] = total - 1;
items[items.length - 2] = 'next-more';
}
return items;
}
export default React.memo(
React.forwardRef(function Pagination(
{
style,
pageCount,
currentPage = 0,
maxPageItemCount = 9,
onPageChange,
}: PaginationProps,
ref: React.Ref<HTMLDivElement>,
) {
const pageItems = generatePageItems(
pageCount,
currentPage,
maxPageItemCount,
);
return (
<div ref={ref} className="dt-pagination" style={style}>
<ul className="pagination pagination-sm">
{pageItems.map(item =>
typeof item === 'number' ? (
// actual page number
<li
key={item}
className={currentPage === item ? 'active' : undefined}
>
<a
href={`#page-${item}`}
role="button"
onClick={e => {
e.preventDefault();
onPageChange(item);
}}
>
{item + 1}
</a>
</li>
) : (
<li key={item} className="dt-pagination-ellipsis">
<span></span>
</li>
),
)}
</ul>
</div>
);
}),
);

View File

@@ -0,0 +1,99 @@
/**
* 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 from 'react';
import { formatSelectOptions } from '@superset-ui/chart-controls';
export type SizeOption = [number, string];
export interface SelectPageSizeRendererProps {
current: number;
options: SizeOption[];
onChange: SelectPageSizeProps['onChange'];
}
function DefaultSelectRenderer({
current,
options,
onChange,
}: SelectPageSizeRendererProps) {
return (
<span className="dt-select-page-size form-inline">
Show{' '}
<select
className="form-control input-sm"
value={current}
onBlur={() => {}}
onChange={e => {
onChange(Number((e.target as HTMLSelectElement).value));
}}
>
{options.map(option => {
const [size, text] = Array.isArray(option)
? option
: [option, option];
return (
<option key={size} value={size}>
{text}
</option>
);
})}
</select>{' '}
entries
</span>
);
}
export interface SelectPageSizeProps extends SelectPageSizeRendererProps {
total?: number;
selectRenderer?: typeof DefaultSelectRenderer;
onChange: (pageSize: number) => void;
}
function getOptionValue(x: SizeOption) {
return Array.isArray(x) ? x[0] : x;
}
export default React.memo(function SelectPageSize({
total,
options: sizeOptions,
current: currentSize,
selectRenderer,
onChange,
}: SelectPageSizeProps) {
const sizeOptionValues = sizeOptions.map(getOptionValue);
let options = [...sizeOptions];
// insert current size to list
if (
currentSize !== undefined &&
(currentSize !== total || !sizeOptionValues.includes(0)) &&
!sizeOptionValues.includes(currentSize)
) {
options = [...sizeOptions];
options.splice(
sizeOptionValues.findIndex(x => x > currentSize),
0,
formatSelectOptions([currentSize])[0],
);
}
const current = currentSize === undefined ? sizeOptionValues[0] : currentSize;
const SelectRenderer = selectRenderer || DefaultSelectRenderer;
return (
<SelectRenderer current={current} options={options} onChange={onChange} />
);
});