Skip to content

Commit

Permalink
[OP#41289] list all linked workpackages (#71)
Browse files Browse the repository at this point in the history
Signed-off-by: Artur Neumann <artur@jankaritech.com>
  • Loading branch information
individual-it committed Mar 17, 2022
1 parent 5a3a629 commit 7c85e8f
Show file tree
Hide file tree
Showing 6 changed files with 472 additions and 69 deletions.
57 changes: 12 additions & 45 deletions src/components/tab/SearchInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { translate as t } from '@nextcloud/l10n'
import Multiselect from '@nextcloud/vue/dist/Components/Multiselect'
import WorkPackage from './WorkPackage'
import { showError } from '@nextcloud/dialogs'
import { workpackageHelper } from '../../utils/workpackageHelper'
const STATE_OK = 'ok'
const STATE_ERROR = 'error'
Expand Down Expand Up @@ -96,12 +97,6 @@ export default {
this.state = STATE_ERROR
}
},
replaceHrefToGetId(href) {
// this is a helper method replaces the string like this "/api/v3/types/3" to get id
return href
? href.replace(/.*\//, '')
: null
},
async linkWorkPackageToFile(selectedOption) {
const params = new URLSearchParams()
params.append('workpackageId', selectedOption.id)
Expand Down Expand Up @@ -148,48 +143,20 @@ export default {
if (this.isStateLoading) this.state = STATE_OK
},
async processWorkPackages(workPackages) {
for (const workPackage of workPackages) {
const statusId = this.replaceHrefToGetId(workPackage._links.status.href)
const typeId = this.replaceHrefToGetId(workPackage._links.type.href)
const userId = this.replaceHrefToGetId(workPackage._links.assignee.href)
const userName = workPackage._links.assignee.title
const avatarUrl = generateUrl('/apps/integration_openproject/avatar?')
+ encodeURIComponent('userId')
+ '=' + userId
+ '&' + encodeURIComponent('userName')
+ '=' + userName
const statusColor = await this.getWorkPackageColorAttributes('/apps/integration_openproject/statuses/', statusId)
const typeColor = await this.getWorkPackageColorAttributes('/apps/integration_openproject/types/', typeId)
const selectedIdFound = this.selectedId.some(el => el.id === workPackage.id)
const workpackageIdFound = this.searchResults.some(el => el.id === workPackage.id)
if (!workpackageIdFound && !selectedIdFound) {
this.searchResults.push({
id: workPackage.id,
subject: workPackage.subject,
project: workPackage._links.project.title,
statusTitle: workPackage._links.status.title,
typeTitle: workPackage._links.type.title,
assignee: userName,
statusCol: statusColor,
typeCol: typeColor,
picture: avatarUrl,
})
for (let workPackage of workPackages) {
try {
workPackage = await workpackageHelper.getAdditionalMetaData(workPackage)
const selectedIdFound = this.selectedId.some(el => el.id === workPackage.id)
const workpackageIdFound = this.searchResults.some(el => el.id === workPackage.id)
if (!workpackageIdFound && !selectedIdFound) {
this.searchResults.push(workPackage)
}
} catch (e) {
console.error('could not process workpackage data')
}
}
},
async getWorkPackageColorAttributes(path, id) {
const url = generateUrl(path + id)
let response
try {
response = await axios.get(url)
} catch (e) {
response = e.response
}
this.checkForErrorCode(response.status)
return (response.status === 200 && response.data?.color)
? response.data.color
: ''
},
},
}
</script>
Expand Down
63 changes: 63 additions & 0 deletions src/utils/workpackageHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { generateUrl } from '@nextcloud/router'
import axios from '@nextcloud/axios'

export const workpackageHelper = {
async getColorAttributes(path, id) {
const url = generateUrl(path + id)
let response
try {
response = await axios.get(url)
} catch (e) {
response = e.response
}
return (response.status === 200 && response.data?.color)
? response.data.color
: ''
},
replaceHrefToGetId(href) {
// this is a helper method replaces the string like this "/api/v3/types/3" to get id
return href
? href.replace(/.*\//, '')
: null
},
async getAdditionalMetaData(workPackage) {
if (typeof workPackage._links.status.href !== 'string'
|| workPackage._links.status.href === ''
|| typeof workPackage._links.type.href !== 'string'
|| workPackage._links.type.href === ''
|| typeof workPackage.id !== 'number'
|| typeof workPackage.subject !== 'string'
|| workPackage.subject === ''
|| typeof workPackage._links.project.title !== 'string'
|| workPackage._links.project.title === ''
|| typeof workPackage._links.status.title !== 'string'
|| workPackage._links.status.title === ''
|| typeof workPackage._links.type.title !== 'string'
|| workPackage._links.type.title === ''
) {
throw new Error('missing data in workpackage object')
}
const statusId = this.replaceHrefToGetId(workPackage._links.status.href)
const typeId = this.replaceHrefToGetId(workPackage._links.type.href)
const userId = this.replaceHrefToGetId(workPackage._links.assignee.href)
const userName = workPackage._links.assignee.title
const avatarUrl = generateUrl('/apps/integration_openproject/avatar?')
+ encodeURIComponent('userId')
+ '=' + userId
+ '&' + encodeURIComponent('userName')
+ '=' + userName
const statusColor = await this.getColorAttributes('/apps/integration_openproject/statuses/', statusId)
const typeColor = await this.getColorAttributes('/apps/integration_openproject/types/', typeId)
return {
id: workPackage.id,
subject: workPackage.subject,
project: workPackage._links.project.title,
statusTitle: workPackage._links.status.title,
typeTitle: workPackage._links.type.title,
assignee: userName,
statusCol: statusColor,
typeCol: typeColor,
picture: avatarUrl,
}
},
}
19 changes: 16 additions & 3 deletions src/views/ProjectsTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import SearchInput from '../components/tab/SearchInput'
import { loadState } from '@nextcloud/initial-state'
import { workpackageHelper } from '../utils/workpackageHelper'
export default {
name: 'ProjectsTab',
Expand All @@ -60,7 +61,7 @@ export default {
},
data: () => ({
error: '',
fileInfo: null,
fileInfo: { },
state: 'loading',
workpackages: [],
requestUrl: loadState('integration_openproject', 'request-url'),
Expand All @@ -80,6 +81,7 @@ export default {
async update(fileInfo) {
this.fileInfo = fileInfo
this.workpackages = []
this.state = 'loading'
await this.fetchWorkpackages(this.fileInfo.id)
},
/**
Expand All @@ -100,14 +102,21 @@ export default {
if (!Array.isArray(response.data)) {
this.state = 'failed-fetching-workpackages'
} else {
// empty data means there are no workpackages linked
if (response.data.length > 0) {
for (let workPackage of response.data) {
workPackage = await workpackageHelper.getAdditionalMetaData(workPackage)
this.workpackages.push(workPackage)
}
}
this.state = 'ok'
}
} catch (error) {
if (error.response && error.response.status === 401) {
this.state = 'no-token'
} else if (error.response.status === 404) {
} else if (error.response && error.response.status === 404) {
this.state = 'connection-error'
} else if (error.response.status === 500) {
} else if (error.response && error.response.status === 500) {
this.state = 'error'
} else {
this.state = 'failed-fetching-workpackages'
Expand Down Expand Up @@ -146,5 +155,9 @@ export default {
padding-top: 0;
font-size: 1.2rem;
}
.icon-loading:after {
top: 140%;
}
}
</style>
20 changes: 19 additions & 1 deletion tests/jest/components/tab/SearchInput.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,24 @@ describe('SearchInput.vue tests', () => {
)
axiosSpy.mockRestore()
})
it('should log an error on invalid payload', async () => {
const axiosSpy = jest.spyOn(axios, 'get')
.mockImplementationOnce(() => Promise.resolve({
status: 200,
data: [{
id: 123,
}],
}))
const consoleMock = jest.spyOn(console, 'error')
.mockImplementationOnce(() => {})
wrapper = mountSearchInput()
const inputField = wrapper.find(inputSelector)
await inputField.setValue('orga')
await localVue.nextTick()
expect(consoleMock).toHaveBeenCalledWith('could not process workpackage data')
consoleMock.mockRestore()
axiosSpy.mockRestore()
})
})

describe('search list', () => {
Expand Down Expand Up @@ -212,7 +230,7 @@ describe('SearchInput.vue tests', () => {
})
})

function mountSearchInput(fileInfo = null) {
function mountSearchInput(fileInfo = { }) {
return mount(SearchInput, {
localVue,
mocks: {
Expand Down
Loading

0 comments on commit 7c85e8f

Please sign in to comment.