Skip to content

Commit

Permalink
Merge pull request #263 from sasjs/ctrl-save
Browse files Browse the repository at this point in the history
feat: add the functionality of saving file by ctrl + s in editor
  • Loading branch information
sabhas authored Aug 25, 2022
2 parents e63eaa5 + bce83cb commit 8b8739a
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 56 deletions.
2 changes: 1 addition & 1 deletion web/src/components/filePathInputModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const FilePathInputModal = ({
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value

const specialChars = /[`!@#$%^&*()_+\-=[\]{};':"\\|,<>?~]/
const specialChars = /[`!@#$%^&*()+\-=[\]{};':"\\|,<>?~]/
const fileExtension = /\.(exe|sh|htaccess)$/i

if (specialChars.test(value)) {
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/nameInputModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const NameInputModal = ({
const value = event.target.value

const folderNameRegex = /[`!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~]/
const fileNameRegex = /[`!@#$%^&*()_+\-=[\]{};':"\\|,<>/?~]/
const fileNameRegex = /[`!@#$%^&*()+\-=[\]{};':"\\|,<>/?~]/
const fileNameExtensionRegex = /.(exe|sh|htaccess)$/i

const specialChars = isFolder ? folderNameRegex : fileNameRegex
Expand Down
138 changes: 84 additions & 54 deletions web/src/containers/Studio/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import React, {
useEffect,
useRef,
useState,
useContext
useContext,
useCallback
} from 'react'
import axios from 'axios'

Expand Down Expand Up @@ -139,6 +140,88 @@ const SASjsEditor = ({
prevFileContent !== fileContent && !!selectedFilePath
)

const saveFile = useCallback(
(filePath?: string) => {
setIsLoading(true)

if (filePath) {
filePath = filePath.startsWith('/') ? filePath : `/${filePath}`
}

const formData = new FormData()

const stringBlob = new Blob([fileContent], { type: 'text/plain' })
formData.append('file', stringBlob)
formData.append('filePath', filePath ?? selectedFilePath)

const axiosPromise = filePath
? axios.post('/SASjsApi/drive/file', formData)
: axios.patch('/SASjsApi/drive/file', formData)

axiosPromise
.then(() => {
if (filePath && fileContent === prevFileContent) {
// when fileContent and prevFileContent is same,
// callback function in setPrevFileContent method is not called
// because behind the scene useEffect hook is being used
// for calling callback function, and it's only fired when the
// new value is not equal to old value.
// So, we'll have to explicitly update the selected file path

setSelectedFilePath(filePath, true)
} else {
setPrevFileContent(fileContent, () => {
if (filePath) {
setSelectedFilePath(filePath, true)
}
})
}
setSnackbarMessage('File saved!')
setSnackbarSeverity(AlertSeverityType.Success)
setOpenSnackbar(true)
})
.catch((err) => {
setModalTitle('Abort')
setModalPayload(
typeof err.response.data === 'object'
? JSON.stringify(err.response.data)
: err.response.data
)
setOpenModal(true)
})
.finally(() => {
setIsLoading(false)
})
},
[
fileContent,
prevFileContent,
selectedFilePath,
setPrevFileContent,
setSelectedFilePath
]
)

useEffect(() => {
editorRef.current.addAction({
// An unique identifier of the contributed action.
id: 'save-file',

// A label of the action that will be presented to the user.
label: 'Save',

// An optional array of keybindings for the action.
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],

// Method that will be executed when the action is triggered.
// @param editor The editor instance is passed in as a convenience
run: () => {
if (!selectedFilePath) return setOpenFilePathInputModal(true)
if (prevFileContent !== fileContent) return saveFile()
}
})
}, [fileContent, prevFileContent, selectedFilePath, saveFile])

useEffect(() => {
setRunTimes(Object.values(appContext.runTimes))
}, [appContext.runTimes])
Expand Down Expand Up @@ -249,59 +332,6 @@ const SASjsEditor = ({
saveFile(filePath)
}

const saveFile = (filePath?: string) => {
setIsLoading(true)

if (filePath) {
filePath = filePath.startsWith('/') ? filePath : `/${filePath}`
}

const formData = new FormData()

const stringBlob = new Blob([fileContent], { type: 'text/plain' })
formData.append('file', stringBlob, 'filename.sas')
formData.append('filePath', filePath ?? selectedFilePath)

const axiosPromise = filePath
? axios.post('/SASjsApi/drive/file', formData)
: axios.patch('/SASjsApi/drive/file', formData)

axiosPromise
.then(() => {
if (filePath && fileContent === prevFileContent) {
// when fileContent and prevFileContent is same,
// callback function in setPrevFileContent method is not called
// because behind the scene useEffect hook is being used
// for calling callback function, and it's only fired when the
// new value is not equal to old value.
// So, we'll have to explicitly update the selected file path

setSelectedFilePath(filePath, true)
} else {
setPrevFileContent(fileContent, () => {
if (filePath) {
setSelectedFilePath(filePath, true)
}
})
}
setSnackbarMessage('File saved!')
setSnackbarSeverity(AlertSeverityType.Success)
setOpenSnackbar(true)
})
.catch((err) => {
setModalTitle('Abort')
setModalPayload(
typeof err.response.data === 'object'
? JSON.stringify(err.response.data)
: err.response.data
)
setOpenModal(true)
})
.finally(() => {
setIsLoading(false)
})
}

return (
<Box sx={{ width: '100%', typography: 'body1', marginTop: '50px' }}>
<Backdrop
Expand Down

0 comments on commit 8b8739a

Please sign in to comment.