Skip to content

Commit

Permalink
clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
OlegMoshkovich committed Mar 14, 2023
1 parent e93b296 commit d4161b0
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 64 deletions.
87 changes: 69 additions & 18 deletions src/Components/OpenModelControl.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import Selector from './Selector'
import OpenIcon from '../assets/icons/Open.svg'
import UploadIcon from '../assets/icons/Upload.svg'
import {handleBeforeUnload} from '../utils/event'
import {getOrganizations} from '../utils/GitHub'
import {getOrganizations, getRepositories, getFiles, getUserRepositories} from '../utils/GitHub'
import {RectangularButton} from '../Components/Buttons'


/**
Expand All @@ -24,14 +25,27 @@ import {getOrganizations} from '../utils/GitHub'
*/
export default function OpenModelControl({fileOpen}) {
const [isDialogDisplayed, setIsDialogDisplayed] = useState(false)
const [orgNamesArr, setOrgNamesArray] = useState(['loading'])
const {user} = useAuth0()
const theme = useTheme()
const accessToken = useStore((state) => state.accessToken)
useEffect(() => {
const organizations = getOrganizations(accessToken)
console.log('organizations from open component', organizations )
})


/**
* Asynchronously fetch organizations
*
* @return {Array} organizations
*/
async function fetchOrganizations() {
const orgs = await getOrganizations(accessToken)
const orgNamesFetched = Object.keys(orgs).map((key) => orgs[key].login)
const orgNames = [...orgNamesFetched, user ? user.nickname : 'my own repo']
setOrgNamesArray(orgNames)
console.log('in the fetch Organizations', orgs)
return orgs
}
fetchOrganizations()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
<Box
sx={{
Expand All @@ -56,6 +70,7 @@ export default function OpenModelControl({fileOpen}) {
isDialogDisplayed={isDialogDisplayed}
setIsDialogDisplayed={setIsDialogDisplayed}
fileOpen={fileOpen}
orgNamesArr={orgNamesArr}
/>
}
</Box>
Expand All @@ -68,19 +83,44 @@ export default function OpenModelControl({fileOpen}) {
* @param {Function} setIsDialogDisplayed
* @return {object} React component
*/
function OpenModelDialog({isDialogDisplayed, setIsDialogDisplayed, fileOpen}) {
const {isAuthenticated} = useAuth0()
function OpenModelDialog({isDialogDisplayed, setIsDialogDisplayed, fileOpen, orgNamesArr}) {
const {isAuthenticated, user} = useAuth0()
// const isAuthenticated = true
const [selectedOrg, setSelectedOrg] = useState('')
const [selectedRepo, setSelectedRepo] = useState('')
const [selectedFile, setSelectedFile] = useState('')
const [repoNamesArr, setRepoNamesArr] = useState(['loading'])
const [filesArr, setFilesArr] = useState(['loading'])
const theme = useTheme()
const navigate = useNavigate()
const accessToken = useStore((state) => state.accessToken)
const openFile = () => {
fileOpen()
setIsDialogDisplayed(false)
}
const list = [
{0: 'one'},
{1: 'two'},
{2: 'three'},
]
const selectOrg = async (org) => {
setSelectedOrg(org)
let repos
if (orgNamesArr[org] === user.nickname) {
repos = await getUserRepositories(user.nickname, accessToken)
} else {
repos = await getRepositories(orgNamesArr[org], accessToken)
}
const repoNames = Object.keys(repos).map((key) => repos[key].name)
setRepoNamesArr(repoNames)
}
const selectRepo = async (repo) => {
setSelectedRepo(repo)
const owner = orgNamesArr[selectedOrg]
const files = await getFiles(repoNamesArr[repo], owner, accessToken)
const fileNames = Object.keys(files).map((key) => files[key].name)
setFilesArr(fileNames)
}
const navigateToFile = () => {
if (filesArr[selectedFile].includes('.ifc')) {
navigate({pathname: `/share/v/gh/${orgNamesArr[selectedOrg]}/${repoNamesArr[selectedRepo]}/main/${filesArr[selectedFile]}`})
}
}
return (
<Dialog
icon={<OpenIcon/>}
Expand Down Expand Up @@ -110,10 +150,14 @@ function OpenModelDialog({isDialogDisplayed, setIsDialogDisplayed, fileOpen}) {
</p>
{isAuthenticated ?
<Box>
<Selector label={'Organization'} list={list}/>
<Selector label={'Repository'} list={list}/>
<Selector label={'File'} list={list}/>
<Selector label={'Branch'} list={list}/>
<Selector label={'Organization'} list={orgNamesArr} selected={selectedOrg} setSelected={selectOrg}/>
<Selector label={'Repository'} list={repoNamesArr} selected={selectedRepo} setSelected={selectRepo} testId={'Repository'}/>
<Selector label={'File'} list={filesArr} selected={selectedFile} setSelected={setSelectedFile} testId={'File'}/>
{selectedFile !== '' &&
<Box sx={{textAlign: 'center', marginTop: '4px'}}>
<RectangularButton title={'Load file'} icon={<UploadIcon/>} onClick={navigateToFile}/>
</Box>
}
</Box> :
<Box
sx={{
Expand All @@ -126,7 +170,14 @@ function OpenModelDialog({isDialogDisplayed, setIsDialogDisplayed, fileOpen}) {
Please login to get access to your files on GitHub
</Box>
}
<p>Models opened from local drive cannot yet be saved or shared.</p>
<Box
sx={{
marginTop: '1em',
fontSize: '.8em',
}}
>
* Local files cannot yet be saved or shared.
</Box>
</Box>
}
/>
Expand Down
30 changes: 30 additions & 0 deletions src/Components/OpenModelControl.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react'
import {render, fireEvent} from '@testing-library/react'
import {
mockedUseAuth0,
mockedUserLoggedIn,
mockedUserLoggedOut} from '../__mocks__/authentication'
import OpenModelControl from './OpenModelControl'
import ShareMock from '../ShareMock'


describe('Open Model Dialog', () => {
it('Renders a login message if the user is not logged in', () => {
mockedUseAuth0.mockReturnValue(mockedUserLoggedOut)
const {getByTitle, getByText} = render(<ShareMock><OpenModelControl/></ShareMock>)
const button = getByTitle('Open IFC')
fireEvent.click(button)
const loginText = getByText('Please login to get access to your files on GitHub')
expect(loginText).toBeInTheDocument()
})
it('Renders file selector if the user is logged in', async () => {
mockedUseAuth0.mockReturnValue(mockedUserLoggedIn)
const {getByTitle, getByTestId} = render(<ShareMock><OpenModelControl/></ShareMock>)
const button = getByTitle('Open IFC')
fireEvent.click(button)
const File = getByTestId('File')
const Repository = await getByTestId('Repository')
expect(File).toBeInTheDocument()
expect(Repository).toBeInTheDocument()
})
})
85 changes: 43 additions & 42 deletions src/Components/Selector.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, {useState} from 'react'
// import {useNavigate} from 'react-router-dom'
import React from 'react'
import MenuItem from '@mui/material/MenuItem'
import Typography from '@mui/material/Typography'
import TextField from '@mui/material/TextField'
Expand All @@ -11,64 +10,66 @@ import {handleBeforeUnload} from '../utils/event'
* @property {Function} setIsDialogDisplayed callback
* @return {React.ReactElement}
*/
export default function Selector({setIsDialogDisplayed, label, selected, list}) {
// const navigate = useNavigate()
const [localSelected, setLocalSelected] = useState(selected)
export default function Selector({setIsDialogDisplayed, label, selected, setSelected, list, testId = 'Selector'}) {
const theme = useTheme()
const handleSelect = (e) => {
setLocalSelected(e.target.value)
window.removeEventListener('beforeunload', handleBeforeUnload)
// navigate({pathname: urlList[e.target.value]})
setSelected(e.target.value)
}


list.map((x) => console.log(x))

return (
<TextField
sx={{
'width': '260px',
'padding': '0px 0px 12px 0px',
'& .MuiOutlinedInput-input': {
color: theme.palette.secondary.main,
},
'& .MuiInputLabel-root': {
color: theme.palette.secondary.main,
},
'& .MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline': {
borderColor: theme.palette.secondary.main,
},
'&:hover .MuiOutlinedInput-input': {
color: theme.palette.secondary.main,
},
'&:hover .MuiInputLabel-root': {
color: theme.palette.secondary.main,
},
'&:hover .MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline': {
borderColor: theme.palette.secondary.main,
},
'& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-input': {
color: theme.palette.secondary.main,
},
'& .MuiInputLabel-root.Mui-focused': {
color: theme.palette.secondary.main,
},
'& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline': {
borderColor: theme.palette.secondary.main,
},
}}
value={localSelected}
sx={selectorStyles(theme)}
value={selected}
onChange={(e) => handleSelect(e)}
variant='outlined'
label={label}
select
size='small'
data-testid={testId}
>
{list.map((listMember, i) => {
return (
<MenuItem key={i} value={i}><Typography variant='p'>{listMember[i]}</Typography></MenuItem>
<MenuItem key={i} value={i}><Typography variant='p'>{listMember}</Typography></MenuItem>
)
})}
</TextField>
)
}

const selectorStyles = (theme) => {
return (
{
'width': '260px',
'padding': '0px 0px 12px 0px',
'& .MuiOutlinedInput-input': {
color: theme.palette.secondary.main,
},
'& .MuiInputLabel-root': {
color: theme.palette.secondary.main,
},
'& .MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline': {
borderColor: theme.palette.secondary.main,
},
'&:hover .MuiOutlinedInput-input': {
color: theme.palette.secondary.main,
},
'&:hover .MuiInputLabel-root': {
color: theme.palette.secondary.main,
},
'&:hover .MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline': {
borderColor: theme.palette.secondary.main,
},
'& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-input': {
color: theme.palette.secondary.main,
},
'& .MuiInputLabel-root.Mui-focused': {
color: theme.palette.secondary.main,
},
'& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline': {
borderColor: theme.palette.secondary.main,
},
}
)
}
60 changes: 56 additions & 4 deletions src/utils/GitHub.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export async function getComment(repository, issueId, commentId, accessToken = '
}
}


/**
* Retrieves the contents download URL for a GitHub repository path
*
Expand Down Expand Up @@ -184,11 +185,62 @@ export async function getDownloadURL(repository, path, ref = '', accessToken = '
export async function getOrganizations(accessToken = '') {
const res = await octokit.request(`/user/orgs`, {
headers: {
'authorization': `Bearer ${accessToken}`,
'X-GitHub-Api-Version': '2022-11-28',
authorization: `Bearer ${accessToken}`,
},
})
return res
return res.data
}


/**
* Retrieves repositories associated with an organization
*
* @param {string} [org]
* @param {string} [accessToken]
* @return {Promise} the list of organization
*/
export async function getRepositories(org, accessToken = '') {
const res = await octokit.request('GET /orgs/{org}/repos', {
org,
headers: {
authorization: `Bearer ${accessToken}`,
},
})
return res.data
}

/**
* Retrieves repositories associated with the authenticated user
*
* @param {string} [accessToken]
* @return {Promise} the list of organization
*/
export async function getUserRepositories(username, accessToken = '') {
const res = await octokit.request('GET /users/{username}/repos', {
username,
headers: {
authorization: `Bearer ${accessToken}`,
},
})
return res.data
}


/**
* Retrieves files associated with a repository
*
* @param {string} [accessToken]
* @return {Promise} the list of organization
*/
export async function getFiles(repo, owner, accessToken = '') {
const res = await octokit.request('/repos/{owner}/{repo}/contents', {
owner,
repo,
headers: {
authorization: `Bearer ${accessToken}`,
},
})
return res.data
}


Expand Down Expand Up @@ -231,6 +283,7 @@ export const parseGitHubRepositoryURL = (githubURL) => {
}
}


// DO NOT EXPORT ANY BELOW //
/**
* Fetch the resource at the given path from GitHub, substituting in
Expand All @@ -244,7 +297,6 @@ export const parseGitHubRepositoryURL = (githubURL) => {
async function getGitHub(repository, path, args = {}) {
assertDefined(repository.orgName)
assertDefined(repository.name)
console.log('args', args)

debug().log('Dispatching GitHub request for repo:', repository)
const res = await octokit.request(`GET /repos/{org}/{repo}/${path}`, {
Expand Down

0 comments on commit d4161b0

Please sign in to comment.