From 5bd89047b28f2c1a51a6cecc1736089cbc0f1fc2 Mon Sep 17 00:00:00 2001 From: Frank Noirot Date: Fri, 4 Oct 2024 16:51:06 -0400 Subject: [PATCH] Add logic to navigate out from deleted or renamed project --- src/components/ProjectsContextProvider.tsx | 60 ++++++++++++++++--- src/machines/projectsMachine.ts | 69 +++++++++++++++------- 2 files changed, 100 insertions(+), 29 deletions(-) diff --git a/src/components/ProjectsContextProvider.tsx b/src/components/ProjectsContextProvider.tsx index e90ecf963..b4d3b0620 100644 --- a/src/components/ProjectsContextProvider.tsx +++ b/src/components/ProjectsContextProvider.tsx @@ -7,7 +7,7 @@ import { createContext, useEffect, useState } from 'react' import { Actor, AnyStateMachine, fromPromise, Prop, StateFrom } from 'xstate' import { useLspContext } from './LspProvider' import toast from 'react-hot-toast' -import { useNavigate } from 'react-router-dom' +import { useLocation, useNavigate } from 'react-router-dom' import { PATHS } from 'lib/paths' import { createNewProjectDirectory, @@ -38,6 +38,7 @@ export const ProjectsContextProvider = ({ children: React.ReactNode }) => { const navigate = useNavigate() + const location = useLocation() const { commandBarSend } = useCommandsContext() const { onProjectOpen } = useLspContext() const { @@ -84,17 +85,49 @@ export const ProjectsContextProvider = ({ const newPathName = `${PATHS.FILE}/${encodeURIComponent( projectPath )}` - console.log('navigating to', newPathName) - console.log('defaultDirectory is', context.defaultDirectory) navigate(newPathName) } }, + navigateToProjectIfNeeded: ({ event }) => { + console.log('navigateToProjectIfNeeded', event) + if ( + event.type.startsWith('xstate.done.actor.') && + 'output' in event + ) { + const isInAProject = location.pathname.startsWith(PATHS.FILE) + const isInDeletedProject = + event.type === 'xstate.done.actor.delete-project' && + isInAProject && + decodeURIComponent(location.pathname).includes(event.output.name) + if (isInDeletedProject) { + navigate(PATHS.HOME) + return + } + + const isInRenamedProject = + event.type === 'xstate.done.actor.rename-project' && + isInAProject && + decodeURIComponent(location.pathname).includes( + event.output.oldName + ) + console.log('isInRenamedProject', isInRenamedProject) + if (isInRenamedProject) { + const newPathName = location.pathname.replace( + encodeURIComponent(event.output.oldName), + encodeURIComponent(event.output.newName) + ) + navigate(newPathName) + return + } + } + }, toastSuccess: ({ event }) => toast.success( ('data' in event && typeof event.data === 'string' && event.data) || ('output' in event && - typeof event.output === 'string' && - event.output) || + 'message' in event.output && + typeof event.output.message === 'string' && + event.output.message) || '' ), toastError: ({ event }) => @@ -122,7 +155,9 @@ export const ProjectsContextProvider = ({ await createNewProjectDirectory(name) - return `Successfully created "${name}"` + return { + message: `Successfully created "${name}"`, + } }), renameProject: fromPromise(async ({ input }) => { const { @@ -134,7 +169,7 @@ export const ProjectsContextProvider = ({ } = input let name = newName ? newName : defaultProjectName if (doesProjectNameNeedInterpolated(name)) { - const nextIndex = await getNextProjectIndex(name, projects) + const nextIndex = getNextProjectIndex(name, projects) name = interpolateProjectNameWithIndex(name, nextIndex) } @@ -142,7 +177,11 @@ export const ProjectsContextProvider = ({ window.electron.path.join(defaultDirectory, oldName), name ) - return `Successfully renamed "${oldName}" to "${name}"` + return { + message: `Successfully renamed "${oldName}" to "${name}"`, + oldName: oldName, + newName: name, + } }), deleteProject: fromPromise(async ({ input }) => { await window.electron.rm( @@ -151,7 +190,10 @@ export const ProjectsContextProvider = ({ recursive: true, } ) - return `Successfully deleted "${input.name}"` + return { + message: `Successfully deleted "${input.name}"`, + name: input.name, + } }), }, guards: { diff --git a/src/machines/projectsMachine.ts b/src/machines/projectsMachine.ts index 63bb675ba..971c75b7c 100644 --- a/src/machines/projectsMachine.ts +++ b/src/machines/projectsMachine.ts @@ -12,14 +12,35 @@ export const projectsMachine = setup({ events: {} as | { type: 'Read projects'; data: {} } | { type: 'Open project'; data: ProjectsCommandSchema['Open project'] } - | { type: 'Rename project'; data: ProjectsCommandSchema['Rename project'] } - | { type: 'Create project'; data: ProjectsCommandSchema['Create project'] } - | { type: 'Delete project'; data: ProjectsCommandSchema['Delete project'] } + | { + type: 'Rename project' + data: ProjectsCommandSchema['Rename project'] + } + | { + type: 'Create project' + data: ProjectsCommandSchema['Create project'] + } + | { + type: 'Delete project' + data: ProjectsCommandSchema['Delete project'] + } | { type: 'navigate'; data: { name: string } } | { type: 'xstate.done.actor.read-projects' output: Project[] } + | { + type: 'xstate.done.actor.delete-project' + output: { message: string; name: string } + } + | { + type: 'xstate.done.actor.create-project' + output: { message: string } + } + | { + type: 'xstate.done.actor.rename-project' + output: { message: string; oldName: string; newName: string } + } | { type: 'assign'; data: { [key: string]: any } }, input: {} as { projects: Project[] @@ -30,16 +51,20 @@ export const projectsMachine = setup({ actions: { setProjects: assign({ projects: ({ context, event }) => - 'output' in event ? event.output : context.projects, + 'output' in event && Array.isArray(event.output) + ? event.output + : context.projects, }), toastSuccess: () => {}, toastError: () => {}, navigateToProject: () => {}, + navigateToProjectIfNeeded: () => {}, }, actors: { readProjects: fromPromise(() => Promise.resolve([] as Project[])), - createProject: fromPromise((_: { input: { name: string, projects: Project[] } }) => - Promise.resolve('') + createProject: fromPromise( + (_: { input: { name: string; projects: Project[] } }) => + Promise.resolve({ message: '' }) ), renameProject: fromPromise( (_: { @@ -50,24 +75,32 @@ export const projectsMachine = setup({ defaultDirectory: string projects: Project[] } - }) => Promise.resolve('') + }) => + Promise.resolve({ + message: '', + oldName: '', + newName: '', + }) ), deleteProject: fromPromise( (_: { input: { defaultDirectory: string; name: string } }) => - Promise.resolve('') + Promise.resolve({ + message: '', + name: '', + }) ), }, guards: { 'Has at least 1 project': () => false, }, }).createMachine({ - /** @xstate-layout N4IgpgJg5mDOIC5QAkD2BbMACdBDAxgBYCWAdmAMS6yzFSkDaADALqKgAOqtALsaqXYgAnogC0ADgDsAOgCM0gEwTFAVgBsitaonqANCAAeiNdJkSALIqYBOGzoDMcm+oC+rg2kw4CJcjORqLFJULA4AJ1QAKzB8HlgKACUwXAgwyJi42GY2JBAuXn5BPOMEB01zKQcLZwVVOQsmJlUDUQRpWSYtGokNG0UFB3dPDGw8IjIwAKCQ9OjY+IoAYXCUnmwI+bicoQLiPgEhUql1WQsJBpsVFXVVHVbEGwsHGSYHaylVJgt1OXUbIYeEBeMa+SbTWBzTKLZKpKELbKsXbcfZFI6IdROGRaLQOJgSCQuWz6ESPAHY5RSKnVN4A4bA0Y+Cb+QKQzbQhLJUi4bzshY7PJ7A7FUDHVSdaqqBwOK6KKr9B4IdTfGRfNRSOQnWxyLr0kFMvxTVnwrLLVa4dYmngCzgo4XohAnRTydSEwl3JwDCyKywSVUatQODRyHESPWM8aGiFWhIAETAABswJa+dskYK7WiSogTn6HE6LKofkWmCS2lIfjILFJdMoVP0Q1Jw95I+DjanFgB5DhgUhWm35TOHbNlKpVqm++rPapPH1yVSvX6KTGYhoVxTN0HMqYrNZkKBWigQARTMgAN1QAGspvhzesxB2B0Ks6KTIoLDZsZ65DLMUwpDYipSP+2LAZ8QbSK6ig2JuBrgruFr7oeYDhJE4QyBwCYWgAZqg4ToDIt5rGAD4ZPy6a2oUw6vgg1hFq8Vh2BI+IaGoQEgXK-5SjoubQbBrb+FyPJIR2R4njI55XlMqzcpgpFbNaFGDlRIpGIgDTVK8NghjYTA6uUigOIqzxyFWyjvIGAI1vm-FgoJvbCaQB6iShaEYVhPC4fhMgyTyJGPkpz7UWpCAhgMMhSHWdzvh+bxlogJlmRIFlSlZyVNkC+oCVM8ZJnwTmHse-iSdeMgQImyb+WRaa5JRqLBaUgwLv8GqEuo6jVv03qkrRH7Ypi9S9A0UrVrZ24yLlyYidVPAUK5eHuTheEEeVeVVQpT5DqpjXii83zVGoTz-ioLQ9e+n7LkGdTDdUkVjVGsIQNNCkJEVp6kBepXmhA8kcptKkOu+zqpecNhUh1H4Aoqt2Lk4fyanIiNuJlEZ2VMj3PRyYnFR9Uk+SkP0dtkci1cp9XbeIDRMC6yoqBWpY6GxPUw6WeKnH80GXPd4IYwVRNzahC2YUt3nfb9CL-eTDpiD+1P9BqGp3JozinW0AyftIzQ6FYro6huKMtmjMjdr2mMLBQkv2iOMsVlWNQaP8eKFqogE9VcC6RcoVi9J8WvuECITlfAeRZWjyIA9bOJ2-O7UAt8dyu20NsWDI+aFponxPF73MsjMoRE+HUsjmDryGcxVw6lTzSKi7fo-lU3y6F1yMjIb43tjNwd1VbNEOLoMh2JdCi6Tovyq4gtfyPmTtN++vw5zud5m3Ehc9yFYULjqqjQU3-y4oqummdYunMdY6p3AvMhCegy88KvL7r+drwNFYffaQC9iKsqC7aYW0qWMqBochL6TXys5Ga98GrqX+NTaCVRLAAn+JiRQX9EbmBlM4Cs04rgZVbluB6BNb5dzJmvUo0EXjtWlDUYCIY-zj3aC8ZiyVngWGrMxKUgI8FwX8CbUgt9IEUwQGIRoqdbh-ClASJodYD4lzlASRo2l0pPH9q4IAA */ + /** @xstate-layout N4IgpgJg5mDOIC5QAkD2BbMACdBDAxgBYCWAdmAMS6yzFSkDaADALqKgAOqtALsaqXYgAHogAsAJgA0IAJ6IAjBIkA2AHQAOCUw0qNkjQE4xYjQF8zMtJhwES5NcmpZSqLBwBOqAFZh8PWAoAJTBcCHcvX39YZjYkEC5efkF40QQFFQBmAHY1Qwz9QwBWU0NMrRl5BGyxBTUVJlVM01rtBXNLEGtsPCIyMEdnVwifPwCKAGEPUJ5sT1H-WKFE4j4BITSMzMzNIsyJDSZMhSYmFWzKxAkTNSYxIuU9zOKT7IsrDB67fsHYEajxiEwv8xjFWMtuKtkhsrpJboZsioincFMdTIjLggVGJ1GImMVMg0JISjEV3l1PrY+g4nH95gDAiFSLgbPSxkt4is1ilQGlrhJ4YjkbU0RoMXJEIYkWoikV8hJinjdOdyd0qfYBrSQdFJtNcLNtTwOZxIdyYQh+YKkSjReKqqYBQoEQpsgiSi9MqrKb0Nb9DYEACJgAA2YANbMW4M5puhqVhAvxQptCnRKkxCleuw0Gm2+2aRVRXpsPp+Woj4wA8hwwKRDcaEjH1nGLXDE9aRSmxWmJVipWocmdsbL8kxC501SWHFMZmQoIaKBABAMyAA3VAAawG+D1swAtOX61zY7zENlEWoMkoatcdPoipjCWIZRIirozsPiYYi19qQNp-rZ3nMAPC8Dw1A4YN9QAM1QDx0DUbcZjAfdInZKMTSSJsT2qc9Lwka8lTvTFTB2WUMiyQwc3yPRv3VH4mRZQDywXJc1FXDcBmmZlMBQhYjXQhtMJ5ERT1wlQr0kQj7kxKiZTxM5s2zbQEVoycBgY9AmNQ-wKGA0DwMgngYLgtQuJZZCDwEo8sJEnD1Dwgjb2kntig0GUkWVfZDEMfFVO+Bwg1DPhSDnZjFwcdjNzUCAQzDCztP4uIMKhGy0jPezxPwySnPvHsTjlPIhyOHRsnwlM-N-NRArDLS+N0kDYIM6DYPgmKgvivjD0bYS+VbBF21RTs7UUUcimfRpXyYRF8LFCrfSBCBaoZFiItINcor1CBeIZLqhPNdKL0yxzs2cqoNDqdpSo0EoSoLOb6NCRaQv9FblzWjjTMe7bQQYBQksElKesUMRjFubRMllCHsm2a5MVldRDBfFpmj0IpxPuhwFqW0F6v0iDmpMzbvuiXbAfNFNQcaI5IaKaH9jETFsUMNRVDxOU5TxBULE6VwYvgeIJ38sAIT25td27KpdzG7yZeho5slHVmMc1IY3HLfnkrNZt2hOW5smRCQM2uhQHkZ6VtkRBFnmu0qFGVv11ZFsnm0kdN8QFJVjlUPZ9co+3-2C0KEqdrXsJMJ8ryc86iUyYiCvxFNzldb3jHtjTsf8EPj1ssQchZlR8jR5EmDRrIGZcuF7maF1aZtslx29IWqtiwPDSz1LxDxepnlOfYDghp03eyOpngzXuYdHNPHozgJ26B9IXR2cTvP0BVkSRXKqgLtyq8OfQcXOwlubMIA */ id: 'Home machine', initial: 'Reading projects', context: ({ input }) => ({ - ...input + ...input, }), on: { @@ -109,7 +142,9 @@ export const projectsMachine = setup({ }, 'Open project': { - target: 'Opening project', + target: 'Reading projects', + actions: 'navigateToProject', + reenter: true, }, }, }, @@ -133,7 +168,7 @@ export const projectsMachine = setup({ onDone: [ { target: 'Reading projects', - actions: ['toastSuccess'], + actions: ['toastSuccess', 'navigateToProject'], }, ], onError: [ @@ -171,7 +206,7 @@ export const projectsMachine = setup({ onDone: [ { target: '#Home machine.Reading projects', - actions: ['toastSuccess'], + actions: ['toastSuccess', "navigateToProjectIfNeeded"], }, ], onError: [ @@ -202,7 +237,7 @@ export const projectsMachine = setup({ }, onDone: [ { - actions: ['toastSuccess'], + actions: ['toastSuccess', 'navigateToProjectIfNeeded'], target: '#Home machine.Reading projects', }, ], @@ -236,11 +271,5 @@ export const projectsMachine = setup({ ], }, }, - - 'Opening project': { - entry: ['navigateToProject'], - - always: "Reading projects" - }, }, })