2018-05-01 11:37:30 -07:00
|
|
|
import Service from '@ember/service';
|
2019-08-31 20:51:14 -07:00
|
|
|
import Configurator from 'wherehows-web/services/configurator';
|
|
|
|
import { bannerAnimationSpeed } from '@datahub/utils/constants/notifications';
|
|
|
|
import { NotificationEvent } from '@datahub/utils/constants/notifications';
|
2018-05-01 11:37:30 -07:00
|
|
|
import { delay } from 'wherehows-web/utils/promise-delay';
|
2019-08-31 20:51:14 -07:00
|
|
|
import { computed } from '@ember/object';
|
2018-05-01 11:37:30 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Expected properties to be found on a basic banner object added to our list
|
|
|
|
*/
|
|
|
|
export interface IBanner {
|
|
|
|
content: string;
|
|
|
|
type: NotificationEvent;
|
|
|
|
isExiting: boolean;
|
|
|
|
isDismissable: boolean;
|
|
|
|
iconName: string;
|
2018-05-03 14:05:15 -07:00
|
|
|
usePartial: boolean;
|
2018-05-01 11:37:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* When creating a new banner, helps to determine whether that banner isDismissable
|
|
|
|
*/
|
|
|
|
const isDismissableMap: { [key: string]: boolean } = {
|
|
|
|
[NotificationEvent['info']]: true,
|
|
|
|
[NotificationEvent['confirm']]: true,
|
|
|
|
[NotificationEvent['error']]: false
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* When creating a new banner, helps to determine the kind of font awesome icon indicator will be on
|
|
|
|
* the left side of the banner
|
|
|
|
*/
|
|
|
|
const iconNameMap: { [key: string]: string } = {
|
|
|
|
[NotificationEvent['info']]: 'info-circle',
|
|
|
|
[NotificationEvent['confirm']]: 'exclamation-circle',
|
|
|
|
[NotificationEvent['error']]: 'times-circle'
|
|
|
|
};
|
|
|
|
|
|
|
|
export default class BannerService extends Service {
|
|
|
|
/**
|
|
|
|
* Our cached list of banner objects to be rendered
|
|
|
|
* @type {Array<IBanner>}
|
|
|
|
*/
|
|
|
|
banners: Array<IBanner> = [];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Computes the banners list elements to toggle the isShowingBanners flag, which not only activates the
|
|
|
|
* banner component but also triggers the navbar and app-container body to shift up/down to accommodate
|
|
|
|
* for the banner component space
|
|
|
|
* @type {ComputedProperty<boolean>}
|
|
|
|
*/
|
2019-08-31 20:51:14 -07:00
|
|
|
@computed('banners.@each.isExiting')
|
|
|
|
get isShowingBanners(): boolean {
|
|
|
|
const { banners } = this;
|
2018-05-01 11:37:30 -07:00
|
|
|
// Note: If we have no banners, flag should always be false. If we have more than one banner, flag
|
|
|
|
// should always be true, BUT if we only have one banner and it is in an exiting state we can go ahead
|
|
|
|
// and trigger this to be false to line up with the animation
|
|
|
|
return banners.length > 0 && (banners.length > 1 || !banners[0].isExiting);
|
2019-08-31 20:51:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
appInitialBanners([showStagingBanner, showLiveDataWarning, showChangeManagement]: Array<boolean>): void {
|
|
|
|
const { getConfig } = Configurator;
|
2018-05-01 11:37:30 -07:00
|
|
|
|
2018-05-03 18:20:53 -07:00
|
|
|
if (showStagingBanner) {
|
|
|
|
this.addBanner(
|
|
|
|
'You are viewing/editing in the staging environment. Changes made here will not reflect in production',
|
|
|
|
NotificationEvent['info']
|
|
|
|
);
|
|
|
|
}
|
2018-09-13 10:43:07 -07:00
|
|
|
|
|
|
|
if (showLiveDataWarning) {
|
|
|
|
this.addBanner(
|
|
|
|
'You are viewing/editing live data. Changes made here will affect production data',
|
|
|
|
NotificationEvent['confirm']
|
|
|
|
);
|
|
|
|
}
|
2019-08-31 20:51:14 -07:00
|
|
|
|
|
|
|
if (showChangeManagement) {
|
|
|
|
const changeManagementLink = getConfig('changeManagementLink', { useDefault: true, default: '' });
|
|
|
|
this.addBanner(
|
|
|
|
`Our pipeline is currently under maintenance or a new deployment and some features may be temporarily
|
|
|
|
unavailable. You can find more information at ${changeManagementLink}`,
|
|
|
|
NotificationEvent['confirm']
|
|
|
|
);
|
|
|
|
}
|
2018-05-03 18:20:53 -07:00
|
|
|
}
|
|
|
|
|
2018-05-01 11:37:30 -07:00
|
|
|
/**
|
|
|
|
* Method to actually take care of removing the first banner from our queue.
|
|
|
|
*/
|
|
|
|
async dequeue(): Promise<void> {
|
|
|
|
// Note: Since dequeuing the banner will remove it from the DOM, we don't want to actually dequeue
|
2018-05-01 22:50:04 -07:00
|
|
|
// until the removal animation, which takes 0.6 seconds, is completed.
|
|
|
|
const animationOffset = bannerAnimationSpeed + 0.2;
|
|
|
|
const dismissDelay = delay(animationOffset);
|
2018-05-01 11:37:30 -07:00
|
|
|
|
|
|
|
await dismissDelay;
|
2019-08-31 20:51:14 -07:00
|
|
|
this.banners.shiftObject();
|
2018-05-01 11:37:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Method to add the banner to our queue. Takes the content and type of banner and creates a
|
|
|
|
* standardized interface that our servie can understand
|
|
|
|
* @param message - the message to put in the banner's content box
|
|
|
|
* @param {NotificationEvent} type - what type of banner notification we are going for (which will
|
|
|
|
* determine the appearance and interaction properties)
|
2018-05-03 14:05:15 -07:00
|
|
|
* @param usePartial - in some situations, we want to use a partial component to render in the banner instead
|
|
|
|
* of a simple string. This flag will allow that
|
2018-05-01 11:37:30 -07:00
|
|
|
*/
|
2018-05-03 14:05:15 -07:00
|
|
|
addBanner(message: string, type: NotificationEvent = NotificationEvent['info'], usePartial = false): void {
|
2019-08-31 20:51:14 -07:00
|
|
|
this.banners.unshiftObject({
|
2018-05-01 11:37:30 -07:00
|
|
|
type,
|
2018-05-03 14:05:15 -07:00
|
|
|
usePartial,
|
2018-05-01 11:37:30 -07:00
|
|
|
content: message,
|
|
|
|
isExiting: false,
|
|
|
|
isDismissable: isDismissableMap[type],
|
|
|
|
iconName: iconNameMap[type]
|
|
|
|
});
|
|
|
|
}
|
2018-05-14 11:26:52 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Allows us to target a specific banner for removal by giving the content and type and then searching the
|
|
|
|
* list for a specific match to remove at the found index. If nothing is matched, function does nothing
|
|
|
|
* @param content - banner content to match for removal
|
|
|
|
* @param type = banner type to match for removal
|
|
|
|
*/
|
|
|
|
removeBanner(content: string, type: NotificationEvent): void {
|
2019-08-31 20:51:14 -07:00
|
|
|
const { banners } = this;
|
2018-05-14 11:26:52 -07:00
|
|
|
|
|
|
|
const removalIndex = banners.reduce(
|
|
|
|
(index, banner, currIndex) => (banner.content === content && banner.type === type ? currIndex : index),
|
|
|
|
-1
|
|
|
|
);
|
|
|
|
|
|
|
|
if (removalIndex > -1) {
|
|
|
|
banners.removeAt(removalIndex, 1);
|
|
|
|
}
|
|
|
|
}
|
2018-05-01 11:37:30 -07:00
|
|
|
}
|