From: Eduardo San Martin Morote Date: Mon, 31 May 2021 10:40:57 +0000 (+0200) Subject: refactor(devtools): split code X-Git-Tag: v2.0.0-beta.1~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5e90bdeed9b03177a6876d130286008ecc6194dc;p=thirdparty%2Fvuejs%2Fpinia.git refactor(devtools): split code --- diff --git a/src/devtools/actions.ts b/src/devtools/actions.ts new file mode 100644 index 00000000..2968389f --- /dev/null +++ b/src/devtools/actions.ts @@ -0,0 +1,108 @@ +import { Pinia } from '../rootStore' +import { saveAs } from 'file-saver' +import { toastMessage } from './utils' + +export function checkClipboardAccess() { + if (!('clipboard' in navigator)) { + toastMessage(`Your browser doesn't support the Clipboard API`, 'error') + return true + } +} + +function checkNotFocusedError(error: Error) { + if (error.message.toLowerCase().includes('document is not focused')) { + toastMessage( + 'You need to activate the "Emulate a focused page" setting in the "Rendering" panel of devtools.', + 'warn' + ) + return true + } +} + +export async function actionGlobalCopyState(pinia: Pinia) { + if (checkClipboardAccess()) return + try { + await navigator.clipboard.writeText(JSON.stringify(pinia.state.value)) + toastMessage('Global state copied to clipboard.') + } catch (error) { + if (checkNotFocusedError(error)) return + toastMessage( + `Failed to serialize the state. Check the console for more details.`, + 'error' + ) + console.error(error) + } +} + +export async function actionGlobalPasteState(pinia: Pinia) { + if (checkClipboardAccess()) return + try { + pinia.state.value = JSON.parse(await navigator.clipboard.readText()) + toastMessage('Global state pasted from clipboard.') + } catch (error) { + if (checkNotFocusedError(error)) return + toastMessage( + `Failed to deserialize the state from clipboard. Check the console for more details.`, + 'error' + ) + console.error(error) + } +} + +export async function actionGlobalSaveState(pinia: Pinia) { + try { + saveAs( + new Blob([JSON.stringify(pinia.state.value)], { + type: 'text/plain;charset=utf-8', + }), + 'pinia-state.json' + ) + } catch (error) { + toastMessage( + `Failed to export the state as JSON. Check the console for more details.`, + 'error' + ) + console.error(error) + } +} + +let fileInput: HTMLInputElement | undefined +function getFileOpener() { + if (!fileInput) { + fileInput = document.createElement('input') + fileInput.type = 'file' + fileInput.accept = '.json' + } + + function openFile(): Promise { + return new Promise((resolve, reject) => { + fileInput!.onchange = async () => { + const files = fileInput!.files + if (!files) return resolve(null) + const file = files.item(0) + if (!file) return resolve(null) + return resolve({ text: await file.text(), file }) + } + fileInput!.oncancel = () => resolve(null) + fileInput!.click() + }) + } + return openFile +} + +export async function actionGlobalOpenStateFile(pinia: Pinia) { + try { + const open = await getFileOpener() + const result = await open() + if (!result) return + const { text, file } = result + pinia.state.value = JSON.parse(text) + toastMessage(`Global state imported from "${file.name}".`) + } catch (error) { + toastMessage( + `Failed to export the state as JSON. Check the console for more details.`, + 'error' + ) + console.error(error) + } +} diff --git a/src/devtools/plugin.ts b/src/devtools/plugin.ts index 5f686013..330ebafa 100644 --- a/src/devtools/plugin.ts +++ b/src/devtools/plugin.ts @@ -1,6 +1,6 @@ import { setupDevtoolsPlugin, TimelineEvent } from '@vue/devtools-api' import { App, ComponentPublicInstance } from 'vue' -import { Pinia, PiniaPluginContext, setActivePinia } from '../rootStore' +import { PiniaPluginContext, setActivePinia } from '../rootStore' import { Store, GettersTree, @@ -8,6 +8,12 @@ import { StateTree, ActionsTree, } from '../types' +import { + actionGlobalCopyState, + actionGlobalPasteState, + actionGlobalSaveState, + actionGlobalOpenStateFile, +} from './actions' import { formatDisplay, formatEventData, @@ -15,7 +21,7 @@ import { formatStoreForInspectorState, formatStoreForInspectorTree, } from './formatting' -import { saveAs } from 'file-saver' +import { toastMessage } from './utils' /** * Registered stores used for devtools. @@ -30,112 +36,7 @@ const componentStateTypes: string[] = [] const MUTATIONS_LAYER_ID = 'pinia:mutations' const INSPECTOR_ID = 'pinia' -function checkClipboardAccess() { - if (!('clipboard' in navigator)) { - toastMessage(`Your browser doesn't support the Clipboard API`, 'error') - return true - } -} - -function checkNotFocusedError(error: Error) { - if (error.message.toLowerCase().includes('document is not focused')) { - toastMessage( - 'You need to activate the "Emulate a focused page" setting in the "Rendering" panel of devtools.', - 'warn' - ) - return true - } -} - -async function actionGlobalCopyState(pinia: Pinia) { - if (checkClipboardAccess()) return - try { - await navigator.clipboard.writeText(JSON.stringify(pinia.state.value)) - toastMessage('Global state copied to clipboard.') - } catch (error) { - if (checkNotFocusedError(error)) return - toastMessage( - `Failed to serialize the state. Check the console for more details.`, - 'error' - ) - console.error(error) - } -} - -async function actionGlobalPasteState(pinia: Pinia) { - if (checkClipboardAccess()) return - try { - pinia.state.value = JSON.parse(await navigator.clipboard.readText()) - toastMessage('Global state pasted from clipboard.') - } catch (error) { - if (checkNotFocusedError(error)) return - toastMessage( - `Failed to deserialize the state from clipboard. Check the console for more details.`, - 'error' - ) - console.error(error) - } -} - -async function actionGlobalSaveState(pinia: Pinia) { - try { - saveAs( - new Blob([JSON.stringify(pinia.state.value)], { - type: 'text/plain;charset=utf-8', - }), - 'pinia-state.json' - ) - } catch (error) { - toastMessage( - `Failed to export the state as JSON. Check the console for more details.`, - 'error' - ) - console.error(error) - } -} - -let fileInput: HTMLInputElement | undefined -function getFileOpener() { - if (!fileInput) { - fileInput = document.createElement('input') - fileInput.type = 'file' - fileInput.accept = '.json' - } - - function openFile(): Promise { - return new Promise((resolve, reject) => { - fileInput!.onchange = async () => { - const files = fileInput!.files - if (!files) return resolve(null) - const file = files.item(0) - if (!file) return resolve(null) - return resolve({ text: await file.text(), file }) - } - fileInput!.oncancel = () => resolve(null) - fileInput!.click() - }) - } - return openFile -} - -async function actionGlobalOpenStateFile(pinia: Pinia) { - try { - const open = await getFileOpener() - const result = await open() - if (!result) return - const { text, file } = result - pinia.state.value = JSON.parse(text) - toastMessage(`Global state imported from "${file.name}".`) - } catch (error) { - toastMessage( - `Failed to export the state as JSON. Check the console for more details.`, - 'error' - ) - console.error(error) - } -} - -export function addDevtools(app: App, store: Store) { +function addDevtools(app: App, store: Store) { // TODO: we probably need to ensure the latest version of the store is kept: // without effectScope, multiple stores will be created and will have a // limited lifespan for getters. @@ -493,26 +394,3 @@ export function devtoolsPlugin< return { ...wrappedActions } } - -/** - * Shows a toast or console.log - * - * @param message - message to log - * @param type - different color of the tooltip - */ -function toastMessage( - message: string, - type?: 'normal' | 'error' | 'warn' | undefined -) { - const piniaMessage = '🍍 ' + message - - if (typeof __VUE_DEVTOOLS_TOAST__ === 'function') { - __VUE_DEVTOOLS_TOAST__(piniaMessage, type) - } else if (type === 'error') { - console.error(piniaMessage) - } else if (type === 'warn') { - console.warn(piniaMessage) - } else { - console.log(piniaMessage) - } -} diff --git a/src/devtools/utils.ts b/src/devtools/utils.ts new file mode 100644 index 00000000..bb577f61 --- /dev/null +++ b/src/devtools/utils.ts @@ -0,0 +1,22 @@ +/** + * Shows a toast or console.log + * + * @param message - message to log + * @param type - different color of the tooltip + */ +export function toastMessage( + message: string, + type?: 'normal' | 'error' | 'warn' | undefined +) { + const piniaMessage = '🍍 ' + message + + if (typeof __VUE_DEVTOOLS_TOAST__ === 'function') { + __VUE_DEVTOOLS_TOAST__(piniaMessage, type) + } else if (type === 'error') { + console.error(piniaMessage) + } else if (type === 'warn') { + console.warn(piniaMessage) + } else { + console.log(piniaMessage) + } +}