Last active
November 25, 2019 18:29
-
-
Save Akryum/05964e81d09fb5088b7769cff15f5e7c to your computer and use it in GitHub Desktop.
Example of migration to Vue Function-based Component API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
import { isValidMultiName } from '@/util/folders' | |
import FOLDER_CURRENT from '@/graphql/folder/folderCurrent.gql' | |
import FOLDERS_FAVORITE from '@/graphql/folder/foldersFavorite.gql' | |
import FOLDER_OPEN from '@/graphql/folder/folderOpen.gql' | |
import FOLDER_OPEN_PARENT from '@/graphql/folder/folderOpenParent.gql' | |
import FOLDER_SET_FAVORITE from '@/graphql/folder/folderSetFavorite.gql' | |
import PROJECT_CWD_RESET from '@/graphql/project/projectCwdReset.gql' | |
import FOLDER_CREATE from '@/graphql/folder/folderCreate.gql' | |
const SHOW_HIDDEN = 'vue-ui.show-hidden-folders' | |
export default { | |
data () { | |
return { | |
loading: 0, | |
error: false, | |
editingPath: false, | |
editedPath: '', | |
folderCurrent: {}, | |
foldersFavorite: [], | |
showHidden: localStorage.getItem(SHOW_HIDDEN) === 'true', | |
showNewFolder: false, | |
newFolderName: '' | |
} | |
}, | |
apollo: { | |
folderCurrent: { | |
query: FOLDER_CURRENT, | |
fetchPolicy: 'network-only', | |
loadingKey: 'loading', | |
async result () { | |
await this.$nextTick() | |
this.$refs.folders.scrollTop = 0 | |
} | |
}, | |
foldersFavorite: FOLDERS_FAVORITE | |
}, | |
computed: { | |
newFolderValid () { | |
return isValidMultiName(this.newFolderName) | |
} | |
}, | |
watch: { | |
showHidden (value) { | |
if (value) { | |
localStorage.setItem(SHOW_HIDDEN, 'true') | |
} else { | |
localStorage.removeItem(SHOW_HIDDEN) | |
} | |
} | |
}, | |
beforeRouteLeave (to, from, next) { | |
if (to.matched.some(m => m.meta.needProject)) { | |
this.resetProjectCwd() | |
} | |
next() | |
}, | |
methods: { | |
async openFolder (path) { | |
this.editingPath = false | |
this.error = null | |
this.loading++ | |
try { | |
await this.$apollo.mutate({ | |
mutation: FOLDER_OPEN, | |
variables: { | |
path | |
}, | |
update: (store, { data: { folderOpen } }) => { | |
store.writeQuery({ query: FOLDER_CURRENT, data: { folderCurrent: folderOpen } }) | |
} | |
}) | |
} catch (e) { | |
this.error = e | |
} | |
this.loading-- | |
}, | |
async openParentFolder (folder) { | |
this.editingPath = false | |
this.error = null | |
this.loading++ | |
try { | |
await this.$apollo.mutate({ | |
mutation: FOLDER_OPEN_PARENT, | |
update: (store, { data: { folderOpenParent } }) => { | |
store.writeQuery({ query: FOLDER_CURRENT, data: { folderCurrent: folderOpenParent } }) | |
} | |
}) | |
} catch (e) { | |
this.error = e | |
} | |
this.loading-- | |
}, | |
async toggleFavorite () { | |
await this.$apollo.mutate({ | |
mutation: FOLDER_SET_FAVORITE, | |
variables: { | |
path: this.folderCurrent.path, | |
favorite: !this.folderCurrent.favorite | |
}, | |
update: (store, { data: { folderSetFavorite } }) => { | |
store.writeQuery({ query: FOLDER_CURRENT, data: { folderCurrent: folderSetFavorite } }) | |
let data = store.readQuery({ query: FOLDERS_FAVORITE }) | |
// TODO this is a workaround | |
// See: https://github.com/apollographql/apollo-client/issues/4031#issuecomment-433668473 | |
data = { | |
foldersFavorite: data.foldersFavorite.slice() | |
} | |
if (folderSetFavorite.favorite) { | |
data.foldersFavorite.push(folderSetFavorite) | |
} else { | |
const index = data.foldersFavorite.findIndex( | |
f => f.path === folderSetFavorite.path | |
) | |
index !== -1 && data.foldersFavorite.splice(index, 1) | |
} | |
store.writeQuery({ query: FOLDERS_FAVORITE, data }) | |
} | |
}) | |
}, | |
cwdChangedUpdate (previousResult, { subscriptionData }) { | |
return { | |
cwd: subscriptionData.data.cwd | |
} | |
}, | |
async openPathEdit () { | |
this.editedPath = this.folderCurrent.path | |
this.editingPath = true | |
await this.$nextTick() | |
this.$refs.pathInput.focus() | |
}, | |
submitPathEdit () { | |
this.openFolder(this.editedPath) | |
}, | |
refreshFolder () { | |
this.openFolder(this.folderCurrent.path) | |
}, | |
resetProjectCwd () { | |
this.$apollo.mutate({ | |
mutation: PROJECT_CWD_RESET | |
}) | |
}, | |
async createFolder () { | |
if (!this.newFolderValid) return | |
const result = await this.$apollo.mutate({ | |
mutation: FOLDER_CREATE, | |
variables: { | |
name: this.newFolderName | |
} | |
}) | |
this.openFolder(result.data.folderCreate.path) | |
this.newFolderName = '' | |
this.showNewFolder = false | |
}, | |
slicePath (path) { | |
const parts = [] | |
let startIndex = 0 | |
let index | |
const findSeparator = () => { | |
index = path.indexOf('/', startIndex) | |
if (index === -1) index = path.indexOf('\\', startIndex) | |
return index !== -1 | |
} | |
const addPart = index => { | |
const folder = path.substring(startIndex, index) | |
const slice = path.substring(0, index + 1) | |
parts.push({ | |
name: folder, | |
path: slice | |
}) | |
} | |
while (findSeparator()) { | |
addPart(index) | |
startIndex = index + 1 | |
} | |
if (startIndex < path.length) addPart(path.length) | |
return parts | |
} | |
} | |
} | |
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
import { useQuery, mutate } from 'vue-apollo' | |
import { nextTick, state, value, watch } from 'vue' | |
import { onBeforeRouteLeave } from 'vue-router' | |
import { isValidMultiName } from '@/util/folders' | |
import FOLDER_CURRENT from '@/graphql/folder/folderCurrent.gql' | |
import FOLDERS_FAVORITE from '@/graphql/folder/favoriteFolders.gql' | |
import FOLDER_OPEN from '@/graphql/folder/folderOpen.gql' | |
import FOLDER_OPEN_PARENT from '@/graphql/folder/folderOpenParent.gql' | |
import FOLDER_SET_FAVORITE from '@/graphql/folder/folderSetFavorite.gql' | |
import PROJECT_CWD_RESET from '@/graphql/project/projectCwdReset.gql' | |
import FOLDER_CREATE from '@/graphql/folder/folderCreate.gql' | |
const SHOW_HIDDEN = 'vue-ui.show-hidden-folders' | |
export default { | |
setup (props, { refs }) { | |
const { networkState } = useNetworkState() | |
// Folder | |
const { currentFolderData } = usecurrentFolderData(networkState) | |
const folderNavigationFeature = useFolderNavigation({ | |
networkState, | |
currentFolderData | |
refs, | |
}) | |
const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData) | |
const { showHiddenFolders } = useHiddenFolders() | |
const createFolderFeature = useCreateFolder(folderNavigationFeature.openFolder) | |
// Current working directory | |
const { updateOnCwdChanged } = useCwd() | |
// Utils | |
const { slicePath } = usePathUtils() | |
return { | |
networkState, | |
currentFolderData, | |
...folderNavigationFeature, | |
refreshFolder, | |
favoriteFolders, | |
toggleFavorite, | |
showHiddenFolders, | |
...createFolderFeature, | |
updateOnCwdChanged, | |
slicePath, | |
} | |
} | |
} | |
function useNetworkState () { | |
const networkState = state({ | |
loading: 0, | |
error: false, | |
}) | |
return { | |
networkState | |
} | |
} | |
function usecurrentFolderData (networkState) { | |
const currentFolderData = useQuery({ | |
query: FOLDER_CURRENT, | |
fetchPolicy: 'networkState-only', | |
networkState, | |
async result () { | |
await nextTick() | |
refs.folders.scrollTop = 0 | |
} | |
}, {}) | |
return { | |
currentFolderData | |
} | |
} | |
function useFolderNavigation ({ networkState, currentFolderData, refs }) { | |
// Path editing | |
const pathEditing = state({ | |
editingPath: false, | |
editedPath: '', | |
}) | |
async function openPathEdit () { | |
pathEditing.editedPath = currentFolderData.path | |
pathEditing.editingPath = true | |
await nextTick() | |
refs.pathInput.focus() | |
} | |
function submitPathEdit () { | |
openFolder(pathEditing.editedPath) | |
} | |
// Folder opening | |
const openFolder = async (path) => { | |
pathEditing.editingPath = false | |
networkState.error = null | |
networkState.loading++ | |
try { | |
await mutate({ | |
mutation: FOLDER_OPEN, | |
variables: { | |
path | |
}, | |
update: (store, { data: { folderOpen } }) => { | |
store.writeQuery({ query: FOLDER_CURRENT, data: { currentFolderData: folderOpen } }) | |
} | |
}) | |
} catch (e) { | |
networkState.error = e | |
} | |
networkState.loading-- | |
} | |
async function openParentFolder () { | |
pathEditing.editingPath = false | |
networkState.error = null | |
networkState.loading++ | |
try { | |
await mutate({ | |
mutation: FOLDER_OPEN_PARENT, | |
update: (store, { data: { folderOpenParent } }) => { | |
store.writeQuery({ query: FOLDER_CURRENT, data: { currentFolderData: folderOpenParent } }) | |
} | |
}) | |
} catch (e) { | |
networkState.error = e | |
} | |
networkState.loading-- | |
} | |
// Refresh | |
function refreshFolder () { | |
openFolder(currentFolderData.path) | |
} | |
return { | |
pathEditing, | |
openPathEdit, | |
submitPathEdit, | |
openFolder, | |
openParentFolder, | |
refreshFolder | |
} | |
} | |
function useFavoriteFolders (currentFolderData) { | |
const favoriteFolders = useQuery(FOLDERS_FAVORITE, []) | |
async function toggleFavorite () { | |
await mutate({ | |
mutation: FOLDER_SET_FAVORITE, | |
variables: { | |
path: currentFolderData.path, | |
favorite: !currentFolderData.favorite | |
}, | |
update: (store, { data: { folderSetFavorite } }) => { | |
store.writeQuery({ query: FOLDER_CURRENT, data: { currentFolderData: folderSetFavorite } }) | |
let data = store.readQuery({ query: FOLDERS_FAVORITE }) | |
// TODO this is a workaround | |
// See: https://github.com/apollographql/apollo-client/issues/4031#issuecomment-433668473 | |
data = { | |
favoriteFolders: data.favoriteFolders.slice() | |
} | |
if (folderSetFavorite.favorite) { | |
data.favoriteFolders.push(folderSetFavorite) | |
} else { | |
const index = data.favoriteFolders.findIndex( | |
f => f.path === folderSetFavorite.path | |
) | |
index !== -1 && data.favoriteFolders.splice(index, 1) | |
} | |
store.writeQuery({ query: FOLDERS_FAVORITE, data }) | |
} | |
}) | |
} | |
return { | |
favoriteFolders, | |
toggleFavorite | |
} | |
} | |
function useHiddenFolders () { | |
const showHiddenFolders = value(localStorage.getItem(SHOW_HIDDEN) === 'true') | |
watch(showHiddenFolders, value => { | |
if (value) { | |
localStorage.setItem(SHOW_HIDDEN, 'true') | |
} else { | |
localStorage.removeItem(SHOW_HIDDEN) | |
} | |
}, { lazy: true }) | |
return { | |
showHiddenFolders | |
} | |
} | |
function useCwd () { | |
async function resetProjectCwd () { | |
await mutate({ | |
mutation: PROJECT_CWD_RESET | |
}) | |
} | |
onBeforeRouteLeave((to, from, next) => { | |
if (to.matched.some(m => m.meta.needProject)) { | |
resetProjectCwd() | |
} | |
next() | |
}) | |
// Update apollo cache | |
const updateOnCwdChanged = (previousResult, { subscriptionData }) => { | |
return { | |
cwd: subscriptionData.data.cwd | |
} | |
} | |
return { | |
updateOnCwdChanged | |
} | |
} | |
function useCreateFolder (openFolder) { | |
const showNewFolder = value(false) | |
const newFolderName = value('') | |
const newFolderValid = computed(() => isValidMultiName(newFolderName.value)) | |
async function createFolder () { | |
if (!newFolderValid.value) return | |
const result = await mutate({ | |
mutation: FOLDER_CREATE, | |
variables: { | |
name: newFolderName.value | |
} | |
}) | |
openFolder(result.data.folderCreate.path) | |
newFolderName.value = '' | |
showNewFolder.value = false | |
} | |
return { | |
showNewFolder, | |
newFolderName, | |
newFolderValid, | |
createFolder | |
} | |
} | |
function usePathUtils () { | |
const slicePath = (path) => { | |
const parts = [] | |
let startIndex = 0 | |
let index | |
function findSeparator () { | |
index = path.indexOf('/', startIndex) | |
if (index === -1) index = path.indexOf('\\', startIndex) | |
return index !== -1 | |
} | |
const addPart = index => { | |
const folder = path.substring(startIndex, index) | |
const slice = path.substring(0, index + 1) | |
parts.push({ | |
name: folder, | |
path: slice | |
}) | |
} | |
while (findSeparator()) { | |
addPart(index) | |
startIndex = index + 1 | |
} | |
if (startIndex < path.length) addPart(path.length) | |
return parts | |
} | |
return { | |
slicePath | |
} | |
} | |
</script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
import { useQuery, mutate } from 'vue-apollo' | |
import { nextTick, state, value, watch } from 'vue' | |
import { onBeforeRouteLeave } from 'vue-router' | |
// Reusable functions not specific to this component | |
import { useNetworkState } from '@/functions/network' | |
import { usePathUtils } from '@/functions/path' | |
import { resetCwdOnLeave, useCwdUtils } from '@/functions/cwd' | |
// GraphQL | |
import FOLDER_CURRENT from '@/graphql/folder/folderCurrent.gql' | |
import FOLDERS_FAVORITE from '@/graphql/folder/favoriteFolders.gql' | |
import FOLDER_OPEN from '@/graphql/folder/folderOpen.gql' | |
import FOLDER_OPEN_PARENT from '@/graphql/folder/folderOpenParent.gql' | |
import FOLDER_SET_FAVORITE from '@/graphql/folder/folderSetFavorite.gql' | |
import PROJECT_CWD_RESET from '@/graphql/project/projectCwdReset.gql' | |
import FOLDER_CREATE from '@/graphql/folder/folderCreate.gql' | |
// Misc | |
import { isValidMultiName } from '@/util/folders' | |
const SHOW_HIDDEN = 'vue-ui.show-hidden-folders' | |
export default { | |
setup (props, { refs }) { | |
const { networkState } = useNetworkState() | |
// Folder | |
const { currentFolderData } = usecurrentFolderData(networkState) | |
const folderNavigationFeature = useFolderNavigation({ | |
networkState, | |
currentFolderData | |
refs, | |
}) | |
const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData) | |
const { showHiddenFolders } = useHiddenFolders() | |
const createFolderFeature = useCreateFolder(folderNavigation.openFolder) | |
// Current working directory | |
resetCwdOnLeave() | |
const { updateOnCwdChanged } = useCwdUtils() | |
// Utils | |
const { slicePath } = usePathUtils() | |
return { | |
networkState, | |
currentFolderData, | |
...folderNavigationFeature, | |
refreshFolder, | |
favoriteFolders, | |
toggleFavorite, | |
showHiddenFolders, | |
...createFolderFeature, | |
updateOnCwdChanged, | |
slicePath, | |
} | |
} | |
} | |
// Reusable functions specific to this component | |
export function usecurrentFolderData (networkState) { | |
const currentFolderData = useQuery({ | |
query: FOLDER_CURRENT, | |
fetchPolicy: 'networkState-only', | |
networkState, | |
async result () { | |
await nextTick() | |
refs.folders.scrollTop = 0 | |
} | |
}, {}) | |
return { | |
currentFolderData | |
} | |
export } | |
export function useFolderNavigation ({ networkState, currentFolderData, refs }) { | |
// Path editing | |
const pathEditing = state({ | |
editingPath: false, | |
editedPath: '', | |
}) | |
async function openPathEdit () { | |
pathEditing.editedPath = currentFolderData.path | |
pathEditing.editingPath = true | |
await nextTick() | |
refs.pathInput.focus() | |
} | |
function submitPathEdit () { | |
openFolder(pathEditing.editedPath) | |
} | |
// Folder opening | |
const openFolder = async (path) => { | |
pathEditing.editingPath = false | |
networkState.error = null | |
networkState.loading++ | |
try { | |
await mutate({ | |
mutation: FOLDER_OPEN, | |
variables: { | |
path | |
}, | |
update: (store, { data: { folderOpen } }) => { | |
store.writeQuery({ query: FOLDER_CURRENT, data: { currentFolderData: folderOpen } }) | |
} | |
}) | |
} catch (e) { | |
networkState.error = e | |
} | |
networkState.loading-- | |
} | |
async function openParentFolder () { | |
pathEditing.editingPath = false | |
networkState.error = null | |
networkState.loading++ | |
try { | |
await mutate({ | |
mutation: FOLDER_OPEN_PARENT, | |
update: (store, { data: { folderOpenParent } }) => { | |
store.writeQuery({ query: FOLDER_CURRENT, data: { currentFolderData: folderOpenParent } }) | |
} | |
}) | |
} catch (e) { | |
networkState.error = e | |
} | |
networkState.loading-- | |
} | |
// Refresh | |
function refreshFolder () { | |
openFolder(currentFolderData.path) | |
} | |
return { | |
pathEditing, | |
openPathEdit, | |
submitPathEdit, | |
openFolder, | |
openParentFolder, | |
refreshFolder | |
} | |
} | |
export function useFavoriteFolders (currentFolderData) { | |
const favoriteFolders = useQuery(FOLDERS_FAVORITE, []) | |
async function toggleFavorite () { | |
await mutate({ | |
mutation: FOLDER_SET_FAVORITE, | |
variables: { | |
path: currentFolderData.path, | |
favorite: !currentFolderData.favorite | |
}, | |
update: (store, { data: { folderSetFavorite } }) => { | |
store.writeQuery({ query: FOLDER_CURRENT, data: { currentFolderData: folderSetFavorite } }) | |
let data = store.readQuery({ query: FOLDERS_FAVORITE }) | |
// TODO this is a workaround | |
// See: https://github.com/apollographql/apollo-client/issues/4031#issuecomment-433668473 | |
data = { | |
favoriteFolders: data.favoriteFolders.slice() | |
} | |
if (folderSetFavorite.favorite) { | |
data.favoriteFolders.push(folderSetFavorite) | |
} else { | |
const index = data.favoriteFolders.findIndex( | |
f => f.path === folderSetFavorite.path | |
) | |
index !== -1 && data.favoriteFolders.splice(index, 1) | |
} | |
store.writeQuery({ query: FOLDERS_FAVORITE, data }) | |
} | |
}) | |
} | |
return { | |
favoriteFolders, | |
toggleFavorite | |
} | |
} | |
export function useHiddenFolders () { | |
const showHiddenFolders = value(localStorage.getItem(SHOW_HIDDEN) === 'true') | |
watch(showHiddenFolders, value => { | |
if (value) { | |
localStorage.setItem(SHOW_HIDDEN, 'true') | |
} else { | |
localStorage.removeItem(SHOW_HIDDEN) | |
} | |
}, { lazy: true }) | |
return { | |
showHiddenFolders | |
} | |
} | |
export function useCreateFolder (openFolder) { | |
const showNewFolder = value(false) | |
const newFolderName = value('') | |
const newFolderValid = computed(() => isValidMultiName(newFolderName.value)) | |
async function createFolder () { | |
if (!newFolderValid.value) return | |
const result = await mutate({ | |
mutation: FOLDER_CREATE, | |
variables: { | |
name: newFolderName.value | |
} | |
}) | |
openFolder(result.data.folderCreate.path) | |
newFolderName.value = '' | |
showNewFolder.value = false | |
} | |
return { | |
showNewFolder, | |
newFolderName, | |
newFolderValid, | |
createFolder | |
} | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I do that now too, the example above is pending some refactoring in vue-cli-ui. 😸