Skip to content

Instantly share code, notes, and snippets.

@Akryum
Last active June 25, 2019 11:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Akryum/6eff23ae9f7483d6b5151c26d18842c2 to your computer and use it in GitHub Desktop.
Save Akryum/6eff23ae9f7483d6b5151c26d18842c2 to your computer and use it in GitHub Desktop.
<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
})
},
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
},
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
}
}
}
</script>
<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/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 {
setup (props, { refs }) {
/* Network management */
const network = state({
loading: 0,
error: false,
})
/* Current folder */
const folderCurrrent = useQuery({
query: FOLDER_CURRENT,
fetchPolicy: 'network-only',
loadingKey: 'loading',
async result () {
await nextTick()
refs.folders.scrollTop = 0
}
}, {})
/* Editable path input in top toolbar */
const pathEditing = state({
editingPath: false,
editedPath: '',
})
const openPathEdit = async () => {
pathEditing.editedPath = folderCurrent.path
pathEditing.editingPath = true
await nextTick()
refs.pathInput.focus()
}
const submitPathEdit = () => {
openFolder(pathEditing.editedPath)
}
/* Opening folder */
const openFolder = async (path) => {
pathEditing.editingPath = false
network.error = null
network.loading++
try {
await mutate({
mutation: FOLDER_OPEN,
variables: {
path
},
update: (store, { data: { folderOpen } }) => {
store.writeQuery({ query: FOLDER_CURRENT, data: { folderCurrent: folderOpen } })
}
})
} catch (e) {
network.error = e
}
network.loading--
}
const openParentFolder = async (folder) => {
pathEditing.editingPath = false
network.error = null
network.loading++
try {
await mutate({
mutation: FOLDER_OPEN_PARENT,
update: (store, { data: { folderOpenParent } }) => {
store.writeQuery({ query: FOLDER_CURRENT, data: { folderCurrent: folderOpenParent } })
}
})
} catch (e) {
network.error = e
}
network.loading--
}
/* Refresh button */
const refreshFolder = () => {
openFolder(folderCurrent.path)
}
/* Favorite folders */
const foldersFavorite = useQuery(FOLDERS_FAVORITE, [])
const toggleFavorite = async () => {
await mutate({
mutation: FOLDER_SET_FAVORITE,
variables: {
path: folderCurrent.path,
favorite: !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 })
}
})
}
/* Hidden folders */
const showHidden = value(localStorage.getItem(SHOW_HIDDEN) === 'true')
watch(showHidden, value => {
if (value) {
localStorage.setItem(SHOW_HIDDEN, 'true')
} else {
localStorage.removeItem(SHOW_HIDDEN)
}
}, {
lazy: true,
})
/* Current working directory */
const resetProjectCwd = async () => {
await mutate({
mutation: PROJECT_CWD_RESET
})
}
onBeforeRouteLeave((to, from, next) => {
if (to.matched.some(m => m.meta.needProject)) {
resetProjectCwd()
}
next()
})
// Update apollo cache
const cwdChangedUpdate = (previousResult, { subscriptionData }) => {
return {
cwd: subscriptionData.data.cwd
}
}
/* Create folder */
const showNewFolder = value(false)
const newFolderName = value('')
const newFolderValid = computed(() => isValidMultiName(newFolderName.value))
const createFolder = async () => {
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
}
/* Path utils */
const 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
}
return {
network,
folderCurrent,
openFolder,
openParentFolder,
pathEditing,
openPathEdit,
submitPathEdit,
refreshFolder,
foldersFavorite,
toggleFavorite,
showHidden,
cwdChangedUpdate,
showNewFolder,
newFolderName,
newFolderValid,
createFolder,
slicePath,
}
}
}
</script>
<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/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 {
setup (props, { refs }) {
/* Network management */
const { network } = useNetworkState()
/* Current folder */
const { folderCurrent } = useFolderCurrent(network)
const {
/* Editable path input in top toolbar */
pathEditing,
openPathEdit,
submitPathEdit,
/* Folder opening */
openFolder,
openParentFolder,
/* Refresh */
refreshFolder
} = useFolderToolbar(network, refs, folderCurrent)
/* Favorite folders */
const { foldersFavorite, toggleFavorite } = useFavoriteFolders(folderCurrent)
/* Hidden folders */
const { showHidden } = useHiddenFolders()
/* Current working directory */
const { cwdChangedUpdate } = useCwd()
/* Create folder */
const {
showNewFolder,
newFolderName,
newFolderValid,
createFolder
} = useCreateFolder(openFolder)
/* Path utils */
const { slicePath } = usePathUtils()
return {
network,
folderCurrent,
pathEditing,
openPathEdit,
submitPathEdit,
openFolder,
openParentFolder,
refreshFolder,
foldersFavorite,
toggleFavorite,
showHidden,
cwdChangedUpdate,
showNewFolder,
newFolderName,
newFolderValid,
createFolder,
slicePath,
}
}
}
function useNetworkState () {
const network = state({
loading: 0,
error: false,
})
return {
network
}
}
function useFolderCurrent (networkState) {
const folderCurrent = useQuery({
query: FOLDER_CURRENT,
fetchPolicy: 'network-only',
networkState,
async result () {
await nextTick()
refs.folders.scrollTop = 0
}
}, {})
return {
folderCurrent
}
}
function useFolderToolbar (network, refs, folderCurrent) {
// Path editing
const pathEditing = state({
editingPath: false,
editedPath: '',
})
const openPathEdit = async () => {
pathEditing.editedPath = folderCurrent.path
pathEditing.editingPath = true
await nextTick()
refs.pathInput.focus()
}
const submitPathEdit = () => {
openFolder(pathEditing.editedPath)
}
// Folder opening
const openFolder = async (path) => {
pathEditing.editingPath = false
network.error = null
network.loading++
try {
await mutate({
mutation: FOLDER_OPEN,
variables: {
path
},
update: (store, { data: { folderOpen } }) => {
store.writeQuery({ query: FOLDER_CURRENT, data: { folderCurrent: folderOpen } })
}
})
} catch (e) {
network.error = e
}
network.loading--
}
const openParentFolder = async () => {
pathEditing.editingPath = false
network.error = null
network.loading++
try {
await mutate({
mutation: FOLDER_OPEN_PARENT,
update: (store, { data: { folderOpenParent } }) => {
store.writeQuery({ query: FOLDER_CURRENT, data: { folderCurrent: folderOpenParent } })
}
})
} catch (e) {
network.error = e
}
network.loading--
}
// Refresh
const refreshFolder = () => {
openFolder(folderCurrent.path)
}
return {
pathEditing,
openPathEdit,
submitPathEdit,
openFolder,
openParentFolder,
refreshFolder
}
}
function useFavoriteFolders (folderCurrent) {
const foldersFavorite = useQuery(FOLDERS_FAVORITE, [])
const toggleFavorite = async () => {
await mutate({
mutation: FOLDER_SET_FAVORITE,
variables: {
path: folderCurrent.path,
favorite: !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 })
}
})
}
return {
foldersFavorite,
toggleFavorite
}
}
function useHiddenFolders () {
const showHidden = value(localStorage.getItem(SHOW_HIDDEN) === 'true')
watch(showHidden, value => {
if (value) {
localStorage.setItem(SHOW_HIDDEN, 'true')
} else {
localStorage.removeItem(SHOW_HIDDEN)
}
}, {
lazy: true,
})
return {
showHidden
}
}
function useCwd () {
const resetProjectCwd = async () => {
await mutate({
mutation: PROJECT_CWD_RESET
})
}
onBeforeRouteLeave((to, from, next) => {
if (to.matched.some(m => m.meta.needProject)) {
resetProjectCwd()
}
next()
})
// Update apollo cache
const cwdChangedUpdate = (previousResult, { subscriptionData }) => {
return {
cwd: subscriptionData.data.cwd
}
}
return {
cwdChangedUpdate
}
}
function useCreateFolder (openFolder) {
const showNewFolder = value(false)
const newFolderName = value('')
const newFolderValid = computed(() => isValidMultiName(newFolderName.value))
const createFolder = async () => {
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
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
}
return {
slicePath
}
}
</script>
<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/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 {
setup (props, { refs }) {
/* Network management */
const { network } = useNetworkState()
/* Current folder */
const { folderCurrent } = useFolderCurrent(network)
const folderToolbar = useFolderToolbar(network, refs, folderCurrent)
/* Favorite folders */
const { foldersFavorite, toggleFavorite } = useFavoriteFolders(folderCurrent)
/* Hidden folders */
const { showHidden } = useHiddenFolders()
/* Current working directory */
const { cwdChangedUpdate } = useCwd()
/* Create folder */
const createFolder = useCreateFolder(openFolder)
/* Path utils */
const { slicePath } = usePathUtils()
return {
network,
folderCurrent,
...folderToolbar,
refreshFolder,
foldersFavorite,
toggleFavorite,
showHidden,
cwdChangedUpdate,
...createFolder,
slicePath,
}
}
}
function useNetworkState () {
const network = state({
loading: 0,
error: false,
})
return {
network
}
}
function useFolderCurrent (networkState) {
const folderCurrent = useQuery({
query: FOLDER_CURRENT,
fetchPolicy: 'network-only',
networkState,
async result () {
await nextTick()
refs.folders.scrollTop = 0
}
}, {})
return {
folderCurrent
}
}
function useFolderToolbar (network, refs, folderCurrent) {
// Path editing
const pathEditing = state({
editingPath: false,
editedPath: '',
})
const openPathEdit = async () => {
pathEditing.editedPath = folderCurrent.path
pathEditing.editingPath = true
await nextTick()
refs.pathInput.focus()
}
const submitPathEdit = () => {
openFolder(pathEditing.editedPath)
}
// Folder opening
const openFolder = async (path) => {
pathEditing.editingPath = false
network.error = null
network.loading++
try {
await mutate({
mutation: FOLDER_OPEN,
variables: {
path
},
update: (store, { data: { folderOpen } }) => {
store.writeQuery({ query: FOLDER_CURRENT, data: { folderCurrent: folderOpen } })
}
})
} catch (e) {
network.error = e
}
network.loading--
}
const openParentFolder = async () => {
pathEditing.editingPath = false
network.error = null
network.loading++
try {
await mutate({
mutation: FOLDER_OPEN_PARENT,
update: (store, { data: { folderOpenParent } }) => {
store.writeQuery({ query: FOLDER_CURRENT, data: { folderCurrent: folderOpenParent } })
}
})
} catch (e) {
network.error = e
}
network.loading--
}
// Refresh
const refreshFolder = () => {
openFolder(folderCurrent.path)
}
return {
pathEditing,
openPathEdit,
submitPathEdit,
openFolder,
openParentFolder,
refreshFolder
}
}
function useFavoriteFolders (folderCurrent) {
const foldersFavorite = useQuery(FOLDERS_FAVORITE, [])
const toggleFavorite = async () => {
await mutate({
mutation: FOLDER_SET_FAVORITE,
variables: {
path: folderCurrent.path,
favorite: !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 })
}
})
}
return {
foldersFavorite,
toggleFavorite
}
}
function useHiddenFolders () {
const showHidden = value(localStorage.getItem(SHOW_HIDDEN) === 'true')
watch(showHidden, value => {
if (value) {
localStorage.setItem(SHOW_HIDDEN, 'true')
} else {
localStorage.removeItem(SHOW_HIDDEN)
}
}, {
lazy: true,
})
return {
showHidden
}
}
function useCwd () {
const resetProjectCwd = async () => {
await mutate({
mutation: PROJECT_CWD_RESET
})
}
onBeforeRouteLeave((to, from, next) => {
if (to.matched.some(m => m.meta.needProject)) {
resetProjectCwd()
}
next()
})
// Update apollo cache
const cwdChangedUpdate = (previousResult, { subscriptionData }) => {
return {
cwd: subscriptionData.data.cwd
}
}
return {
cwdChangedUpdate
}
}
function useCreateFolder (openFolder) {
const showNewFolder = value(false)
const newFolderName = value('')
const newFolderValid = computed(() => isValidMultiName(newFolderName.value))
const createFolder = async () => {
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
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
}
return {
slicePath
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment