Skip to content

Commit

Permalink
Merge pull request #475 from cloud-pi-native/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
this-is-tobi committed Jul 13, 2023
2 parents 498827e + 6b0da80 commit 69bf3c5
Show file tree
Hide file tree
Showing 259 changed files with 7,864 additions and 5,890 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ node_modules
.env.test
.env.prod
.env.int
.env.codespace

# cypress
screenshots
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Liste des outils utilisés par le projet à installer sur son ordinateur :

- Install [Docker Desktop](https://www.docker.com/products/docker-desktop)
- Install [Docker](https://docs.docker.com/get-docker/)
- Install [Docker Compose Plugin](https://docs.docker.com/compose/install/)
- Install [Nodejs](https://nodejs.org/en/download/)
- Install [Pnpm](https://pnpm.io/installation)
Expand Down Expand Up @@ -39,6 +39,7 @@ La gestion des dépendances est effectuée à l'aide de [pnpm](https://pnpm.io/)
│ └── server/
├── packages
│ ├── test-utils/
│ ├── tsconfig/
│ └── shared/
├── node_modules/
├── package.json
Expand Down Expand Up @@ -75,6 +76,16 @@ pnpm run dev

De nombreuses commandes sont disponible dans le fichier `package.json` à la racine du projet, vous pouvez lancer ces dernières à l'aide de la commande `pnpm run <le_nom_du_script>`.

Pour faciliter les opérations de migrations de base de données via [Prisma](https://www.prisma.io/), un script est disponible :

```sh
# Lancer le script
pnpm --filter server run db:wrapper

# Voir l'aide du script
pnpm --filter server run db:wrapper -h
```

### Accès aux services

Interface graphique (Client): <http://localhost:8080>
Expand Down
7 changes: 4 additions & 3 deletions apps/client/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
root: true,
extends: [
Expand Down Expand Up @@ -28,6 +25,10 @@ module.exports = {
'comma-dangle': [2, 'always-multiline'],
'vue/no-v-html': 0,
'no-irregular-whitespace': 0,
'@typescript-eslint/no-unused-vars': 'off',
'no-unused-vars': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
},
overrides: [
{
Expand Down
12 changes: 7 additions & 5 deletions apps/client/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# Base stage
FROM docker.io/node:18.16.0-bullseye-slim AS base
FROM docker.io/node:18.16.1-bullseye-slim AS base

RUN npm install --location=global pnpm
WORKDIR /app
RUN chown node:node /app
COPY --chown=node:node pnpm-workspace.yaml pnpm-lock.yaml .npmrc ./
COPY --chown=node:node apps/client/ ./apps/client/
COPY --chown=node:node packages/shared/ ./packages/shared/
COPY --chown=node:node packages/tsconfig/ ./packages/tsconfig/
COPY --chown=node:node packages/test-utils/ ./packages/test-utils/
COPY --chown=node:node patches/ ./patches/

Expand All @@ -16,24 +17,25 @@ FROM base AS dev

USER node
RUN pnpm install --no-optional
RUN pnpm --filter shared run build
ENTRYPOINT [ "pnpm", "--filter", "client", "run", "dev" ]


# Build stage
FROM base AS build

ARG APP_VERSION
RUN pnpm --filter client --no-optional deploy build
WORKDIR /app/build
RUN npm run build
RUN pnpm install --no-optional
RUN pnpm --filter shared run build
RUN pnpm --filter client run build


# Prod stage
FROM docker.io/bitnami/nginx:1.24.0 AS prod

USER 0
RUN apt update && apt install -y gettext-base
COPY --chown=1001:0 --chmod=770 --from=build /app/build/dist /opt/bitnami/nginx/html/
COPY --chown=1001:0 --chmod=770 --from=build /app/apps/client/dist /opt/bitnami/nginx/html/
COPY --chown=1001:0 --chmod=660 ./apps/client/nginx/default.conf.tpl /default.conf.tpl
COPY --chown=1001:0 --chmod=660 ./apps/client/nginx/default.conf /opt/bitnami/nginx/conf/server_blocks/default.conf
COPY --chown=1001:0 ./apps/client/nginx/entrypoint.sh /docker-entrypoint-initdb.d/load-env.sh
Expand Down
6 changes: 4 additions & 2 deletions apps/client/cypress/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
FROM docker.io/cypress/included:12.14.0
FROM docker.io/cypress/included:12.17.1

RUN npm install --location=global pnpm
WORKDIR /app
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml .npmrc ./
COPY apps/client/package.json ./apps/client/
COPY apps/client/ ./apps/client/
COPY packages/shared/ ./packages/shared/
COPY packages/tsconfig/ ./packages/tsconfig/
COPY packages/test-utils/ ./packages/test-utils/
COPY patches/ ./patches/
RUN pnpm install
RUN pnpm --filter shared run build
ENTRYPOINT [ "pnpm", "--filter", "client", "run" ]
CMD [ "cypress:run" ]
124 changes: 124 additions & 0 deletions apps/client/cypress/components/specs/cluster-form.ct.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import VueDsfr from '@gouvminint/vue-dsfr'
import { createPinia } from 'pinia'
import '@gouvfr/dsfr/dist/dsfr.min.css'
import '@gouvfr/dsfr/dist/utility/icons/icons.min.css'
import '@gouvfr/dsfr/dist/utility/utility.main.min.css'
import '@gouvminint/vue-dsfr/styles'
import '@/main.css'
import * as icons from '@/icons.js'
import ClusterForm from '@/components/ClusterForm.vue'
import { getRandomCluster, getRandomProject, repeatFn } from 'test-utils'
import { useSnackbarStore } from '@/stores/snackbar.js'
import { useAdminClusterStore } from '@/stores/admin/cluster.js'

describe('ClusterForm.vue', () => {
it('Should mount a new cluster ClusterForm', () => {
const pinia = createPinia()

useSnackbarStore(pinia)

const allProjects = repeatFn(5)(getRandomProject)

const props = {
allProjects,
}

const extensions = {
use: [
[
VueDsfr, { icons: Object.values(icons) },
],
],
global: {
plugins: [pinia],
},
}

cy.mount(ClusterForm, { extensions, props })
cy.getByDataTestid('labelInput')
.find('input')
.type('label')
cy.getByDataTestid('clusterResourcesCbx').find('input[type=checkbox]')
.check({ force: true })
cy.get('#privacy-select')
.select('dedicated')
cy.get('#multi-select')
.select(`${allProjects[0].organization.name} - ${allProjects[0].name}`)
cy.getByDataTestid('addClusterBtn').should('be.enabled')
})

it('Should mount an update cluster ClusterForm', () => {
const pinia = createPinia()

useSnackbarStore(pinia)
const adminClusterStore = useAdminClusterStore(pinia)

const allProjects = repeatFn(5)(getRandomProject)
adminClusterStore.clusters = [getRandomCluster([allProjects[0].id])]

const props = {
cluster: adminClusterStore.clusters[0],
allProjects,
isNewCluster: false,
}

const extensions = {
use: [
[
VueDsfr, { icons: Object.values(icons) },
],
],
global: {
plugins: [pinia],
},
}

cy.mount(ClusterForm, { extensions, props })

cy.getByDataTestid('user-json').should('be.visible')
cy.getByDataTestid('cluster-json').should('be.visible')
cy.getByDataTestid('labelInput')
.find('input')
.should('have.value', props.cluster.label)
.and('be.disabled')
cy.getByDataTestid('clusterResourcesCbx').find('input[type=checkbox]')
.should(props.cluster.clusterResources ? 'be.checked' : 'not.be.checked')
cy.get('#privacy-select')
.should('have.value', props.cluster.privacy)
cy.get('#privacy-select')
.select('dedicated')
cy.get('[data-testid$="-tag"]').should('have.length', props.cluster.projectsId.length)
cy.getByDataTestid('updateClusterBtn').should('be.enabled')
})

it('Should disable project selector when privacy is public', () => {
const pinia = createPinia()

useSnackbarStore(pinia)

const allProjects = repeatFn(5)(getRandomProject)

const props = {
allProjects,
}

const extensions = {
use: [
[
VueDsfr, { icons: Object.values(icons) },
],
],
global: {
plugins: [pinia],
},
}

cy.mount(ClusterForm, { extensions, props })
cy.get('#privacy-select')
.select('dedicated')
cy.get('#multi-select').should('be.visible')
cy.get('#privacy-select')
.select('public')
cy.get('#multi-select').should('not.to.exist')
})
})
49 changes: 49 additions & 0 deletions apps/client/cypress/components/specs/multi-selector.ct.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import VueDsfr from '@gouvminint/vue-dsfr'
import '@gouvfr/dsfr/dist/dsfr.min.css'
import '@gouvfr/dsfr/dist/utility/icons/icons.min.css'
import '@gouvfr/dsfr/dist/utility/utility.main.min.css'
import '@gouvminint/vue-dsfr/styles'
import '@/main.css'
import * as icons from '@/icons.js'
import MultiSelector from '@/components/MultiSelector.vue'

describe('MultiSelector.vue', () => {
it('Should mount a MultiSelector', () => {
const props = {
options: [
{
name: 'name1',
id: '1',
}, {
name: 'name2',
id: '2',
},
],
}

const extensions = {
use: [
[
VueDsfr, { icons: Object.values(icons) },
],
],
}

cy.mount(MultiSelector, { extensions, props })
cy.get('[data-testid$="-tag"]').should('not.exist')
cy.get('option')
.should('have.length', props.options.length + 1)
cy.get('#multi-select')
.select(props.options[1].name)
cy.getByDataTestid(`${props.options[1].name}-tag`)
.should('be.visible')
cy.get('#multi-select')
.select(props.options[0].name)
cy.getByDataTestid(`${props.options[0].name}-tag`)
.should('be.visible')
cy.get('[data-testid$="-tag"]').should('have.length', 2)
cy.getByDataTestid(`${props.options[0].name}-tag`)
.click()
cy.get('[data-testid$="-tag"]').should('have.length', 1)
})
})
17 changes: 10 additions & 7 deletions apps/client/cypress/components/specs/permission-form.ct.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import '@gouvfr/dsfr/dist/utility/utility.main.min.css'
import '@/main.css'
import * as icons from '@/icons.js'
import PermissionForm from '@/components/PermissionForm.vue'
import { createRandomDbSetup, getRandomUser } from 'test-utils'
import { createRandomDbSetup, getRandomUser, getRandomUserProject } from 'test-utils'
import { useProjectStore } from '@/stores/project.js'
import { useUserStore } from '@/stores/user.js'

Expand All @@ -23,13 +23,16 @@ describe('PermissionForm.vue', () => {
projectStore.selectedProjectOwner = randomDbSetup.users[0]
userStore.userProfile = randomDbSetup.users[1]

const userToLicence = {
...getRandomUserProject(),
user: getRandomUser(),
}
projectStore.selectedProject.roles = [userToLicence, ...randomDbSetup.project.roles]

const environment = projectStore.selectedProject?.environments[0]
const ownerPermission = environment.permissions.find(permission => permission.user.email === projectStore.selectedProjectOwner.email)
const userPermission = environment.permissions.find(permission => permission.user.email !== projectStore.selectedProjectOwner.email)

const userToLicence = getRandomUser()
randomDbSetup.project.users = [userToLicence, ...randomDbSetup.project.users]

const props = {
environment,
}
Expand Down Expand Up @@ -86,11 +89,11 @@ describe('PermissionForm.vue', () => {
cy.get('label')
.should('contain', `E-mail de l'utilisateur à accréditer sur l'environnement de ${props.environment?.name}`)
cy.get('.fr-hint-text')
.should('contain', `Entrez l'e-mail d'un membre du projet ${projectStore.selectedProject.name}. Ex : ${userToLicence.email}`)
.should('contain', `Entrez l'e-mail d'un membre du projet ${projectStore.selectedProject.name}. Ex : ${userToLicence.user.email}`)
cy.get('datalist#suggestionList')
.find('option')
.should('have.length', randomDbSetup.project.users.length - props.environment.permissions.length)
.should('have.value', userToLicence.email)
.should('have.length', projectStore.selectedProject.roles.length - props.environment.permissions.length)
.should('have.value', userToLicence.user.email)
})
})
it('Should mount a PermissionForm with no user to licence', () => {
Expand Down
Loading

0 comments on commit 69bf3c5

Please sign in to comment.