Skip to content

Commit 8139f14

Browse files
authored
Merge pull request #24 from Libertech-FR/app-developement
App developement
2 parents 6aad6ed + d84ca50 commit 8139f14

File tree

127 files changed

+6460
-1183
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+6460
-1183
lines changed

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ module.exports = {
2323
'@typescript-eslint/explicit-function-return-type': 'off',
2424
'@typescript-eslint/explicit-module-boundary-types': 'off',
2525
'@typescript-eslint/no-inferrable-types': 'off',
26-
'@typescript-eslint/no-explicit-any': 'off',
26+
'@typescript-eslint/no-explicit-any': 'error',
2727
'@typescript-eslint/no-var-requires': 'off',
2828
},
2929
}

Makefile

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
IMGNAME?=ghcr.io/libertech-fr/teaket:latest
22
APPNAME?=teaket
3+
MINIO_ACCESS_KEY?=AKIAIOSFODNN7EXAMPLE
4+
MINIO_SECRET_KEY?=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
35

46
.DEFAULT_GOAL := help
57
help:
68
@printf "\033[33mUsage:\033[0m\n make [target] [arg=\"val\"...]\n\n\033[33mTargets:\033[0m\n"
79
@grep -E '^[-a-zA-Z0-9_\.\/]+:.*?## .*$$' $(MAKEFILE_LIST) \
810
| sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[32m%-15s\033[0m %s\n", $$1, $$2}'
911

12+
run-app:
13+
cd ./app && yarn dev
14+
15+
run-service:
16+
cd ./service && yarn start:dev
17+
18+
run: ## Run app and service
19+
@make dbs &
20+
@make run-app &
21+
@make run-service &
22+
1023
dbs: ## Start databases
1124
@docker volume create $(APPNAME)-mongodb
1225
@docker run -d --rm \
@@ -21,18 +34,39 @@ dbs: ## Start databases
2134
@docker volume create $(APPNAME)-redis
2235
@docker run -d --rm \
2336
--name $(APPNAME)-redis \
37+
-v $(APPNAME)-redis:/data \
2438
--network dev \
2539
-p 6379:6379 \
26-
redis
27-
@sleep 1
40+
redis || true
41+
@docker volume create $(APPNAME)-minio
42+
@docker run -d --rm \
43+
-p 9000:9000 \
44+
-p 9090:9090 \
45+
--name $(APPNAME)-minio \
46+
--network dev \
47+
-v $(APPNAME)-minio:/data \
48+
-e "MINIO_ACCESS_KEY=$(MINIO_ACCESS_KEY)" \
49+
-e "MINIO_SECRET_KEY=$(MINIO_SECRET_KEY)" \
50+
minio/minio server /data --console-address ":9090" || true
51+
@docker run --rm -it \
52+
--network dev \
53+
-e MINIO_BUCKET="teaket" \
54+
--entrypoint sh minio/mc -c "\
55+
mc config host add myminio http://teaket-minio:9000 \$(MINIO_ACCESS_KEY) \$(MINIO_SECRET_KEY) && \
56+
(mc mb myminio/teaket || true) \
57+
" || true
2858
@docker exec -it teaket-mongodb mongo --eval "rs.initiate({_id: 'rs0', members: [{_id: 0, host: '127.0.0.1:27017'}]})" || true
2959

3060
stop-dbs: ## Stop databases
3161
@docker stop $(APPNAME)-redis || true
3262
@docker stop $(APPNAME)-mongodb || true
63+
@docker stop $(APPNAME)-minio || true
3364

3465
buildseeds: ## Build populate image
3566
docker build -t seeding -f ./populate/Dockerfile ./populate
3667

3768
populate-db: ## Populate database
38-
docker run --rm --network dev -v ./populate:/app -v ./service/.dev-token.json:/app/.dev-token.json seeding
69+
docker run --rm --network dev -v $(CURDIR)/populate:/app -v $(CURDIR)/service/.dev-token.json:/app/.dev-token.json seeding
70+
71+
populate-from-gaiasys: ## Populate database
72+
docker run --rm --network dev -v $(CURDIR)/populate:/app -v $(CURDIR)/service/.dev-token.json:/app/.dev-token.json seeding python populate_from_gaiasys.py

app/nuxt.config.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import pugPlugin from 'vite-plugin-pug'
33
import openapiTS from 'openapi-typescript'
44
import { writeFileSync } from 'fs'
55
import { resolve } from 'path'
6+
import timezone from 'dayjs/plugin/timezone'
67

78
const TK_APP_API_URL = process.env.TK_APP_API_URL || 'http://localhost:7100'
89

@@ -27,15 +28,7 @@ export default defineNuxtConfig({
2728
global: true,
2829
dirs: [{ path: '~/components', prefix: 'tk' }],
2930
},
30-
modules: [
31-
'@nuxt-alt/auth',
32-
'@nuxt-alt/http',
33-
'@pinia/nuxt',
34-
'nuxt-quasar-ui',
35-
'@vueuse/nuxt',
36-
'dayjs-nuxt',
37-
...appSetup(),
38-
],
31+
modules: ['@nuxt-alt/auth', '@nuxt-alt/http', '@pinia/nuxt', 'nuxt-quasar-ui', '@vueuse/nuxt', 'dayjs-nuxt', ...appSetup()],
3932
auth: {
4033
globalMiddleware: true,
4134
rewriteRedirects: true,
@@ -73,19 +66,38 @@ export default defineNuxtConfig({
7366
},
7467
},
7568
},
69+
dayjs: {
70+
locales: ['fr', 'en'],
71+
defaultLocale: 'fr',
72+
defaultTimezone: 'Paris',
73+
plugins: ['timezone', 'relativeTime'],
74+
},
75+
pinia: {
76+
autoImports: ['defineStore'],
77+
},
7678
appConfig: {
7779
customSlots: {},
7880
},
7981
quasar: {
8082
iconSet: 'mdi-v5',
83+
plugins: ['Notify'],
84+
config: {
85+
notify: {
86+
timeout: 2500,
87+
position: 'top-right',
88+
actions: [{ icon: 'mdi-close', color: 'white' }],
89+
},
90+
},
8191
},
8292
vite: {
8393
define: {
8494
'process.env.DEBUG': process.env.NODE_ENV === 'development',
8595
},
8696
plugins: [
97+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
8798
pugPlugin(<any>{
8899
pretty: true,
100+
compilerOptions: {},
89101
}),
90102
],
91103
},
@@ -100,7 +112,7 @@ export default defineNuxtConfig({
100112
shim: false,
101113
},
102114
hooks: {
103-
'ready': async () => {
115+
ready: async () => {
104116
console.log('[OpenapiTS] Generating .nuxt/types/service-api.d.ts...')
105117
try {
106118
const fileData = await openapiTS(`${TK_APP_API_URL}/swagger/json`)
@@ -109,6 +121,6 @@ export default defineNuxtConfig({
109121
} catch (error) {
110122
console.debug('[OpenapiTS] Error while generating .nuxt/types/service-api.d.ts', error)
111123
}
112-
}
113-
}
124+
},
125+
},
114126
})

app/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,23 @@
1616
"@nuxt-alt/http": "^1.6.8",
1717
"@pinia/nuxt": "^0.4.11",
1818
"@quasar/extras": "^1.16.6",
19+
"@tiptap/pm": "^2.1.11",
20+
"@tiptap/starter-kit": "^2.1.11",
21+
"@tiptap/vue-3": "^2.1.11",
1922
"@vueuse/router": "^10.4.1",
23+
"bson-objectid": "^2.0.4",
2024
"cookie": "^0.5.0",
2125
"pinia": "^2.1.6",
2226
"quasar": "^2.12.6"
2327
},
2428
"devDependencies": {
2529
"@nuxt/devtools": "latest",
2630
"@types/node": "^18.17.3",
31+
"@typescript-eslint/eslint-plugin": "^6.6.0",
32+
"@typescript-eslint/parser": "^6.6.0",
2733
"@vueuse/core": "^10.4.1",
2834
"@vueuse/nuxt": "^10.4.1",
2935
"dayjs-nuxt": "^1.1.2",
30-
"@typescript-eslint/eslint-plugin": "^6.6.0",
31-
"@typescript-eslint/parser": "^6.6.0",
3236
"eslint": "^8.49.0",
3337
"nuxt": "~3.6.5",
3438
"nuxt-quasar-ui": "^2.0.5",
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<template>
2+
<editor-content :editor="editor" />
3+
</template>
4+
5+
<script setup>
6+
import { useEditor, EditorContent } from '@tiptap/vue-3'
7+
import StarterKit from '@tiptap/starter-kit'
8+
9+
const editor = useEditor({
10+
content: '<p>I’m running Tiptap with Vue.js. 🎉</p>',
11+
extensions: [
12+
StarterKit,
13+
],
14+
})
15+
</script>

app/src/components/appbar/Menu.vue

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,30 @@ q-btn(flat icon="mdi-dots-grid" size="xl")
66
.col-4(v-for="app in apps" :key="app.name")
77
q-btn(flat stack dense :to="app.to" rounded).full-width
88
q-icon(:name="app.icon.name" :color="app.icon.color" size="xl")
9+
q-badge(v-if="app.badge" :color="app.badge.color" floating) {{ app.badge.value }}
910
div.text-center(:class="`text-${app.title.color}`") {{ app.title.name }}
11+
1012
</template>
1113

1214
<script lang="ts" setup>
15+
import { usePinia, useQuasar } from "#imports";
16+
const store = usePinia()
17+
const $q = useQuasar()
18+
const user = store.state.value.auth.user
19+
const { data, error } = await useHttpApi('/tickets/ticket', {
20+
method: 'get',
21+
query: {
22+
'filters[@lifestep][]': 1,
23+
'filters[^envelope.assigned.name]': `/${user.displayName}/`,
24+
}
25+
})
26+
if (error.value) {
27+
$q.notify({
28+
message: 'Impossible de charger les tickets',
29+
type: 'negative'
30+
})
31+
}
32+
const baseFilter = 'sort[metadata.lastUpdatedAt]=desc&skip=0&limit=10'
1333
const apps: {
1434
title: {
1535
name: string
@@ -41,7 +61,11 @@ const apps: {
4161
name: 'mdi-ticket',
4262
color: 'primary'
4363
},
44-
to: '/tickets'
64+
to: `/tickets?filters[^envelope.assigned.name]=/${user.displayName}/&filters[@lifestep][]=1&${baseFilter}`,
65+
badge: {
66+
color: 'red',
67+
value: data.value.total
68+
}
4569
},
4670
{
4771
title: {
@@ -52,7 +76,7 @@ const apps: {
5276
name: 'mdi-ticket',
5377
color: 'primary'
5478
},
55-
to: '/tickets'
79+
to: `/tickets?filters[@lifestep][]=1&${baseFilter}`
5680
},
5781
{
5882
title: {
@@ -88,4 +112,6 @@ const apps: {
88112
to: '/deconnexion'
89113
}
90114
]
115+
116+
91117
</script>

app/src/components/searchfilters/Main.vue

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,39 @@
11
<template lang="pug">
22
.row.q-gutter-sm.items-center.q-mt-sm
3-
//- .col.col-md-2
4-
//- q-select(:options="fieldTypes" label="Type de champ" v-model="fieldType" clearable @update:model-value="clearFields(['field', 'comparator'])")
5-
.col.col-md-2
6-
q-select(:options="fields" label="Champs" v-model="field" clearable @update:model-value="onFieldChange($event)")
7-
.col.col-md-2
8-
q-select(:options="comparatorFilteredByType" label="Comparateurs" v-model="comparator" clearable @update:model-value="clearFields([])" :disable="isFieldDisabled.comparator")
9-
template(v-slot:selected-item="scope")
10-
q-icon(:name="scope.opt.icon" size="xs")
11-
template(v-slot:option="scope")
12-
q-item(v-bind="scope.itemProps")
13-
q-item-section(avatar)
14-
q-icon(:name="scope.opt.icon")
15-
q-item-section
16-
q-item-label
17-
span {{ scope.opt.label }}
18-
19-
.col-12.col-md-2(v-show="!comparator?.multiplefields")
20-
q-input(v-model="search" label="Rechercher" clearable :type="searchInputType" :disable="isFieldDisabled.search" :prefix="comparator?.prefix" :suffix="comparator?.suffix")
21-
.col-6.col-md-2(v-show="comparator?.multiplefields")
22-
q-input(v-model="searchMin" label="Min" clearable :type="searchInputType" :disable="isFieldDisabled.search" )
23-
.col-6.col-md-2(v-show="comparator?.multiplefields")
24-
q-input(v-model="searchMax" label="Max" clearable :type="searchInputType" :disable="isFieldDisabled.search" )
25-
.col-12.col-md-1
26-
q-btn(color="primary" @click="addFilter" :disable="isFieldDisabled.addButton") Ajouter
27-
q-space
28-
.col-12.col-md-2
29-
tk-SearchfiltersRightSelect(ref="rightSelect")
3+
//- .col.col-md-2
4+
//- q-select(:options="fieldTypes" label="Type de champ" v-model="fieldType" clearable @update:model-value="clearFields(['field', 'comparator'])")
5+
.col.col-md-2
6+
q-select(:options="fields" label="Champs" v-model="field" clearable @update:model-value="onFieldChange($event)")
7+
.col.col-md-2
8+
q-select(:options="comparatorFilteredByType" label="Comparateurs" v-model="comparator" clearable @update:model-value="clearFields([])" :disable="isFieldDisabled.comparator")
9+
template(v-slot:selected-item="scope")
10+
q-icon(:name="scope.opt.icon" size="xs")
11+
template(v-slot:option="scope")
12+
q-item(v-bind="scope.itemProps")
13+
q-item-section(avatar)
14+
q-icon(:name="scope.opt.icon")
15+
q-item-section
16+
q-item-label
17+
span {{ scope.opt.label }}
18+
19+
.col-12.col-md-2(v-show="!comparator?.multiplefields")
20+
q-input(v-model="search" label="Rechercher" clearable :type="searchInputType" :disable="isFieldDisabled.search" :prefix="comparator?.prefix" :suffix="comparator?.suffix")
21+
.col-6.col-md-2(v-show="comparator?.multiplefields")
22+
q-input(v-model="searchMin" label="Min" clearable :type="searchInputType" :disable="isFieldDisabled.search" )
23+
.col-6.col-md-2(v-show="comparator?.multiplefields")
24+
q-input(v-model="searchMax" label="Max" clearable :type="searchInputType" :disable="isFieldDisabled.search" )
25+
.col-12.col-md-1
26+
q-btn(color="primary" @click="addFilter" :disable="isFieldDisabled.addButton") Ajouter
27+
q-space
28+
.col-12.col-md-2
29+
tk-SearchfiltersRightSelect(ref="rightSelect")
3030
</template>
3131

3232
<script lang="ts" setup>
3333
import { ref, computed, inject } from 'vue'
3434
import { useRouter, useRoute } from 'nuxt/app'
3535
import { useDayjs } from '#imports';
36+
import { pushQuery } from '~/composables'
3637
import type { Filter, Field, Comparator, SearchFilter } from '~/types'
3738
const dayjs = useDayjs()
3839
@@ -70,7 +71,7 @@ const comparatorTypes = ref<Comparator[]>([
7071
{ label: 'Inférieur à', querySign: '<', value: '<', icon: 'mdi-less-than', type: ['number', 'date'], multiplefields: false, prefix: '', suffix: '' },
7172
{ label: 'Inférieur ou égal à', querySign: '<=', value: '<=', icon: 'mdi-less-than-or-equal', type: ['number', 'date'], multiplefields: false, prefix: '', suffix: '' },
7273
{ label: 'entre', querySign: '<<', value: 'between', icon: 'mdi-arrow-expand-horizontal', type: ['number', 'date'], multiplefields: true, prefix: '', suffix: '' },
73-
{ label: 'Contiens', querySign: '^', value: '^', icon: 'mdi-apple-keyboard-control', type: ['text'], multiplefields: false, prefix: '/', suffix: '/' },
74+
{ label: 'Contiens', querySign: '^', value: '^', icon: 'mdi-apple-keyboard-control', type: ['text'], multiplefields: false, prefix: '/', suffix: '/i' },
7475
{ label: 'Commence par', querySign: '^', value: '/^', icon: 'mdi-apple-keyboard-control', type: ['text'], multiplefields: false, prefix: '/^', suffix: '/' },
7576
{ label: 'Fini par', querySign: '^', value: '$/', icon: 'mdi-apple-keyboard-control', type: ['text'], multiplefields: false, prefix: '/', suffix: '$/' },
7677
{ label: 'Egal à', querySign: '@', value: '@', icon: 'mdi-apple-keyboard-control', type: [], multiplefields: true, prefix: '', suffix: '' },
@@ -95,11 +96,11 @@ const addFilter = async () => {
9596
if (!searchFilter) return
9697
if (searchFilter.comparator.multiplefields) {
9798
for (const { key, value } of parseMultipleFilter(searchFilter)) {
98-
await pushQuery(key, value)
99+
await pushQuery({ key, value })
99100
}
100101
} else {
101102
const { key, value } = parseSimpleFilter(searchFilter)
102-
await pushQuery(key, value)
103+
await pushQuery({ key, value })
103104
}
104105
}
105106
@@ -130,15 +131,15 @@ const parseMultipleFilter = (searchFilter: SearchFilter) => {
130131
return [min, max]
131132
}
132133
133-
const pushQuery = async (key: string, value: string) => {
134-
const query = {
135-
...route.query,
136-
}
137-
query[key] = value
138-
await router.push({
139-
query
140-
})
141-
}
134+
// const pushQuery = async (key: string, value: string) => {
135+
// const query = {
136+
// ...route.query,
137+
// }
138+
// query[key] = value
139+
// await router.push({
140+
// query
141+
// })
142+
// }
142143
143144
const getSearchFilter = computed(() => {
144145
if (field.value === undefined || field.value === null) return null

0 commit comments

Comments
 (0)