Skip to content

Commit

Permalink
Merge pull request #1550 from cloud-pi-native/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
ArnaudTA authored Feb 19, 2025
2 parents a360e95 + 8bc43f4 commit aaf3978
Show file tree
Hide file tree
Showing 38 changed files with 411 additions and 1,022 deletions.
3 changes: 3 additions & 0 deletions apps/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ npm run build
npm run preview
```

## Récupérer toutes les icones du projets
`grep -r -oh "ri:[a-z0-9-]*" . | sort | uniq | cut -d ':' -f 2 | awk NF | awk '{print " \047" $1 "\047,"}'`

## Crédits

- [vue](https://github.com/vuejs/)
Expand Down
6 changes: 3 additions & 3 deletions apps/client/cypress/e2e/specs/admin/projects.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,12 +314,12 @@ describe('Administration projects', () => {
cy.getByDataTestid('test-tab-team').click()
cy.get('.fr-callout__title')
.should('contain', project.name)
cy.get(`td[title="Quitter le projet"]`)
cy.get(`div[title="Quitter le projet"]`)
.click()
cy.wait('@removeUser')
.its('response.statusCode')
.should('match', /^20\d$/)
cy.get(`td[title="Quitter le projet"]`)
cy.get(`div[title="Quitter le projet"]`)
.should('not.exist')
cy.getByDataTestid('addUserSuggestionInput')
.find('input')
Expand All @@ -333,7 +333,7 @@ describe('Administration projects', () => {
cy.wait('@addUser')
.its('response.statusCode')
.should('match', /^20\d$/)
cy.get(`td[title="Quitter le projet"]`)
cy.get(`div[title="Quitter le projet"]`)
.should('exist')
})

Expand Down
2 changes: 1 addition & 1 deletion apps/client/cypress/e2e/specs/team.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ describe('Team view', () => {
cy.getByDataTestid('teamTable')
.find('tbody > tr')
.should('have.length', project.members.length + 1 + 1)
.get(`td[title="Retirer ${newMember.email} du projet"]`)
.get(`div[title="Retirer ${newMember.email} du projet"]`)
.click()
cy.wait('@removeUser')
.its('response.statusCode')
Expand Down
2 changes: 1 addition & 1 deletion apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"dependencies": {
"@cpn-console/shared": "workspace:^",
"@gouvfr/dsfr": "^1.13.0",
"@gouvminint/vue-dsfr": "^8.1.0",
"@gouvminint/vue-dsfr": "^8.2.1",
"@iconify-json/ri": "^1.2.2",
"@iconify/vue": "^4.2.0",
"@ts-rest/core": "^3.51.0",
Expand Down
24 changes: 8 additions & 16 deletions apps/client/scripts/icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,51 @@ import { icons as riCollection } from '@iconify-json/ri'
* @type {string[]}
*/
const riIconNames = [
'door-open-line',
'shield-keyhole-line',
'arrow-right-line',
'code-s-slash-line',
'git-repository-private-line',
'account-circle-line',
'add-line',
'admin-line',
'alert-line',
'archive-line',
'arrow-drop-left-line',
'arrow-drop-right-line',
'arrow-go-back-line',
'arrow-left-double-line',
'arrow-right-double-line',
'arrow-right-line',
'arrow-right-s-line',
'arrow-up-s-line',
'award-line',
'building-line',
'check-line',
'checkbox-blank-circle-fill',
'checkbox-circle-line',
'clipboard-line',
'close-line',
'code-s-slash-line',
'dashboard-line',
'delete-bin-7-line',
'exchange-line',
'eye-line',
'eye-off-line',
'file-download-line',
'file-info-line',
'filter-line',
'filter-off-line',
'flow-chart',
'focus-3-line',
'folder-line',
'folder-shield-2-line',
'folder-user-line',
'folders-line',
'git-branch-line',
'git-merge-line',
'folder-user-line',
'github-line',
'git-merge-line',
'git-repository-private-line',
'global-line',
'heart-pulse-line',
'key-2-line',
'key-2-line',
'question-line',
'loader-4-line',
'lock-line',
'lock-unlock-line',
'mail-line',
'microsoft-line',
'moon-clear-line',
'newspaper-line',
'pencil-line',
'question-line',
'refresh-line',
'restart-line',
'send-plane-line',
Expand Down
3 changes: 1 addition & 2 deletions apps/client/src/components/AdminRoleForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { computed, onBeforeMount, ref } from 'vue'
import type { AdminPermsKeys, LettersQuery, SharedZodError, User } from '@cpn-console/shared'
import { ADMIN_PERMS, RoleSchema, adminPermsDetails, shallowEqual } from '@cpn-console/shared'
import pDebounce from 'p-debounce'
import { getRandomId } from '@gouvminint/vue-dsfr'
import SuggestionInput from './SuggestionInput.vue'
import { useUsersStore } from '@/stores/users.js'
import { clickInDialog } from '@/utils/func.js'
import { clickInDialog, getRandomId } from '@/utils/func.js'
const props = withDefaults(defineProps<{
id: string
Expand Down
3 changes: 1 addition & 2 deletions apps/client/src/components/EnvironmentForm.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<script lang="ts" setup>
import { computed, onBeforeMount, ref } from 'vue'
import { getRandomId } from '@gouvminint/vue-dsfr'
import type {
CleanedCluster,
CreateEnvironmentBody,
Expand All @@ -18,7 +17,7 @@ import { useSnackbarStore } from '@/stores/snackbar.js'
import { useQuotaStore } from '@/stores/quota.js'
import { useStageStore } from '@/stores/stage.js'
import { useZoneStore } from '@/stores/zone.js'
import { copyContent } from '@/utils/func.js'
import { copyContent, getRandomId } from '@/utils/func.js'
interface OptionType {
text: string
Expand Down
3 changes: 1 addition & 2 deletions apps/client/src/components/ProjectResources.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import { useSnackbarStore } from '@/stores/snackbar.js'
import { useStageStore } from '@/stores/stage.js'
import { useUserStore } from '@/stores/user.js'
import { useZoneStore } from '@/stores/zone.js'
import { clickInDialog } from '@/utils/func.js'
import { clickInDialog, getRandomId } from '@/utils/func.js'
import type { Project } from '@/utils/project-utils.js'
import type { UpdateEnvironmentBody, Environment, Repo, CreateEnvironmentBody, CleanedCluster, Zone, Quota, Cluster } from '@cpn-console/shared'
import { AdminAuthorized, ProjectAuthorized, projectIsLockedInfo } from '@cpn-console/shared'
import { getRandomId } from '@gouvminint/vue-dsfr'
import TimeAgo from 'javascript-time-ago'
import fr from 'javascript-time-ago/locale/fr'
Expand Down
112 changes: 45 additions & 67 deletions apps/client/src/components/TeamCt.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue'
import { getRandomId } from '@gouvminint/vue-dsfr'
import { computed, ref, watch } from 'vue'
import { useRandomId } from '@gouvminint/vue-dsfr'
import type {
LettersQuery,
Member,
User,
} from '@cpn-console/shared'
import pDebounce from 'p-debounce'
Expand Down Expand Up @@ -40,12 +39,11 @@ const headers = [
const snackbarStore = useSnackbarStore()
const userStore = useUserStore()
const newUserInputKey = ref(getRandomId('input'))
const newUserInputKey = ref(useRandomId('input'))
const newUserEmail = ref<string>('')
const usersToAdd = ref<User[]>([])
const rows = ref<any[][]>([])
const lettersNotMatching = ref('')
const tableKey = ref(getRandomId('table'))
const tableKey = ref(useRandomId('table'))
const isUserAlreadyInTeam = computed(() => {
return !!(newUserEmail.value && (props.project.owner.email === newUserEmail.value || props.project.members.find(member => member.email === newUserEmail.value)))
Expand All @@ -57,59 +55,6 @@ const usersToSuggest = computed(() => usersToAdd.value.map(userToAdd => ({
})))
const getRolesNames = (ids?: string[]) => ids ? props.project.roles.filter(role => ids.includes(role.id)).map(role => role.name).join(' / ') || '-' : ''
function getCopyIdComponent(id: string) {
return {
component: 'code',
text: id,
title: 'Copier l\'id',
'data-testid': 'ownerId',
class: 'fr-text-default--info text-xs truncate cursor-pointer',
onClick: () => copyContent(id),
}
}
function createMemberRow(member: Member) {
const row: Array<any> = [
getCopyIdComponent(member.userId),
member.email,
props.project.ownerId === member.userId ? 'Propriétaire' : getRolesNames(member.roleIds),
]
if (props.project.ownerId === member.userId) {
row.push('-')
} else if (member.userId === userStore.userProfile?.id) {
row.push({
cellAttrs: {
class: 'fr-fi-close-line !flex justify-center cursor-pointer fr-text-default--warning',
title: 'Quitter le projet',
onClick: () => removeUserFromProject(member.userId),
},
})
} else if (props.canManage) {
row.push({
cellAttrs: {
class: 'fr-fi-close-line !flex justify-center cursor-pointer fr-text-default--warning',
title: `Retirer ${member.email} du projet`,
onClick: () => removeUserFromProject(member.userId),
},
})
} else {
row.push('-')
}
return row
}
function setRows() {
rows.value = []
if (!props.project.members.find(member => member.userId === props.project.ownerId)) {
rows.value.push(createMemberRow({ ...props.project.owner, roleIds: [], userId: props.project.owner.id }))
}
if (props.project.members?.length) {
props.project.members.forEach((member) => {
rows.value.push(createMemberRow(member))
})
}
tableKey.value = getRandomId('table')
}
const retrieveUsersToAdd = pDebounce(async (letters: LettersQuery['letters']) => {
// Ne pas lancer de requête à moins de 3 caractères tapés
Expand All @@ -123,11 +68,9 @@ const retrieveUsersToAdd = pDebounce(async (letters: LettersQuery['letters']) =>
}
}, 300)
onMounted(() => {
setRows()
})
watch(() => props.project.members, setRows, { immediate: true })
watch(() => props.project.members, () => {
tableKey.value = useRandomId('table')
}, { immediate: true })
const isTransferingProject = ref(false)
const nextOwnerId = ref<string | undefined>(undefined)
Expand All @@ -146,7 +89,7 @@ async function addUserToProject() {
newUserEmail.value = ''
usersToAdd.value = []
newUserInputKey.value = getRandomId('input')
newUserInputKey.value = useRandomId('input')
}
async function removeUserFromProject(userId: string) {
Expand Down Expand Up @@ -177,8 +120,43 @@ async function transferOwnerShip() {
title="Membres du projet"
data-testid="teamTable"
:headers="headers"
:rows="rows"
/>
>
<tr
v-for="member in [{ ...props.project.owner, roleIds: [], userId: props.project.owner.id }, ...project.members]"
:key="member.userId"
>
<td>
<code
text="id"
title="Copier l'id"
:data-testid="member.userId"
class="fr-text-default--info text-xs truncate cursor-pointer"
@click="() => copyContent(member.userId)"
>{{ member.userId }}</code>
</td>
<td>{{ member.email }}</td>
<td>{{ project.ownerId === member.userId ? 'Propriétaire' : getRolesNames(member.roleIds) }}</td>
<td>
<div
v-if="props.project.ownerId === member.userId"
>
-
</div>
<div
v-else-if="member.userId === userStore.userProfile?.id"
class="fr-fi-close-line !flex justify-center cursor-pointer fr-text-default--warning"
title="Quitter le projet"
@click="() => removeUserFromProject(member.userId)"
/>
<div
v-else
class="fr-fi-close-line !flex justify-center cursor-pointer fr-text-default--warning"
:title="`Retirer ${member.email} du projet`"
@click="() => removeUserFromProject(member.userId)"
/>
</td>
</tr>
</DsfrTable>

<div
class="flex w-full items-end"
Expand Down
2 changes: 1 addition & 1 deletion apps/client/src/icon-collections.ts

Large diffs are not rendered by default.

19 changes: 18 additions & 1 deletion apps/client/src/stores/services-monitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const serviceHealthOptions = {
export const useServiceStore = defineStore('serviceMonitor', () => {
const callStastus = ref<'ok' | 'fetching' | 'error'>('fetching')

const displayCause = ref(false)
const services = ref<ServiceBody>([])

const serviceHealthIndex = computed<keyof typeof serviceHealthOptions>(() => {
Expand All @@ -82,14 +83,22 @@ export const useServiceStore = defineStore('serviceMonitor', () => {
const checkServicesHealth = async () => {
callStastus.value = 'fetching'
try {
services.value = await apiClient.Services.getServiceHealth()
services.value = await (displayCause.value
? apiClient.Services.getCompleteServiceHealth()
: apiClient.Services.getServiceHealth())
.then(res => extractData(res, 200))
callStastus.value = 'ok'
} catch (_error) {
callStastus.value = 'error'
}
}

const refreshServicesHealth = async () => {
await apiClient.Services.refreshServiceHealth()
.then(res => extractData(res, 200))
return checkServicesHealth()
}

const startHealthPolling = async () => {
if (!interval) return

Expand All @@ -98,10 +107,18 @@ export const useServiceStore = defineStore('serviceMonitor', () => {
interval = setInterval(checkServicesHealth, 300_000_000)
}

async function toggleDisplayCause() {
displayCause.value = !displayCause.value
await checkServicesHealth()
}

return {
displayCause,
servicesHealth,
services,
checkServicesHealth,
refreshServicesHealth,
toggleDisplayCause,
startHealthPolling,
}
})
8 changes: 8 additions & 0 deletions apps/client/src/utils/func.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,11 @@ export function clickInDialog(e?: MouseEvent | TouchEvent, fn?: () => void) {
}
fn?.()
}

function randomId() {
String.fromCharCode(97)
return (Array.from({ length: 6 })).map(() => String.fromCharCode(97 + Math.floor(Math.random() * 26)))
}
export function getRandomId(suffix?: string, prefix?: string) {
return (prefix ? (`${prefix}-`) : '') + randomId() + (suffix ? (`-${suffix}`) : '')
}
2 changes: 1 addition & 1 deletion apps/client/src/utils/project-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ import type {
projectRoleContract,
} from '@cpn-console/shared'

import { getRandomId } from '@gouvminint/vue-dsfr'
import {
apiClient,
extractData,
} from '@/api/xhr-client.js'
import { useUserStore } from '@/stores/user.js'
import { useLogStore } from '@/stores/log.js'
import { getRandomId } from './func.js'

export type ProjectOperations = 'create'
| 'delete'
Expand Down
Loading

0 comments on commit aaf3978

Please sign in to comment.