Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Part 3: Add workflow build and lint #26

Merged
merged 10 commits into from
Feb 2, 2024
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module.exports = {
{ allowConstantExport: true },
],
'prettier/prettier': [
'warn',
'error',
{},
{
usePrettierrc: true,
Expand Down
25 changes: 25 additions & 0 deletions .github/workflows/build-and-lint-on-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: 'Build and Lint on Pull Requests'
on:
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm install

- name: Build application
run: npm run build

- name: Check for ESLint warnings and errors
run: npm run lint
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,42 @@ This is an example of how to list things you need to use the software and how to
npm run dev
```

### ESLint and Prettier

For ensuring code consistency and adhering to coding standards, our project utilizes ESLint and Prettier. To view linting warnings and errors in the console, it's recommended to run the following script during development:

```sh
npm run lint
```

To automatically fix linting and formatting issues across all files, you can use the following scripts (Note: While these scripts resolve many ESLint warnings or errors, some issues may require manual intervention):

```sh
npm run lint:fix && npm run lint:format
```

### Integrated Development Environments (IDEs) Support

For seamless integration with popular IDEs such as Visual Studio Code and IntelliJ, consider installing the following plugins:

#### Visual Studio Code

1. **ESLint**: Install the ESLint extension to enable real-time linting and error highlighting.
[ESLint Extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)

2. **Prettier**: Enhance code formatting by installing the Prettier extension.
[Prettier Extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)

#### IntelliJ

1. **ESLint**: Install the ESLint plugin to enable ESLint integration within IntelliJ.
[ESLint Plugin](https://plugins.jetbrains.com/plugin/7494-eslint)

2. **Prettier**: Integrate Prettier for code formatting by installing the Prettier plugin.
[Prettier Plugin](https://plugins.jetbrains.com/plugin/10456-prettier)

By incorporating these plugins into your development environment, you can take full advantage of ESLint and Prettier to maintain code quality and consistent formatting throughout your project.

<p align="right">(<a href="#readme-top">back to top</a>)</p>

<!-- CONTRIBUTING -->
Expand Down
54 changes: 27 additions & 27 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,35 +247,35 @@ app.get('/api/userProfile/:principalName/team', tokenVerificationMiddleware, asy

app.get('/api/teamDetail/:teamUniformName', tokenVerificationMiddleware, async (req, res, next) => {
try {
const token = req.token;
const teamUniformName = req.params.teamUniformName;
const teamInfoUrl = `${DAPLA_TEAM_API_URL}/teams/${teamUniformName}`;
const teamUsersUrl = `${DAPLA_TEAM_API_URL}/teams/${teamUniformName}/users`;
const token = req.token
const teamUniformName = req.params.teamUniformName
const teamInfoUrl = `${DAPLA_TEAM_API_URL}/teams/${teamUniformName}`
const teamUsersUrl = `${DAPLA_TEAM_API_URL}/teams/${teamUniformName}/users`

const [teamInfo, teamUsers] = await Promise.all([
fetchAPIData(token, teamInfoUrl, 'Failed to fetch team info')
.then(async (teamInfo) => {
const manager = await fetchTeamManager(token, teamInfo)
return { ...teamInfo, manager};
}),
fetchAPIData(token, teamUsersUrl, 'Failed to fetch team users')
.then(async (teamUsers) => {
const resolvedUsers = await fetchTeamUsersWithGroups(token, teamUsers, teamUniformName);
return { ...teamUsers, _embedded: { users: resolvedUsers } };
}),
]);

res.json({ teamInfo, teamUsers: teamUsers._embedded.users });
fetchAPIData(token, teamInfoUrl, 'Failed to fetch team info').then(async (teamInfo) => {
const manager = await fetchTeamManager(token, teamInfo)
return { ...teamInfo, manager }
}),
fetchAPIData(token, teamUsersUrl, 'Failed to fetch team users').then(async (teamUsers) => {
const resolvedUsers = await fetchTeamUsersWithGroups(token, teamUsers, teamUniformName)
return { ...teamUsers, _embedded: { users: resolvedUsers } }
}),
])

res.json({ teamInfo, teamUsers: teamUsers._embedded.users })
} catch (error) {
next(error);
next(error)
}
});
})

async function fetchTeamManager(token, teamInfo) {
const teamManagerUrl = `${DAPLA_TEAM_API_URL}/groups/${teamInfo.uniform_name}-managers/users`
return await fetchAPIData(token, teamManagerUrl, 'Failed to fetch team manager').then((teamManager) => {
return teamManager.count > 0 ? teamManager._embedded.users[0] : managerFallback()
}).catch(() => managerFallback())
return await fetchAPIData(token, teamManagerUrl, 'Failed to fetch team manager')
.then((teamManager) => {
return teamManager.count > 0 ? teamManager._embedded.users[0] : managerFallback()
})
.catch(() => managerFallback())
}

async function fetchTeamUsersWithGroups(token, teamUsers, teamUniformName) {
Expand All @@ -287,11 +287,11 @@ async function fetchTeamUsersWithGroups(token, teamUsers, teamUniformName) {
.filter((group) => group !== null && group.uniform_name.startsWith(teamUniformName))
.flatMap((group) => group)

user["groups"] = flattenedGroups
user['groups'] = flattenedGroups

return { ...user }
});
return await Promise.all(userPromises);
})
return await Promise.all(userPromises)
}

async function fetchAPIData(token, url, fallbackErrorMessage) {
Expand Down Expand Up @@ -381,7 +381,7 @@ function sectionFallback(uniformName) {
}

function groupFallback() {
return { "_embedded": { "groups": [] }, "count": "0"}
return { _embedded: { groups: [] }, count: '0' }
}

//const lightship = await createLightship();
Expand Down
8 changes: 4 additions & 4 deletions src/@types/group.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { User } from '../@types/user'

export interface Group {
uniform_name: string
display_name: string
manager?: User
}
uniform_name: string
display_name: string
manager?: User
}
40 changes: 20 additions & 20 deletions src/api/teamDetail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,24 @@ export interface TeamDetailResult {
}

export const getTeamDetail = async (teamId: string): Promise<TeamDetailData | ErrorResponse> => {
const accessToken = localStorage.getItem('access_token')

try {
const response = await fetch(`/api/teamDetail/${teamId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
})
if (!response.ok) {
const errorData = await response.json()
return errorData as ErrorResponse
}
const data = await response.json()
return data as TeamDetailData
} catch (error) {
console.error('Error during fetching teams:', error)
throw new Error('Error fetching teams')
const accessToken = localStorage.getItem('access_token')

try {
const response = await fetch(`/api/teamDetail/${teamId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
})
if (!response.ok) {
const errorData = await response.json()
return errorData as ErrorResponse
}
}
const data = await response.json()
return data as TeamDetailData
} catch (error) {
console.error('Error during fetching teams:', error)
throw new Error('Error fetching teams')
}
}
55 changes: 28 additions & 27 deletions src/pages/TeamDetail/TeamDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,38 @@

import { useEffect, useState } from 'react'
import { useState, useEffect } from 'react'
import PageLayout from '../../components/PageLayout/PageLayout'
import { TeamDetailData, getTeamDetail } from '../../api/teamDetail'
import { useParams } from 'react-router-dom'
import { ErrorResponse } from '../../@types/error'


export default function TeamOverview() {
const { teamId } = useParams<{ teamId: string }>()
const [teamDetailData, setTeamDetailData] = useState<TeamDetailData>()
const [error, setError] = useState<ErrorResponse | undefined>()
const [loading, setLoading] = useState<boolean>(true)

useEffect(() => {
if (!teamId) return
console.log(teamId)
getTeamDetail(teamId)
.then((response) => {
if ((response as ErrorResponse).error) {
console.log(response)
setError(response as ErrorResponse)
} else {
console.log((response))
setTeamDetailData(response as TeamDetailData)
}
})
.finally(() => setLoading(false))
.catch((error) => {
setError(error.toString())
})
const { teamId } = useParams<{ teamId: string }>()
// TODO: Temporary hide these so build doesn't fail
// const [teamDetailData, setTeamDetailData] = useState<TeamDetailData>()
// const [error, setError] = useState<ErrorResponse | undefined>()
// const [loading, setLoading] = useState<boolean>(true)

}, [teamId])
const [, setTeamDetailData] = useState<TeamDetailData>()
const [, setError] = useState<ErrorResponse | undefined>()
const [, setLoading] = useState<boolean>(true)

useEffect(() => {
if (!teamId) return
console.log(teamId)
getTeamDetail(teamId)
.then((response) => {
if ((response as ErrorResponse).error) {
console.log(response)
setError(response as ErrorResponse)
} else {
console.log(response)
setTeamDetailData(response as TeamDetailData)
}
})
.finally(() => setLoading(false))
.catch((error) => {
setError(error.toString())
})
}, [teamId])

return <PageLayout title='Teamoversikt' content={<h1>TeamDetail</h1>} />
return <PageLayout title='Teamoversikt' content={<h1>TeamDetail</h1>} />
}
2 changes: 1 addition & 1 deletion src/provider/DaplaCtrlProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ interface BreadcrumbUserProfileDisplayName {
}

interface DaplaCtrlContextType {
breadcrumbUserProfileDisplayName: object | null
breadcrumbUserProfileDisplayName: BreadcrumbUserProfileDisplayName | null
setBreadcrumbUserProfileDisplayName: (
breadcrumbUserProfileDisplayName: BreadcrumbUserProfileDisplayName | null
) => void
Expand Down