Skip to content

Commit

Permalink
First implementation for apikeys view
Browse files Browse the repository at this point in the history
  • Loading branch information
runely committed Jun 3, 2022
1 parent 79ea350 commit 63b3abf
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 15 deletions.
109 changes: 109 additions & 0 deletions src/hooks/useKeysAPI/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { useEffect, useMemo, useState } from 'react'
import axios from 'axios'
import { orderBy } from 'lodash'

import { API } from '../../config'

export function useKeysAPI (defaultItemsOptions = {}, top = 1000000) {
const [_keys, setKeys] = useState([])
const [itemsOptions, setItemsOptions] = useState(defaultItemsOptions)
const [loading, setLoading] = useState(false)
const [updating, setUpdating] = useState(false)

useEffect(() => {
const getApiKeys = async () => {
setLoading(true)
try {
const options = {
headers: {
'X-API-KEY': API.TOKEN
}
}

const url = `${API.URL}/apikeys?$top=${top}`
const { data } = await axios.get(url, options)
setKeys(data.data)
} catch (error) {
console.log('Failed to get api keys')
console.dir(error)
setKeys([])
}
setLoading(false)
}

getApiKeys()
}, [top])

const options = useMemo(() => {
return {
filter: [],
orderBy: ['createdAt'],
order: 'desc',
...itemsOptions
}
}, [itemsOptions])

const keys = useMemo(() => {
if (options.filter.length === 0) return orderBy(_keys, options.orderBy, options.order)

const filtered = _keys.filter(item => options.filter.includes(item.status)) // TODO: Needs rework as status doesn't exist in keys
return orderBy(filtered, options.orderBy, options.order)
}, [options, _keys])

const updateKeysItem = async (id, updateObject) => {
const options = {
headers: {
'X-API-KEY': API.TOKEN
}
}

try {
setUpdating(true)
const { data } = await axios.put(`${API.URL}/apikeys/${id}`, updateObject, options)
const tempKeys = _keys.map(q => {
if (q._id === data._id) {
q = data
}
return q
})
setKeys(tempKeys)
setUpdating(false)
return data
} catch (error) {
setUpdating(false)
throw error
}
}

// remove keys item
const removeKeysItem = async (id) => {
const options = {
headers: {
'X-API-KEY': API.TOKEN
}
}

try {
setUpdating(true)
await axios.delete(`${API.URL}/apikeys/${id}`, options)
const tempKeys = _keys.filter(q => q._id !== id)
setKeys(tempKeys)
setUpdating(false)
return true
} catch (error) {
setUpdating(false)
throw error
}
}

return {
allKeys: _keys,
itemsOptions: options,
loading,
keys,
removeKeysItem,
setItemsOptions,
updateKeysItem,
updating
}
}
112 changes: 97 additions & 15 deletions src/pages/APIKeys/index.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,105 @@
import { relativeDateFormat } from '@vtfk/utilities'
import { IconButton, Table } from '@vtfk/components'
import React, { useState } from 'react'
import { isEqual } from 'lodash'

import ConfirmationDialog from '../../components/ConfirmationDialog'

import { useKeysAPI } from '../../hooks/useKeysAPI'

import './styles.scss'

export function APIKeys () {
const { itemsOptions, keys, loading, removeKeysItem, setItemsOptions, updating } = useKeysAPI()
const [itemIndex, setItemIndex] = useState(-1)

const headers = [
{
label: 'Name',
value: 'name',
onClick: () => handleSortClick(['name'])
},
{
label: 'Created',
value: 'createdAt',
itemTooltip: (value, item, header, index) => <div>{relativeDateFormat({ toDate: new Date(item.createdAt || item.createdTimestamp), locale: 'no' })}</div>,
onClick: () => handleSortClick(['createdAt'])
},
{
label: 'Modified',
value: 'updatedAt',
itemTooltip: (value, item, header, index) => <div>{relativeDateFormat({ toDate: new Date(item.updatedAt || item.modifiedTimestamp), locale: 'no' })}</div>,
onClick: () => handleSortClick(['updatedAt'])
},
{
label: 'Actions',
itemRender: (value, item, header, index) => {
return (
<div className='item-actions'>
<IconButton
icon='close'
onClick={() => setItemIndex(index)}
title='Delete'
/>
</div>
)
}
}
]

function handleSortClick (properties) {
setItemsOptions({
...itemsOptions,
orderBy: properties,
order: isEqual(itemsOptions.orderBy, properties) ? (itemsOptions.order === 'asc' ? 'desc' : 'asc') : 'desc'
})
}

const handleConfirmationOkClick = async id => {
try {
await removeKeysItem(id)
console.log('Successfully removed key', id)
setItemIndex(-1)
} catch (error) {
const removeFailed = error.response?.data?.message || error.message || error
console.log('Failed to remove key:', removeFailed)
// TODO: Add toast for error message
}
}

return (
<div className='apikeys-container'>
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
APIKeys<br />
<div className='apikeys'>
<IconButton
className='add-key-button'
bordered
icon='add'
onClick={() => console.log('Add new key')}
title='Add key'

/>
<Table
headers={headers}
items={keys}
isLoading={loading}
/>
</div>

{
itemIndex > -1 &&
<ConfirmationDialog
open
title={<span>{`Delete api key ${keys[itemIndex].name} ?`}</span>}
okBtnText='Yes'
cancelBtnText='No'
okBtnDisabled={updating}
onClickCancel={() => setItemIndex(-1)}
onClickOk={() => handleConfirmationOkClick(keys[itemIndex]._id)}
onDismiss={() => setItemIndex(-1)}
height='30%'
width='30%'
/>
}
</div>
)
}
11 changes: 11 additions & 0 deletions src/pages/APIKeys/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.apikeys {
.add-key-button {
margin-bottom: 1rem;

}

.item-actions {
display: flex;
gap: 0.5rem;
}
}

0 comments on commit 63b3abf

Please sign in to comment.