Skip to content

Commit 4e69561

Browse files
committed
feat(release): adds release note notification on update
1 parent df26938 commit 4e69561

21 files changed

+170
-94
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"@dvcol/tmdb-http-client": "^1.2.3",
5757
"@dvcol/trakt-http-client": "^1.4.5",
5858
"@dvcol/tvdb-http-client": "^1.1.3",
59-
"@dvcol/web-extension-utils": "^3.0.1",
59+
"@dvcol/web-extension-utils": "^3.1.0",
6060
"@vue/devtools": "^7.0.15",
6161
"iso-3166-2": "^1.0.0",
6262
"naive-ui": "^2.38.1",

pnpm-lock.yaml

+5-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/container/ContainerComponent.ce.vue

+4-1
Original file line numberDiff line numberDiff line change
@@ -165,22 +165,25 @@ onBeforeMount(() => addCustomProgressProperty());
165165
);
166166
}
167167
168-
.n-notification-container .n-notification,
168+
.n-notification-container .n-notification.n-notification--error-type,
169169
.n-message-wrapper .n-message.n-message--error-type {
170170
--custom-bg-color: var(--bg-color-error-80);
171171
--custom-bg-color-hover: var(--bg-color-error);
172172
}
173173
174+
.n-notification-container .n-notification.n-notification--success-type,
174175
.n-message-wrapper .n-message.n-message--success-type {
175176
--custom-bg-color: var(--bg-color-success-80);
176177
--custom-bg-color-hover: var(--bg-color-success);
177178
}
178179
180+
.n-notification-container .n-notification.n-notification--info-type,
179181
.n-message-wrapper .n-message.n-message--info-type {
180182
--custom-bg-color: var(--bg-color-info-80);
181183
--custom-bg-color-hover: var(--bg-color-info);
182184
}
183185
186+
.n-notification-container .n-notification.n-notification--warning-type,
184187
.n-message-wrapper .n-message.n-message--warning-type {
185188
--custom-bg-color: var(--bg-color-warning-80);
186189
--custom-bg-color-hover: var(--bg-color-warning);
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"notification__release_title": {
3+
"message": "New version installed",
4+
"description": "The extension has been updated to a new version."
5+
},
6+
"notification__release_content": {
7+
"message": "A new update has just been installed.\nTo now more, see the release notes.",
8+
"description": "The content of the notification that is shown when a new version is installed."
9+
},
10+
"notification__release_notes": {
11+
"message": "Release notes",
12+
"description": "The text of the link to the release notes."
13+
}
14+
}

src/models/context/context-menu-hooks.model.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
import { openPopup } from '@dvcol/web-extension-utils/chrome/action';
2+
import { context } from '@dvcol/web-extension-utils/chrome/context';
3+
import { runtime } from '@dvcol/web-extension-utils/chrome/runtime';
14
import { createTab } from '@dvcol/web-extension-utils/chrome/tabs';
25

6+
import type { ContextMenuOnClickedData } from '@dvcol/web-extension-utils/chrome/models';
37
import type { RouteLocationNormalized } from 'vue-router';
48

59
import { ContextMenuConstants, ContextMenuId, type ContextMenuIds, ContextMenus } from '~/models/context/context-menu.model';
610
import { Route, RouterStorageKey } from '~/models/router.model';
7-
import { action } from '~/utils/browser/borwser-action.utils';
8-
import { context, type ContextMenuOnClickedData } from '~/utils/browser/browser-context.utils';
9-
import { runtime } from '~/utils/browser/browser-runtime.utils';
1011
import { storage } from '~/utils/browser/browser-storage.utils';
1112

1213
const setLastRoute = (data: ContextMenuOnClickedData) => {
@@ -17,8 +18,8 @@ const setLastRoute = (data: ContextMenuOnClickedData) => {
1718
} satisfies Partial<RouteLocationNormalized>);
1819
};
1920

