-
Notifications
You must be signed in to change notification settings - Fork 130
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
Notification system #4149
Notification system #4149
Conversation
…into notifications-sytem
Thanks for your contribution! Depending on what you are working on, you may want to request a review from a Shopify team:
|
/snapit |
🫰✨ Thanks @gonzaloriestra! Your snapshot has been published to npm. Test the snapshot by intalling your package globally: pnpm i -g @shopify/[email protected]
|
This PR seems inactive. If it's still relevant, please add a comment saying so. Otherwise, take no action. |
This comment has been minimized.
This comment has been minimized.
/snapit |
🫰✨ Thanks @gonzaloriestra! Your snapshot has been published to npm. Test the snapshot by intalling your package globally: pnpm i -g @shopify/[email protected]
|
Differences in type declarationsWe detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:
New type declarationspackages/cli-kit/dist/public/node/global-context.d.tsexport interface GlobalContext {
currentCommandId: string;
}
/**
* Get the current command ID.
*
* @returns Current command ID.
*/
export declare function getCurrentCommandId(): string;
/**
* Set the current command ID.
*
* @param commandId - Command ID.
*/
export declare function setCurrentCommandId(commandId: string): void;
packages/cli-kit/dist/public/node/notifications-system.d.tsimport { zod } from './schema.js';
declare const NotificationSchema: zod.ZodObject<{
id: zod.ZodString;
message: zod.ZodString;
type: zod.ZodEnum<["info", "warning", "error"]>;
frequency: zod.ZodEnum<["always", "once", "once_a_day", "once_a_week"]>;
ownerChannel: zod.ZodString;
cta: zod.ZodOptional<zod.ZodObject<{
label: zod.ZodString;
url: zod.ZodString;
}, "strip", zod.ZodTypeAny, {
url: string;
label: string;
}, {
url: string;
label: string;
}>>;
title: zod.ZodOptional<zod.ZodString>;
minVersion: zod.ZodOptional<zod.ZodString>;
maxVersion: zod.ZodOptional<zod.ZodString>;
minDate: zod.ZodOptional<zod.ZodString>;
maxDate: zod.ZodOptional<zod.ZodString>;
commands: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
surface: zod.ZodOptional<zod.ZodString>;
}, "strip", zod.ZodTypeAny, {
id: string;
type: "error" | "info" | "warning";
message: string;
frequency: "always" | "once" | "once_a_day" | "once_a_week";
ownerChannel: string;
cta?: {
url: string;
label: string;
} | undefined;
title?: string | undefined;
minVersion?: string | undefined;
maxVersion?: string | undefined;
minDate?: string | undefined;
maxDate?: string | undefined;
commands?: string[] | undefined;
surface?: string | undefined;
}, {
id: string;
type: "error" | "info" | "warning";
message: string;
frequency: "always" | "once" | "once_a_day" | "once_a_week";
ownerChannel: string;
cta?: {
url: string;
label: string;
} | undefined;
title?: string | undefined;
minVersion?: string | undefined;
maxVersion?: string | undefined;
minDate?: string | undefined;
maxDate?: string | undefined;
commands?: string[] | undefined;
surface?: string | undefined;
}>;
export type Notification = zod.infer<typeof NotificationSchema>;
declare const NotificationsSchema: zod.ZodObject<{
notifications: zod.ZodArray<zod.ZodObject<{
id: zod.ZodString;
message: zod.ZodString;
type: zod.ZodEnum<["info", "warning", "error"]>;
frequency: zod.ZodEnum<["always", "once", "once_a_day", "once_a_week"]>;
ownerChannel: zod.ZodString;
cta: zod.ZodOptional<zod.ZodObject<{
label: zod.ZodString;
url: zod.ZodString;
}, "strip", zod.ZodTypeAny, {
url: string;
label: string;
}, {
url: string;
label: string;
}>>;
title: zod.ZodOptional<zod.ZodString>;
minVersion: zod.ZodOptional<zod.ZodString>;
maxVersion: zod.ZodOptional<zod.ZodString>;
minDate: zod.ZodOptional<zod.ZodString>;
maxDate: zod.ZodOptional<zod.ZodString>;
commands: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
surface: zod.ZodOptional<zod.ZodString>;
}, "strip", zod.ZodTypeAny, {
id: string;
type: "error" | "info" | "warning";
message: string;
frequency: "always" | "once" | "once_a_day" | "once_a_week";
ownerChannel: string;
cta?: {
url: string;
label: string;
} | undefined;
title?: string | undefined;
minVersion?: string | undefined;
maxVersion?: string | undefined;
minDate?: string | undefined;
maxDate?: string | undefined;
commands?: string[] | undefined;
surface?: string | undefined;
}, {
id: string;
type: "error" | "info" | "warning";
message: string;
frequency: "always" | "once" | "once_a_day" | "once_a_week";
ownerChannel: string;
cta?: {
url: string;
label: string;
} | undefined;
title?: string | undefined;
minVersion?: string | undefined;
maxVersion?: string | undefined;
minDate?: string | undefined;
maxDate?: string | undefined;
commands?: string[] | undefined;
surface?: string | undefined;
}>, "many">;
}, "strip", zod.ZodTypeAny, {
notifications: {
id: string;
type: "error" | "info" | "warning";
message: string;
frequency: "always" | "once" | "once_a_day" | "once_a_week";
ownerChannel: string;
cta?: {
url: string;
label: string;
} | undefined;
title?: string | undefined;
minVersion?: string | undefined;
maxVersion?: string | undefined;
minDate?: string | undefined;
maxDate?: string | undefined;
commands?: string[] | undefined;
surface?: string | undefined;
}[];
}, {
notifications: {
id: string;
type: "error" | "info" | "warning";
message: string;
frequency: "always" | "once" | "once_a_day" | "once_a_week";
ownerChannel: string;
cta?: {
url: string;
label: string;
} | undefined;
title?: string | undefined;
minVersion?: string | undefined;
maxVersion?: string | undefined;
minDate?: string | undefined;
maxDate?: string | undefined;
commands?: string[] | undefined;
surface?: string | undefined;
}[];
}>;
export type Notifications = zod.infer<typeof NotificationsSchema>;
/**
* Shows notifications to the user if they meet the criteria specified in the notifications.json file.
*
* @param currentSurfaces - The surfaces present in the current project (usually for app extensions).
* @returns - A promise that resolves when the notifications have been shown.
*/
export declare function showNotificationsIfNeeded(currentSurfaces?: string[]): Promise<void>;
/**
* Get notifications list from cache (refreshed every hour) or fetch it if not present.
*
* @returns A Notifications object.
*/
export declare function getNotifications(): Promise<Notifications>;
/**
* Filters notifications based on the version of the CLI.
*
* @param notifications - The notifications to filter.
* @param commandId - The command ID to filter by.
* @param currentSurfaces - The surfaces present in the current project (usually for app extensions).
* @param today - The current date.
* @param currentVersion - The current version of the CLI.
* @returns - The filtered notifications.
*/
export declare function filterNotifications(notifications: Notification[], commandId: string, currentSurfaces?: string[], today?: Date, currentVersion?: string): Notification[];
/**
* Returns a string with the filters from a notification, one by line.
*
* @param notification - The notification to get the filters from.
* @returns A string with human-readable filters from the notification.
*/
export declare function stringifyFilters(notification: Notification): string;
/**
* Reads the notifications from the local file.
*
* @returns A Notifications object.
*/
export declare function getLocalNotifications(): Promise<Notifications>;
export {};
Existing type declarationspackages/cli-kit/dist/private/node/conf-store.d.ts@@ -5,13 +5,17 @@ interface CacheValue<T> {
}
export type IntrospectionUrlKey = ;
export type PackageVersionKey = ;
+export type NotificationsKey = ;
+export type NotificationKey = ;
type MostRecentOccurrenceKey = ;
type RateLimitKey = ;
-type ExportedKey = IntrospectionUrlKey | PackageVersionKey;
+type ExportedKey = IntrospectionUrlKey | PackageVersionKey | NotificationsKey | NotificationKey;
interface Cache {
[introspectionUrlKey: IntrospectionUrlKey]: CacheValue<string>;
[packageVersionKey: PackageVersionKey]: CacheValue<string>;
- [mostRecentOccurrenceKey: MostRecentOccurrenceKey]: CacheValue<boolean>;
+ [notifications: NotificationsKey]: CacheValue<string>;
+ [notification: NotificationKey]: CacheValue<string>;
+ [MostRecentOccurrenceKey: MostRecentOccurrenceKey]: CacheValue<boolean>;
[rateLimitKey: RateLimitKey]: CacheValue<number[]>;
}
export interface ConfSchema {
@@ -45,12 +49,13 @@ type CacheValueForKey<TKey extends keyof Cache> = NonNullable<Cache[TKey]>['valu
* @returns The value from the cache or the result of the function.
*/
export declare function cacheRetrieveOrRepopulate(key: ExportedKey, fn: () => Promise<CacheValueForKey<typeof key>>, timeout?: number, config?: LocalStorage<ConfSchema>): Promise<CacheValueForKey<typeof key>>;
+export declare function cacheStore(key: ExportedKey, value: string, config?: LocalStorage<ConfSchema>): void;
/**
* Fetch from cache if already populated, otherwise return undefined.
* @param key - The key to use for the cache.
- * @returns The value from the cache or the result of the function.
+ * @returns The chache element.
*/
-export declare function cacheRetrieve(key: ExportedKey, config?: LocalStorage<ConfSchema>): CacheValueForKey<typeof key> | undefined;
+export declare function cacheRetrieve(key: ExportedKey, config?: LocalStorage<ConfSchema>): CacheValue<string> | undefined;
export declare function cacheClear(config?: LocalStorage<ConfSchema>): void;
interface TimeInterval {
days?: number;
packages/cli-kit/dist/public/node/cli.d.ts@@ -34,4 +34,8 @@ export declare const globalFlags: {
'no-color': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
verbose: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
};
+/**
+ * Clear the CLI cache, used to store some API responses and handle notifications status
+ */
+export declare function clearCache(): void;
export {};
\ No newline at end of file
|
WHY are these changes introduced?
Fixes: https://github.com/Shopify/develop-app-inner-loop/issues/1962
We want to notify CLI users about deprecations, new features or events
WHAT is this pull request doing?
Adds three hidden commands:
notifications generate
: shows several prompts asking for the notification content, type and filters, and adds it to a local notifications.json file.notifications list
: shows the current notifications from the local notifications.jsoncache clear
: clears the CLI cache (Mac stores it in~/Library/Preferences/shopify-cli-kit-nodejs/config.json
), including notifications stuff and other API responses that are temporarily memorizedThen, before each command we check the remote notifications.json from this repository and show the required ones. The file is cached for 24h.
Demo: https://hackdays.shopify.io/projects/18981
How to test your changes?
Install the snapshot from this branch:
npm i -g @shopify/[email protected]
I've uploaded a sample notifications.json to simplify testing:
SHOPIFY_CLI_NOTIFICATIONS_URL=https://shopify.link/MNbn shopify version
SHOPIFY_CLI_NOTIFICATIONS_URL=https://shopify.link/MNbn shopify theme list
When
SHOPIFY_CLI_NOTIFICATIONS_URL
is not passed, it looks for the file in the main branch of this repository (it doesn't exist yet).To generate and list notifications:
shopify notifications generate
shopify notifications list
To clear the cache, so that it downloads again the configuration file and forgets if a notification was shown:
shopify cache clear
Post-release steps
Merge the internal doc: https://github.com/Shopify/vault-pages/pull/7111
Measuring impact
How do we know this change was effective? Please choose one:
Checklist