Skip to content

Commit

Permalink
Merge branch 'master' of github.com:carbon-design-system/carbon-addon…
Browse files Browse the repository at this point in the history
…s-iot-react into dashboard-editor
  • Loading branch information
Stephen Stone committed Oct 9, 2020
2 parents 761cf09 + d5b1e9c commit d42ff05
Show file tree
Hide file tree
Showing 33 changed files with 5,531 additions and 4,197 deletions.
275 changes: 144 additions & 131 deletions src/components/Dashboard/CardRenderer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,148 +61,161 @@ export const loadCardData = async (card, setCard, onFetchData, timeGrain) => {
* it will trigger the dashboard's onSetupCard function and then it's onFetchData function to retrieve the updated card properties
* for each card.
*/
const CardRenderer = React.memo(({ /* eslint-disable react/prop-types */
onCardAction, i18n, isLoading, isEditable, breakpoint, onFetchData, onSetupCard, renderIconByName, timeGrain, ...cardProp }) => {
// pass through the card props
/* eslint-enable react/prop-types */
if (__DEV__) {
warning(
false,
'CardRenderer component has been deprecated and will be removed in the next release of `carbon-addons-iot-react`.'
);
}
const CardRenderer = React.memo(
({
/* eslint-disable react/prop-types */ onCardAction,
i18n,
isLoading,
isEditable,
breakpoint,
onFetchData,
onSetupCard,
renderIconByName,
timeGrain,
...cardProp
}) => {
// pass through the card props
/* eslint-enable react/prop-types */
if (__DEV__) {
warning(
false,
'CardRenderer component has been deprecated and will be removed in the next release of `carbon-addons-iot-react`.'
);
}

const { dataSource, availableActions, type } = cardProp;
const { dataSource, availableActions, type } = cardProp;

/**
* Local state for the card, keeps track of whether it is loading or not, and the current state of the Range Selector
* And which data range is being requested.
*/
const [card, setCard] = useState(cardProp);
// Keep track of the original datasource setting
const [originalDataSource] = useState(dataSource);
// keep track of the expanded card id
const [isExpanded, setIsExpanded] = useState();
/**
* Local state for the card, keeps track of whether it is loading or not, and the current state of the Range Selector
* And which data range is being requested.
*/
const [card, setCard] = useState(cardProp);
// Keep track of the original datasource setting
const [originalDataSource] = useState(dataSource);
// keep track of the expanded card id
const [isExpanded, setIsExpanded] = useState();

// Allow the i18n to change between renders
const cachedI18N = useMemo(() => ({ ...i18n, ...card.i18n }), [i18n, card.i18n]);
// Allow the i18n to change between renders
const cachedI18N = useMemo(() => ({ ...i18n, ...card.i18n }), [i18n, card.i18n]);

// If the dashboard has triggered a bulk load, refetch the data
useEffect(
() => {
const setupAndLoadCard = async () => {
let updatedCard = card;
// Image cards require extra setup before loading data
if (onSetupCard && card.type === CARD_TYPES.IMAGE && !card.content.src) {
updatedCard = await onSetupCard(card);
setCard(updatedCard);
// If the dashboard has triggered a bulk load, refetch the data
useEffect(
() => {
const setupAndLoadCard = async () => {
let updatedCard = card;
// Image cards require extra setup before loading data
if (onSetupCard && card.type === CARD_TYPES.IMAGE && !card.content.src) {
updatedCard = await onSetupCard(card);
setCard(updatedCard);
}
loadCardData(updatedCard, setCard, onFetchData, timeGrain);
};
if (isLoading) {
setupAndLoadCard();
}
loadCardData(updatedCard, setCard, onFetchData, timeGrain);
};
if (isLoading) {
setupAndLoadCard();
}
},
[isLoading, card.content.src] // eslint-disable-line react-hooks/exhaustive-deps
);
},
[isLoading, card.content.src] // eslint-disable-line react-hooks/exhaustive-deps
);

// Speed up performance by caching the available actions
const cachedActions = useMemo(
() =>
merge(
{
range: !isEmpty(dataSource), // all cards should have the range picker
expand:
type === CARD_TYPES.IMAGE ||
type === CARD_TYPES.TIMESERIES ||
type === CARD_TYPES.TABLE ||
type === CARD_TYPES.BAR ||
availableActions?.expand, // image and line chart cards should have expand
},
availableActions || {}
),
[availableActions, dataSource, type]
);
// Speed up performance by caching the available actions
const cachedActions = useMemo(
() =>
merge(
{
range: !isEmpty(dataSource), // all cards should have the range picker
expand:
type === CARD_TYPES.IMAGE ||
type === CARD_TYPES.TIMESERIES ||
type === CARD_TYPES.TABLE ||
type === CARD_TYPES.BAR ||
availableActions?.expand, // image and line chart cards should have expand
},
availableActions || {}
),
[availableActions, dataSource, type]
);

/**
* Listen to the card's range action to decide whether to trigger a data refetch
*/
const cachedOnCardAction = useCallback(
async (id, actionType, payload) => {
// callback time grain change from parent
if (actionType === CARD_ACTIONS.CHANGE_TIME_RANGE) {
// First update the range
const range =
payload && payload.range !== 'default'
? determineCardRange(payload.range)
: originalDataSource.range; // If default, then reset the card range
const cardWithUpdatedRange = {
...card, // expand the current card state
isLoading: true, // set loading
dataSource: {
...cardProp.dataSource,
range: {
...range,
...omit(range, 'timeGrain'),
/**
* Listen to the card's range action to decide whether to trigger a data refetch
*/
const cachedOnCardAction = useCallback(
async (id, actionType, payload) => {
// callback time grain change from parent
if (actionType === CARD_ACTIONS.CHANGE_TIME_RANGE) {
// First update the range
const range =
payload && payload.range !== 'default'
? determineCardRange(payload.range)
: originalDataSource.range; // If default, then reset the card range
const cardWithUpdatedRange = {
...card, // expand the current card state
isLoading: true, // set loading
dataSource: {
...cardProp.dataSource,
range: {
...range,
...omit(range, 'timeGrain'),
},
// Use the maximum selected grain betweeen the dashboard and the current range
timeGrain:
compareGrains(timeGrain, range.timeGrain) < 1 ? range.timeGrain : timeGrain,
},
// Use the maximum selected grain betweeen the dashboard and the current range
timeGrain: compareGrains(timeGrain, range.timeGrain) < 1 ? range.timeGrain : timeGrain,
},
};
// Then trigger a load of the card data
loadCardData(cardWithUpdatedRange, setCard, onFetchData, timeGrain);
} else if (actionType === CARD_ACTIONS.OPEN_EXPANDED_CARD) {
setIsExpanded(true);
} else if (actionType === CARD_ACTIONS.UPDATE_DATA) {
// New action type where we pass the updated values data
setCard(currentCardState => ({
...currentCardState,
values: payload?.values,
}));
}
};
// Then trigger a load of the card data
loadCardData(cardWithUpdatedRange, setCard, onFetchData, timeGrain);
} else if (actionType === CARD_ACTIONS.OPEN_EXPANDED_CARD) {
setIsExpanded(true);
} else if (actionType === CARD_ACTIONS.UPDATE_DATA) {
// New action type where we pass the updated values data
setCard(currentCardState => ({
...currentCardState,
values: payload?.values,
}));
}

// close expanded card
if (actionType === CARD_ACTIONS.CLOSE_EXPANDED_CARD) {
setIsExpanded(false);
}
},
[card, onFetchData, originalDataSource && originalDataSource.range, timeGrain] // eslint-disable-line react-hooks/exhaustive-deps
);
// close expanded card
if (actionType === CARD_ACTIONS.CLOSE_EXPANDED_CARD) {
setIsExpanded(false);
}
},
[card, onFetchData, originalDataSource && originalDataSource.range, timeGrain] // eslint-disable-line react-hooks/exhaustive-deps
);

const commonCardProps = {
...card, // pass all the card props, including the card data to the card
style: cardProp.style, // these come from grid layout and not state
className: cardProp.className, // these come from grid layout and not state
key: cardProp.id,
availableActions: cachedActions,
isExpanded,
i18n: cachedI18N,
isEditable,
onCardAction: cachedOnCardAction,
renderIconByName,
breakpoint,
};
const commonCardProps = {
...card, // pass all the card props, including the card data to the card
style: cardProp.style, // these come from grid layout and not state
className: cardProp.className, // these come from grid layout and not state
key: cardProp.id,
availableActions: cachedActions,
isExpanded,
i18n: cachedI18N,
isEditable,
onCardAction: cachedOnCardAction,
renderIconByName,
breakpoint,
};

return type === CARD_TYPES.VALUE ? (
<ValueCard {...commonCardProps} />
) : type === CARD_TYPES.IMAGE ? (
<ImageCard {...commonCardProps} error={card.setupError || card.error} />
) : type === CARD_TYPES.TIMESERIES ? (
<TimeSeriesCard {...commonCardProps} />
) : type === CARD_TYPES.TABLE ? (
<TableCard {...commonCardProps} />
) : type === CARD_TYPES.BAR ? (
<BarChartCard {...commonCardProps} />
) : type === CARD_TYPES.LIST ? (
<ListCard {...commonCardProps} data={card.content.data} loadData={card.content.loadData} />
) : type === CARD_TYPES.GAUGE ? (
<GaugeCard {...commonCardProps} />
) : type === CARD_TYPES.CUSTOM ? (
<Card hideHeader={isNil(card.title)} {...omit(commonCardProps, 'content')}>
{card.content}
</Card>
) : null;
});
return type === CARD_TYPES.VALUE ? (
<ValueCard {...commonCardProps} />
) : type === CARD_TYPES.IMAGE ? (
<ImageCard {...commonCardProps} error={card.setupError || card.error} />
) : type === CARD_TYPES.TIMESERIES ? (
<TimeSeriesCard {...commonCardProps} />
) : type === CARD_TYPES.TABLE ? (
<TableCard {...commonCardProps} />
) : type === CARD_TYPES.BAR ? (
<BarChartCard {...commonCardProps} />
) : type === CARD_TYPES.LIST ? (
<ListCard {...commonCardProps} data={card.content.data} loadData={card.content.loadData} />
) : type === CARD_TYPES.GAUGE ? (
<GaugeCard {...commonCardProps} />
) : type === CARD_TYPES.CUSTOM ? (
<Card hideHeader={isNil(card.title)} {...omit(commonCardProps, 'content')}>
{card.content}
</Card>
) : null;
}
);

CachedCardRenderer.propTypes = {
style: PropTypes.objectOf(PropTypes.string),
Expand Down
Loading

0 comments on commit d42ff05

Please sign in to comment.