@@ -47,6 +47,7 @@ import {
47
47
import { LocalSetting } from "./localsettings" ;
48
48
import { AdminUIState , AppDispatch } from "./state" ;
49
49
import {
50
+ LICENSE_UPDATE_DISMISSED_KEY ,
50
51
VERSION_DISMISSED_KEY ,
51
52
INSTRUCTIONS_BOX_COLLAPSED_KEY ,
52
53
saveUIData ,
@@ -61,6 +62,7 @@ export enum AlertLevel {
61
62
WARNING ,
62
63
CRITICAL ,
63
64
SUCCESS ,
65
+ INFORMATION ,
64
66
}
65
67
66
68
export interface AlertInfo {
@@ -635,20 +637,6 @@ export const upgradeNotFinalizedWarningSelector = createSelector(
635
637
} ,
636
638
) ;
637
639
638
- /**
639
- * Selector which returns an array of all active alerts which should be
640
- * displayed in the overview list page, these should be non-critical alerts.
641
- */
642
-
643
- export const overviewListAlertsSelector = createSelector (
644
- staggeredVersionWarningSelector ,
645
- clusterPreserveDowngradeOptionOvertimeSelector ,
646
- upgradeNotFinalizedWarningSelector ,
647
- ( ...alerts : Alert [ ] ) : Alert [ ] => {
648
- return without ( alerts , null , undefined ) ;
649
- } ,
650
- ) ;
651
-
652
640
/**
653
641
* Selector which returns an array of all active alerts which should be
654
642
* displayed in the alerts panel, which is embedded within the cluster overview
@@ -707,6 +695,104 @@ export const licenseTypeSelector = createSelector(
707
695
data => licenseTypeNames . get ( data . LicenseType ) || "None" ,
708
696
) ;
709
697
698
+ export const licenseUpdateDismissedLocalSetting = new LocalSetting (
699
+ "license_update_dismissed" ,
700
+ localSettingsSelector ,
701
+ moment ( 0 ) ,
702
+ ) ;
703
+
704
+ const licenseUpdateDismissedPersistentLoadedSelector = createSelector (
705
+ ( state : AdminUIState ) => state . uiData ,
706
+ uiData => uiData && uiData . hasOwnProperty ( LICENSE_UPDATE_DISMISSED_KEY ) ,
707
+ ) ;
708
+
709
+ const licenseUpdateDismissedPersistentSelector = createSelector (
710
+ ( state : AdminUIState ) => state . uiData ,
711
+ uiData => moment ( uiData ?. [ LICENSE_UPDATE_DISMISSED_KEY ] ?. data ?? 0 ) ,
712
+ ) ;
713
+
714
+ export const licenseUpdateNotificationSelector = createSelector (
715
+ licenseTypeSelector ,
716
+ licenseUpdateDismissedLocalSetting . selector ,
717
+ licenseUpdateDismissedPersistentSelector ,
718
+ licenseUpdateDismissedPersistentLoadedSelector ,
719
+ (
720
+ licenseType ,
721
+ licenseUpdateDismissed ,
722
+ licenseUpdateDismissedPersistent ,
723
+ licenseUpdateDismissedPersistentLoaded ,
724
+ ) : Alert => {
725
+ // If customer has Enterprise license they don't need to worry about this.
726
+ if ( licenseType === "Enterprise" ) {
727
+ return undefined ;
728
+ }
729
+
730
+ // If the notification has been dismissed based on the session storage
731
+ // timestamp, don't show it.'
732
+ //
733
+ // Note: `licenseUpdateDismissed` is wrapped in `moment()` because
734
+ // the local storage selector won't convert it back from a string.
735
+ // We omit fixing that here since this change is being backported
736
+ // to many versions.
737
+ if ( moment ( licenseUpdateDismissed ) . isAfter ( moment ( 0 ) ) ) {
738
+ return undefined ;
739
+ }
740
+
741
+ // If the notification has been dismissed based on the uiData
742
+ // storage in the cluster, don't show it. Note that this is
743
+ // different from how version upgrade notifications work, this one
744
+ // is dismissed forever and won't return even if you upgrade
745
+ // further or time passes.
746
+ if (
747
+ licenseUpdateDismissedPersistentLoaded &&
748
+ licenseUpdateDismissedPersistent &&
749
+ licenseUpdateDismissedPersistent . isAfter ( moment ( 0 ) )
750
+ ) {
751
+ return undefined ;
752
+ }
753
+
754
+ return {
755
+ level : AlertLevel . INFORMATION ,
756
+ title : "Coming November 18, 2024" ,
757
+ text : "Important changes to CockroachDB’s licensing model." ,
758
+ link : docsURL . enterpriseLicenseUpdate ,
759
+ dismiss : ( dispatch : any ) => {
760
+ const dismissedAt = moment ( ) ;
761
+ // Note(davidh): I haven't been able to find historical context
762
+ // for why some alerts have both a "local" and a "persistent"
763
+ // dismissal. My thinking is that just the persistent dismissal
764
+ // should be adequate, but I'm preserving that behavior here to
765
+ // match the version upgrade notification.
766
+
767
+ // Dismiss locally.
768
+ dispatch ( licenseUpdateDismissedLocalSetting . set ( dismissedAt ) ) ;
769
+ // Dismiss persistently.
770
+ return dispatch (
771
+ saveUIData ( {
772
+ key : LICENSE_UPDATE_DISMISSED_KEY ,
773
+ value : dismissedAt . valueOf ( ) ,
774
+ } )
775
+ ) ;
776
+ } ,
777
+ } ;
778
+ } ,
779
+ ) ;
780
+
781
+ /**
782
+ * Selector which returns an array of all active alerts which should be
783
+ * displayed in the overview list page, these should be non-critical alerts.
784
+ */
785
+
786
+ export const overviewListAlertsSelector = createSelector (
787
+ staggeredVersionWarningSelector ,
788
+ clusterPreserveDowngradeOptionOvertimeSelector ,
789
+ upgradeNotFinalizedWarningSelector ,
790
+ licenseUpdateNotificationSelector ,
791
+ ( ...alerts : Alert [ ] ) : Alert [ ] => {
792
+ return without ( alerts , null , undefined ) ;
793
+ } ,
794
+ ) ;
795
+
710
796
// daysUntilLicenseExpiresSelector returns number of days remaining before license expires.
711
797
export const daysUntilLicenseExpiresSelector = createSelector (
712
798
getDataFromServer ,
@@ -780,6 +866,7 @@ export function alertDataSync(store: Store<AdminUIState>) {
780
866
const keysToMaybeLoad = [
781
867
VERSION_DISMISSED_KEY ,
782
868
INSTRUCTIONS_BOX_COLLAPSED_KEY ,
869
+ LICENSE_UPDATE_DISMISSED_KEY ,
783
870
] ;
784
871
const keysToLoad = filter ( keysToMaybeLoad , key => {
785
872
return ! ( has ( uiData , key ) || isInFlight ( state , key ) ) ;
0 commit comments