20-
const openPopup = async () => {
21-
if (action?.openPopup) return action.openPopup();
21+
const openPopupApp = async () => {
22+
if (openPopup) return openPopup();
2223
if (!runtime) return;
2324
await createTab({
2425
url: runtime.getURL('views/options/index.html'),
@@ -28,7 +29,7 @@ const openPopup = async () => {
2829
export const ContextMenusHooks: Record<ContextMenuIds, (data: ContextMenuOnClickedData) => void | Promise<void>> = {
2930
[ContextMenuId.OpenInSideTrakt]: async data => {
3031
await setLastRoute(data);
31-
await openPopup();
32+
await openPopupApp();
3233
},
3334
[ContextMenuId.AddToSearchHistory]: setLastRoute,
3435
} as const;
+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
import type { VersionUpdateDetails } from '@dvcol/web-extension-utils/chrome/models';
2+
import type { ContextMenuIds } from '~/models/context/context-menu.model';
3+
14
export const MessageType = {
25
ContextMenu: 'context-menu',
6+
VersionUpdate: 'version-update',
37
} as const;
8+
9+
export type MessageTypes = (typeof MessageType)[keyof typeof MessageType];
10+
11+
/**
12+
* Type union of possible message payloads
13+
*/
14+
export type MessagePayload<T extends MessageTypes = MessageTypes> = T extends typeof MessageType.ContextMenu
15+
? Record<ContextMenuIds, boolean>
16+
: T extends typeof MessageType.VersionUpdate
17+
? VersionUpdateDetails & { date: number }
18+
: MessageTypes;

src/scripts/background/index.ts

+39-17
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,48 @@
1+
import { onContextMenuClicked } from '@dvcol/web-extension-utils/chrome/context';
2+
import { onInstalledEvent, onVersionUpdate } from '@dvcol/web-extension-utils/chrome/runtime';
3+
14
import { ContextMenusHooks, installContextMenus } from '~/models/context/context-menu-hooks.model';
25
import { isContextMenuId } from '~/models/context/context-menu.model';
36
import { MessageType } from '~/models/message/message-type.model';
4-
import { context } from '~/utils/browser/browser-context.utils';
5-
import { runtime } from '~/utils/browser/browser-runtime.utils';
7+
import { onMessage } from '~/utils/browser/browser-message.utils';
8+
import { storage } from '~/utils/browser/browser-storage.utils';
69

710
console.debug('Background script started');
811

9-
runtime?.onInstalled.addListener(async () => {
10-
await installContextMenus();
12+
try {
13+
onInstalledEvent(async details => {
14+
await installContextMenus();
15+
16+
console.debug('Context menu installed', details);
17+
});
18+
} catch (error) {
19+
console.error('Failed to install context menus', error);
20+
}
1121

12-
console.debug('Extension installed');
13-
});
22+
try {
23+
onVersionUpdate(async details => {
24+
console.debug(`Extension updated`, details);
25+
await storage.local.set(MessageType.VersionUpdate, { ...details, date: Date.now() });
26+
});
27+
} catch (error) {
28+
console.error('Failed to handle version update', error);
29+
}
1430

15-
runtime?.onMessage.addListener(async message => {
16-
if (message.type === MessageType.ContextMenu) {
17-
await installContextMenus(message.enabled);
18-
}
19-
});
31+
try {
32+
onMessage(MessageType.ContextMenu, async message => {
33+
await installContextMenus(message.payload);
34+
});
35+
} catch (error) {
36+
console.error('Failed to handle context menu message', error);
37+
}
2038

21-
context?.onClicked.addListener(async info => {
22-
if (isContextMenuId(info.menuItemId)) {
23-
return ContextMenusHooks[info.menuItemId](info);
24-
}
25-
console.error('Unknown context menu event', info);
26-
});
39+
try {
40+
onContextMenuClicked(async info => {
41+
if (isContextMenuId(info.menuItemId)) {
42+
return ContextMenusHooks[info.menuItemId](info);
43+
}
44+
console.error('Unknown context menu event', info);
45+
});
46+
} catch (error) {
47+
console.error('Failed to handle context menu click event', error);
48+
}

src/services/notification.service.ts

+38
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1+
import { createTab } from '@dvcol/web-extension-utils/chrome/tabs';
2+
3+
import { NButton } from 'naive-ui';
4+
5+
import { h } from 'vue';
6+
17
import type { Mutable } from '@dvcol/common-utils/common';
28
import type { NotificationOptions, useMessage, useNotification } from 'naive-ui';
39

10+
import type { MessagePayload, MessageType } from '~/models/message/message-type.model';
11+
12+
import { ExternaLinks } from '~/settings/external.links';
13+
import { useI18n } from '~/utils/i18n.utils';
14+
415
type NotificationApi = ReturnType<typeof useNotification>;
516
type MessageApi = ReturnType<typeof useMessage>;
617

@@ -24,4 +35,31 @@ export class NotificationService {
2435

2536
this.notification.error(option);
2637
}
38+
39+
static release(payload: MessagePayload<typeof MessageType.VersionUpdate>) {
40+
const i18n = useI18n('notification');
41+
const notification = NotificationService.notification.info({
42+
title: i18n('release_title'),
43+
description: `From ${payload.previousVersion} to ${payload.nextVersion}`,
44+
content: i18n('release_content'),
45+
meta: new Date(payload.date).toLocaleDateString(),
46+
duration: 10 * 1000,
47+
action: () =>
48+
h(
49+
NButton,
50+
{
51+
tertiary: true,
52+
type: 'info',
53+
onClick: () => {
54+
createTab({ url: ExternaLinks.release });
55+
notification.destroy();
56+
},
57+
},
58+
{
59+
default: () => i18n('release_notes'),
60+
},
61+
),
62+
});
63+
return notification;
64+
}
2765
}

src/settings/external.links.ts

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export const ExternaLinks = {
2323
support: 'https://github.com/dvcol/trakt-extension/issues',
2424
store: 'https://chrome.google.com/webstore/detail/pdodapikbijcfickiofjkjgkkmlcnbba',
2525
privacy: 'https://github.com/dvcol/trakt-extension/blob/main/PRIVACY.md',
26+
release: 'https://github.com/dvcol/trakt-extension/releases',
2627
} as const;
2728

2829
export const ResolveExternalLinks = {

src/stores/data/image.store.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { arrayMax, findClosestMatch } from '@dvcol/common-utils/common/math';
2+
import { getShortLocale } from '@dvcol/common-utils/common/navigator';
23
import { defineStore, storeToRefs } from 'pinia';
34

45
import { computed, reactive, type Ref, ref } from 'vue';
@@ -11,7 +12,6 @@ import { ErrorService } from '~/services/error.service';
1112
import { Logger } from '~/services/logger.service';
1213
import { TraktService } from '~/services/trakt.service';
1314
import { setStorageWrapper, storage } from '~/utils/browser/browser-storage.utils';
14-
import { getShortLocale } from '~/utils/browser/browser.utils';
1515
import { CachePrefix } from '~/utils/cache.utils';
1616
import { debounce } from '~/utils/debounce.utils';
1717
import { ErrorCount, type ErrorDictionary } from '~/utils/retry.utils';

src/stores/i18n.store.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { defineStore, storeToRefs } from 'pinia';
22
import { computed, ref } from 'vue';
33

4+
import type { BrowserI18nInput } from '@dvcol/web-extension-utils/chrome/i18n';
45
import type { Locale, Locales } from '~/models/i18n.model';
5-
import type { BrowserI18nInput } from '~/utils/browser/browser-i18n.utils';
66

77
export const useI18nStore = defineStore('i18n', () => {
88
const lang = ref<string>('en');

src/stores/settings/context-menu.store.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { computed, reactive, toRefs } from 'vue';
44

55
import { ContextMenuConstants, ContextMenuId, type ContextMenuIds } from '~/models/context/context-menu.model';
66
import { MessageType } from '~/models/message/message-type.model';
7-
import { runtime } from '~/utils/browser/browser-runtime.utils';
7+
import { sendMessage } from '~/utils/browser/browser-message.utils';
88
import { storage } from '~/utils/browser/browser-storage.utils';
99
import { debounce } from '~/utils/debounce.utils';
1010

@@ -24,7 +24,7 @@ export const useContextMenuStore = defineStore(ContextMenuConstants.Store, () =>
2424

2525
const saveState = debounce(async () => {
2626
await storage.local.set(ContextMenuConstants.LocalEnabled, enabled);
27-
await runtime?.sendMessage({ type: MessageType.ContextMenu, enabled });
27+
await sendMessage({ type: MessageType.ContextMenu, payload: enabled });
2828
}, 500);
2929

3030
const restoreState = async () => {

src/utils/browser/borwser-action.utils.ts

-1
This file was deleted.

src/utils/browser/browser-context.utils.ts

-9
This file was deleted.

src/utils/browser/browser-i18n.utils.ts

-32
This file was deleted.
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { onMessageEvent, sendMessageEvent } from '@dvcol/web-extension-utils/chrome/message';
2+
3+
import type { ChromeMessage, ChromeMessageListener, ChromeMessageOptions, ChromeResponsePayload } from '@dvcol/web-extension-utils/chrome/models';
4+
5+
import type { MessagePayload, MessageTypes } from '~/models/message/message-type.model';
6+
7+
export const onMessage = <
8+
R extends ChromeResponsePayload = ChromeResponsePayload,
9+
T extends MessageTypes = MessageTypes,
10+
P extends MessagePayload = MessagePayload<T>,
11+
>(
12+
types: T | T[],
13+
callback: ChromeMessageListener<T, P, R>,
14+
) => onMessageEvent<T, P, R>(callback, types);
15+
16+
export const sendMessage = async <
17+
T extends MessageTypes = MessageTypes,
18+
R extends ChromeResponsePayload = ChromeResponsePayload,
19+
P extends MessagePayload = MessagePayload<T>,
20+
>(
21+
message: ChromeMessage<T, P>,
22+
options?: ChromeMessageOptions,
23+
) => sendMessageEvent<T, P, R>(message, options);

src/utils/browser/browser-runtime.utils.ts

-4
This file was deleted.

src/utils/browser/browser.utils.ts

-11
This file was deleted.

0 commit comments

Comments
 (0)