Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Migrate AlteredSliceTag to typescript #27030

Merged
merged 14 commits into from
Feb 13, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
* under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import { isEqual, isEmpty } from 'lodash';
import { styled, t } from '@superset-ui/core';
import { sanitizeFormData } from 'src/explore/exploreUtils/formData';
Expand All @@ -27,53 +26,84 @@
import ModalTrigger from '../ModalTrigger';
import TableView from '../TableView';

const propTypes = {
origFormData: PropTypes.object.isRequired,
currentFormData: PropTypes.object.isRequired,
};
// Define interfaces for props and state
interface FormData {
[key: string]: any; // Use a more specific type if possible for your form data
EnxDev marked this conversation as resolved.
Show resolved Hide resolved
}

interface AlteredSliceTagProps {
origFormData: FormData;
currentFormData: FormData;
}

interface ControlMap {
[key: string]: {
label?: string;
type?: string;
};
}

interface Diff {
before: any; // Specify a more precise type if possible
after: any; // Specify a more precise type if possible
EnxDev marked this conversation as resolved.
Show resolved Hide resolved
}

interface Row {
control: string;
before: string;
after: string;
}

interface AlteredSliceTagState {
rows: Row[];
hasDiffs: boolean;
controlsMap: ControlMap;
}

const StyledLabel = styled.span`
${({ theme }) => `
font-size: ${theme.typography.sizes.s}px;
color: ${theme.colors.grayscale.dark1};
background-color: ${theme.colors.alert.base};

&: hover {
&:hover {
background-color: ${theme.colors.alert.dark1};
}
`}
`;

function alterForComparison(value) {
// Considering `[]`, `{}`, `null` and `undefined` as identical
// for this purpose
function alterForComparison(value: any): any {
EnxDev marked this conversation as resolved.
Show resolved Hide resolved
// Treat `null`, `undefined`, and empty strings as equivalent
if (value === undefined || value === null || value === '') {
return null;
}
if (typeof value === 'object') {
if (Array.isArray(value) && value.length === 0) {
return null;
}
const keys = Object.keys(value);
if (keys && keys.length === 0) {
return null;
}
// Treat empty arrays and objects as equivalent to null
if (Array.isArray(value) && value.length === 0) {
return null;
}
if (typeof value === 'object' && Object.keys(value).length === 0) {
return null;
}
// Return the value unchanged if it doesn't meet the above conditions
return value;
}

export default class AlteredSliceTag extends React.Component {
constructor(props) {
class AlteredSliceTag extends React.Component<
AlteredSliceTagProps,
AlteredSliceTagState
> {
constructor(props: AlteredSliceTagProps) {
super(props);
const diffs = this.getDiffs(props);
const controlsMap = getControlsForVizType(this.props.origFormData.viz_type);
const controlsMap: ControlMap = getControlsForVizType(
props.origFormData.viz_type,
);
const rows = this.getRowsFromDiffs(diffs, controlsMap);

this.state = { rows, hasDiffs: !isEmpty(diffs), controlsMap };
}

UNSAFE_componentWillReceiveProps(newProps) {
// Update differences if need be
UNSAFE_componentWillReceiveProps(newProps: AlteredSliceTagProps): void {
if (isEqual(this.props, newProps)) {
return;
}
Expand All @@ -84,22 +114,22 @@
}));
}

getRowsFromDiffs(diffs, controlsMap) {
getRowsFromDiffs(
diffs: { [key: string]: Diff },
controlsMap: ControlMap,
): Row[] {
return Object.entries(diffs).map(([key, diff]) => ({
control: (controlsMap[key] && controlsMap[key].label) || key,

Check failure on line 122 in superset-frontend/src/components/AlteredSliceTag/index.tsx

View workflow job for this annotation

GitHub Actions / frontend-build

Prefer using an optional chain expression instead, as it's more concise and easier to read
before: this.formatValue(diff.before, key, controlsMap),
after: this.formatValue(diff.after, key, controlsMap),
}));
}

getDiffs(props) {
// Returns all properties that differ in the
// current form data and the saved form data
getDiffs(props: AlteredSliceTagProps): { [key: string]: Diff } {
const ofd = sanitizeFormData(props.origFormData);
const cfd = sanitizeFormData(props.currentFormData);

const fdKeys = Object.keys(cfd);
const diffs = {};
const diffs: { [key: string]: Diff } = {};
fdKeys.forEach(fdKey => {
if (!ofd[fdKey] && !cfd[fdKey]) {
return;
Expand All @@ -114,11 +144,13 @@
return diffs;
}

isEqualish(val1, val2) {
isEqualish(val1: any, val2: any): boolean {
// Consider refining 'any' types
return isEqual(alterForComparison(val1), alterForComparison(val2));
}

formatValue(value, key, controlsMap) {
formatValue(value: any, key: string, controlsMap: ControlMap): string {
// Consider refining 'any' types
// Format display value based on the control type
// or the value type
if (value === undefined) {
Expand Down Expand Up @@ -167,7 +199,7 @@
return safeStringify(value);
}

renderModalBody() {
renderModalBody(): JSX.Element {
EnxDev marked this conversation as resolved.
Show resolved Hide resolved
const columns = [
{
accessor: 'control',
Expand Down Expand Up @@ -196,15 +228,15 @@
);
}

renderTriggerNode() {
renderTriggerNode(): JSX.Element {
EnxDev marked this conversation as resolved.
Show resolved Hide resolved
return (
<Tooltip id="difference-tooltip" title={t('Click to see difference')}>
<StyledLabel className="label">{t('Altered')}</StyledLabel>
</Tooltip>
);
}

render() {
render(): JSX.Element | null {
EnxDev marked this conversation as resolved.
Show resolved Hide resolved
// Return nothing if there are no differences
if (!this.state.hasDiffs) {
return null;
Expand All @@ -223,4 +255,4 @@
}
}

AlteredSliceTag.propTypes = propTypes;
export default AlteredSliceTag;
Loading