Added Eslint + TS corrections
This commit is contained in:
parent
de29cda24f
commit
847a543dab
22 changed files with 2701 additions and 372 deletions
40
.eslintrc.json
Normal file
40
.eslintrc.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:vue/vue3-strongly-recommended",
|
||||
"@vue/eslint-config-typescript"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.vue"],
|
||||
"rules": {
|
||||
"no-undef": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.vue"],
|
||||
"rules": {
|
||||
"indent": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"parser": "vue-eslint-parser",
|
||||
"parserOptions": {
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["vue", "@typescript-eslint"],
|
||||
"ignorePatterns": ["webpack.mix.js", "**/vendor/*.js", "**/vendor/**/*.js"],
|
||||
"rules": {
|
||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"quotes": ["error", "double"],
|
||||
"semi": ["error", "always"],
|
||||
"vue/script-indent": ["error", 2, { "baseIndent": 0 }]
|
||||
}
|
||||
}
|
||||
1788
package-lock.json
generated
1788
package-lock.json
generated
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
|
@ -15,30 +15,38 @@
|
|||
"@fortawesome/free-brands-svg-icons": "^6.1.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.1.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.1",
|
||||
"@popperjs/core": "^2.11.5",
|
||||
"@types/bootstrap": "^5.1.12",
|
||||
"@types/toastify-js": "^1.11.1",
|
||||
"@types/vue-select": "^3.16.0",
|
||||
"@types/webpack-env": "^1.17.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.35.1",
|
||||
"@typescript-eslint/parser": "^5.35.1",
|
||||
"axios": "^0.21.1",
|
||||
"bootstrap": "^5.1.3",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"cross-env": "^7.0",
|
||||
"css-loader": "^6.7.1",
|
||||
"del-cli": "^4.0.1",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-plugin-vue": "^9.4.0",
|
||||
"eslint-webpack-plugin": "^3.2.0",
|
||||
"glightbox": "^3.2.0",
|
||||
"laravel-mix": "^6.0.6",
|
||||
"laravel-mix-clean": "^0.1.0",
|
||||
"laravel-mix-eslint": "^0.2.0",
|
||||
"laravel-mix-polyfill": "^3.0.1",
|
||||
"lodash": "^4.17.19",
|
||||
"moment": "^2.29.3",
|
||||
"prettier": "^2.7.1",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"sass": "^1.52.1",
|
||||
"sass-loader": "^12.6.0",
|
||||
"sweetalert2": "^11.4.16",
|
||||
"toastify-js": "^1.11.2",
|
||||
"ts-loader": "^9.3.0",
|
||||
"typescript": "^4.7.3",
|
||||
"typescript": "^4.7.4",
|
||||
"vue": "^3.2.36",
|
||||
"vue-loader": "^16.8.3",
|
||||
"vue-select": "^4.0.0-beta.3"
|
||||
|
|
|
|||
5
resources/ts/@types/glightbox/index.d.ts
vendored
Normal file
5
resources/ts/@types/glightbox/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
declare module "glightbox" {
|
||||
export default class GLightbox {
|
||||
constructor(options: { [key: string]: unknown });
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
import axios from "axios";
|
||||
// @ts-ignore Pas de déclaration ts disponible
|
||||
import GLightbox from "glightbox";
|
||||
import * as bootstrap from "bootstrap";
|
||||
|
||||
const bootstrap = require("bootstrap");
|
||||
const metaCSRFToken = document.querySelector("meta[name='csrf-token']");
|
||||
|
||||
if (!metaCSRFToken) {
|
||||
throw new Error("Missing meta CSRF token");
|
||||
}
|
||||
|
||||
/**
|
||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||
|
|
@ -12,17 +16,15 @@ const bootstrap = require("bootstrap");
|
|||
axios.defaults.headers.common = {
|
||||
Accept: "application/json, text/plain, */*",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
"X-CSRF-TOKEN": document
|
||||
.querySelector('meta[name="csrf-token"]')!
|
||||
.getAttribute("content"),
|
||||
"X-CSRF-TOKEN": metaCSRFToken.getAttribute("content"),
|
||||
};
|
||||
|
||||
window.axios = axios;
|
||||
window.bootstrap = bootstrap;
|
||||
|
||||
// enable bs tooltips
|
||||
var tooltipTriggerList = [].slice.call(
|
||||
document.querySelectorAll('[data-bs-toggle="tooltip"]')
|
||||
const tooltipTriggerList = [].slice.call(
|
||||
document.querySelectorAll("[data-bs-toggle='tooltip']")
|
||||
);
|
||||
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
|
|
|
|||
273
resources/ts/components/InvoiceTasksComponent.vue
Normal file
273
resources/ts/components/InvoiceTasksComponent.vue
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
<template>
|
||||
<div v-if="!companies.length">
|
||||
<span class="h3 text-danger">{{
|
||||
__("Pour utiliser ce composant il faut des :compagnies", {
|
||||
compagnies: __("models.classes.companies"),
|
||||
})
|
||||
}}</span>
|
||||
</div>
|
||||
<div v-else-if="!packages.length">
|
||||
<span class="h3 text-danger">{{
|
||||
__("Pour utiliser ce composant il faut des :packages", {
|
||||
packages: __("models.classes.packages"),
|
||||
})
|
||||
}}</span>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="tasks table-responsive"
|
||||
>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>{{ __("Tâches") }}</th>
|
||||
<th>{{ __("Type") }}</th>
|
||||
<th width="100">
|
||||
{{ __("Jours") }}
|
||||
</th>
|
||||
<th width="100">
|
||||
{{ __("Montant") }}
|
||||
</th>
|
||||
<th />
|
||||
</thead>
|
||||
<tbody v-if="tasks.length">
|
||||
<tr
|
||||
v-for="(task, index) in tasks"
|
||||
:key="index"
|
||||
>
|
||||
<td>
|
||||
<textarea
|
||||
v-model="task.desc"
|
||||
rows="2"
|
||||
class="form-control"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<select
|
||||
v-model="task.type"
|
||||
@change="updateAmount(index)"
|
||||
class="form-select"
|
||||
>
|
||||
<option
|
||||
v-for="(typeEnum, index) in taskTypeEnums"
|
||||
:value="typeEnum.value"
|
||||
:key="index"
|
||||
>
|
||||
{{ typeEnum.label }}
|
||||
</option>
|
||||
</select>
|
||||
<select
|
||||
v-if="task.type === getTaskTypeEnum('forfait').value"
|
||||
v-model="task.package"
|
||||
@change="updateAmount(index)"
|
||||
class="form-select"
|
||||
>
|
||||
<option
|
||||
v-for="(packageModel, index) in packages"
|
||||
:value="packageModel"
|
||||
:key="index"
|
||||
:selected="task.package === undefined && index === 0"
|
||||
>
|
||||
{{ packageModel.name }}
|
||||
</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
class="inputNumber"
|
||||
v-model="task.days"
|
||||
@change="updateAmount(index)"
|
||||
type="number"
|
||||
step="0.125"
|
||||
min="0"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
v-if="task.type === getTaskTypeEnum('libre').value"
|
||||
class="inputNumber"
|
||||
v-model="task.amount"
|
||||
type="number"
|
||||
min="0"
|
||||
>
|
||||
<template v-else>
|
||||
{{ task.amount.toFixed(2) }}
|
||||
</template> €
|
||||
</td>
|
||||
<td>
|
||||
<div
|
||||
class="btn-group"
|
||||
role="group"
|
||||
:aria-label="__('Ajouter ou enlever une ligne')"
|
||||
>
|
||||
<button
|
||||
class="btn btn-sm btn-primary"
|
||||
@click.prevent="addTasksRow(index)"
|
||||
>
|
||||
<font-awesome-icon icon="fa-solid fa-plus" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-sm btn-danger"
|
||||
@click.prevent="removeTasksRow(index)"
|
||||
>
|
||||
<font-awesome-icon icon="fa-solid fa-minus" />
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
colspan="4"
|
||||
class="text-end"
|
||||
>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click.prevent="addTasksRow()"
|
||||
>
|
||||
<font-awesome-icon icon="fa-solid fa-plus" />
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
{{ __("Total") }}
|
||||
</td>
|
||||
<td>{{ totalDays }}</td>
|
||||
<td>{{ Number.parseFloat(String(total)).toFixed(2) }} €</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
// import VueSelect from "vue-select";
|
||||
import { defineComponent } from "vue";
|
||||
import trans from "../modules/trans";
|
||||
|
||||
type TaskRow = {
|
||||
desc: string;
|
||||
days: number;
|
||||
type: number;
|
||||
amount: number;
|
||||
package: LaravelModel | null;
|
||||
};
|
||||
|
||||
type TaskType = Enum & { price: number };
|
||||
|
||||
export default defineComponent({
|
||||
mixins: [trans],
|
||||
components: {
|
||||
// VueSelect,
|
||||
FontAwesomeIcon,
|
||||
},
|
||||
mounted() {
|
||||
const json = String(this.$attrs.json ?? "{}"),
|
||||
data = JSON.parse(json);
|
||||
|
||||
this.companies = data.companies;
|
||||
this.packages = data.packages;
|
||||
this.taskTypeEnums = data.taskTypeEnums;
|
||||
this.taskRowModel = data.taskRowModel;
|
||||
|
||||
// * Use first enum value as default
|
||||
this.taskRowModel.type = this.getTaskTypeEnum("web").value as number;
|
||||
this.taskRowModel.package = this._packages[0];
|
||||
},
|
||||
data(): {
|
||||
tasks: TaskRow[];
|
||||
companies: LaravelModelList;
|
||||
packages: LaravelModelList;
|
||||
taskTypeEnums: TaskType[];
|
||||
taskRowModel: TaskRow;
|
||||
} {
|
||||
return {
|
||||
tasks: [],
|
||||
companies: [],
|
||||
packages: [],
|
||||
taskTypeEnums: [],
|
||||
taskRowModel: {
|
||||
desc: "",
|
||||
days: 0,
|
||||
type: 1,
|
||||
amount: 0,
|
||||
package: null,
|
||||
},
|
||||
};
|
||||
},
|
||||
computed__tasks: {
|
||||
total(): number {
|
||||
let total = 0;
|
||||
this.tasks.map((task) => (total += task.amount));
|
||||
return total;
|
||||
},
|
||||
totalDays(): number {
|
||||
let total = 0;
|
||||
this.tasks.map((task) => (total += task.days));
|
||||
return total;
|
||||
},
|
||||
},
|
||||
watch: {},
|
||||
methods: {
|
||||
/**
|
||||
* Get the coresponding task type using value or label
|
||||
*
|
||||
* @param type
|
||||
*/
|
||||
getTaskTypeEnum(type: string | number): TaskType {
|
||||
for (let task of this.taskTypeEnums) {
|
||||
if (
|
||||
typeof type === "string" &&
|
||||
task.label.toLowerCase() === type.toLowerCase()
|
||||
) {
|
||||
return task;
|
||||
}
|
||||
if (typeof type === "number" && task.value === type) {
|
||||
return task;
|
||||
}
|
||||
}
|
||||
throw new Error(`Task type '${type}' not found`);
|
||||
},
|
||||
addTasksRow(beforeIndex: number | null = null): void {
|
||||
if (beforeIndex !== null) {
|
||||
this.tasks.splice(beforeIndex, 0, Object.assign({}, this.taskRowModel));
|
||||
} else this.tasks.push(Object.assign({}, this.taskRowModel));
|
||||
},
|
||||
removeTasksRow(beforeIndex: number): void {
|
||||
this.tasks.splice(beforeIndex, 1);
|
||||
},
|
||||
updateAmount(index: number): void {
|
||||
const task = this.tasks[index];
|
||||
// task.type === getTaskTypeEnum('web').value ||
|
||||
// task.type === getTaskTypeEnum('sio').value
|
||||
switch (task.type) {
|
||||
case this.getTaskTypeEnum("web").value:
|
||||
case this.getTaskTypeEnum("sio").value:
|
||||
task.amount = task.days * this.getTaskTypeEnum(task.type).price;
|
||||
break;
|
||||
case this.getTaskTypeEnum("forfait").value:
|
||||
if (!task.package) {
|
||||
throw new Error(`task ${task.desc} has undefined package`);
|
||||
}
|
||||
task.amount = task.days * (task.package.amount as number);
|
||||
break;
|
||||
case this.getTaskTypeEnum("libre").value:
|
||||
// Do nothing, free input
|
||||
return;
|
||||
default:
|
||||
throw new Error(`Unhandled task type ${task.type}`);
|
||||
}
|
||||
this.tasks[index] = task;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "vue-select/src/scss/vue-select.scss";
|
||||
.tasks {
|
||||
.inputNumber {
|
||||
width: 6rem !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -7,17 +7,15 @@
|
|||
label="label"
|
||||
:options="labels"
|
||||
>
|
||||
<template v-slot:option="{ option }: { option: SelectModel }">
|
||||
<template #option="{ option }: { option: SelectModel }">
|
||||
<span
|
||||
class="py-1 px-2"
|
||||
:style="`background-color: ${(option as SelectModel).color};color: ${invertColor((option as SelectModel).color, true)};`"
|
||||
:style="`background-color: ${(option as SelectModel).color};color: ${invertColor((option as SelectModel).color, true)};`"
|
||||
>
|
||||
{{ String(option.label) }}
|
||||
</span>
|
||||
</template>
|
||||
<template
|
||||
v-slot:no-options="{ search, searching }: { search: string, searching: boolean }"
|
||||
>
|
||||
<template #no-options>
|
||||
{{ __("Pus de label disponibles") }}
|
||||
</template>
|
||||
</VueSelect>
|
||||
|
|
@ -27,7 +25,7 @@
|
|||
:key="label.value"
|
||||
:value="label.value"
|
||||
:name="`${name}[]`"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -44,7 +42,7 @@ export default defineComponent({
|
|||
},
|
||||
mounted() {
|
||||
const json = String(this.$attrs.json ?? "{}"),
|
||||
data = JSON.parse(json);
|
||||
data = JSON.parse(json);
|
||||
this.name = data.name;
|
||||
for (let label of data.value ?? []) {
|
||||
this.selectedLabels.push({
|
||||
|
|
@ -54,7 +52,11 @@ export default defineComponent({
|
|||
});
|
||||
}
|
||||
for (let label of data.labels) {
|
||||
this.labels.push({ label: label.name, value: label.id, color: label.color });
|
||||
this.labels.push({
|
||||
label: label.name,
|
||||
value: label.id,
|
||||
color: label.color,
|
||||
});
|
||||
}
|
||||
},
|
||||
data(): {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,27 @@
|
|||
<template>
|
||||
<!-- TODO: order by name, status -->
|
||||
<div ref="macroschedule" class="macroschedule">
|
||||
<div
|
||||
ref="macroschedule"
|
||||
class="macroschedule"
|
||||
>
|
||||
<div class="row mb-3">
|
||||
<div class="col-1">
|
||||
<button class="btn btn-primary" v-on:click.prevent="goPreviousWeek()">←</button>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click.prevent="goPreviousWeek()"
|
||||
>
|
||||
←
|
||||
</button>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h1 class="text-secondary">Plan de charge</h1>
|
||||
<h1 class="text-secondary">
|
||||
Plan de charge
|
||||
</h1>
|
||||
<div class="input-group">
|
||||
<label for="scheduleDateSelect" class="input-group-text">
|
||||
<label
|
||||
for="scheduleDateSelect"
|
||||
class="input-group-text"
|
||||
>
|
||||
Voir date :
|
||||
</label>
|
||||
<input
|
||||
|
|
@ -16,8 +29,12 @@
|
|||
class="form-control"
|
||||
type="date"
|
||||
:value="startMoment.format('YYYY-MM-DD')"
|
||||
v-on:input="showMacroScheduleDate($event.target ? ($event.target as HTMLInputElement).value : '')"
|
||||
/>
|
||||
@input="
|
||||
showMacroScheduleDate(
|
||||
$event.target ? ($event.target as HTMLInputElement).value : ''
|
||||
)
|
||||
"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
|
|
@ -27,7 +44,9 @@
|
|||
<span
|
||||
v-for="(activityEnum, index) of activitiesEnum"
|
||||
:key="index"
|
||||
:class="`p-1 m-2 border badge badge-activity-${String(activityEnum.value)}`"
|
||||
:class="`p-1 m-2 border badge badge-activity-${String(
|
||||
activityEnum.value
|
||||
)}`"
|
||||
>
|
||||
{{ String(activityEnum.label) }}
|
||||
</span>
|
||||
|
|
@ -41,7 +60,12 @@
|
|||
</fieldset>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<button class="btn btn-primary" v-on:click.prevent="goNextWeek()">→</button>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click.prevent="goNextWeek()"
|
||||
>
|
||||
→
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
|
|
@ -49,10 +73,18 @@
|
|||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" rowspan="3" class="align-middle">
|
||||
<th
|
||||
scope="col"
|
||||
rowspan="3"
|
||||
class="align-middle"
|
||||
>
|
||||
{{ isAdmin ? "Projets" : "" }}
|
||||
</th>
|
||||
<th scope="col" rowspan="3" class="align-middle">
|
||||
<th
|
||||
scope="col"
|
||||
rowspan="3"
|
||||
class="align-middle"
|
||||
>
|
||||
{{ isAdmin ? "Statut" : "" }}
|
||||
</th>
|
||||
<th
|
||||
|
|
@ -70,9 +102,8 @@
|
|||
{{ ucfirst(daysNextMonth[0].format("MMMM")) }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr v-if="macroscheduleConfig !== null">
|
||||
<th
|
||||
v-if="macroscheduleConfig !== null"
|
||||
v-for="weekNumber in macroscheduleConfig.numberOfWeeksToShow"
|
||||
:key="weekNumber"
|
||||
:colspan="7 - 2"
|
||||
|
|
@ -89,7 +120,7 @@
|
|||
:key="index"
|
||||
:class="
|
||||
'dayCell p-0 text-center ' +
|
||||
(currentDay.isSame(todayMoment, 'day') ? 'today' : '')
|
||||
(currentDay.isSame(todayMoment, 'day') ? 'today' : '')
|
||||
"
|
||||
>
|
||||
{{ currentDay.format("dd") }} {{
|
||||
|
|
@ -101,28 +132,36 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<template v-if="isAdmin">
|
||||
<tr v-for="(project, index) of projects" :key="index" class="projectRow">
|
||||
<tr
|
||||
v-for="(project, index) of projects"
|
||||
:key="index"
|
||||
class="projectRow"
|
||||
>
|
||||
<th scope="col">
|
||||
<a
|
||||
:href="getProjectRoute(project)"
|
||||
:class="
|
||||
'rounded-1 p-1 project text-nowrap text-truncate overflow-hidden bg-enum-' +
|
||||
project.status
|
||||
project.status
|
||||
"
|
||||
>
|
||||
{{ str_limit(String(project.name), 45) }}
|
||||
</a>
|
||||
</th>
|
||||
<td>
|
||||
<span class="fw-bold text-nowrap text-truncate overflow-hidden">
|
||||
{{ String(projectStatusEnum[project.status as number].label) }}
|
||||
<span
|
||||
class="fw-bold text-nowrap text-truncate overflow-hidden"
|
||||
>
|
||||
{{
|
||||
String(projectStatusEnum[project.status as number].label)
|
||||
}}
|
||||
</span>
|
||||
</td>
|
||||
<template v-for="(currentDay, index) of daysToShow">
|
||||
<td
|
||||
:class="
|
||||
'p-0 border border-dark activities ' +
|
||||
(currentDay.isSame(todayMoment, 'day') ? 'today' : '')
|
||||
(currentDay.isSame(todayMoment, 'day') ? 'today' : '')
|
||||
"
|
||||
v-if="dayShouldbeenSeen(currentDay)"
|
||||
:key="index"
|
||||
|
|
@ -135,23 +174,30 @@
|
|||
:key="index"
|
||||
:class="
|
||||
getActivityClass(activity) +
|
||||
' activity ' +
|
||||
(hoverActivityId === activity.id ? 'hover' : '')
|
||||
' activity ' +
|
||||
(hoverActivityId === activity.id ? 'hover' : '')
|
||||
"
|
||||
v-on:click="showModale(project, activity, currentDay, index === 0)"
|
||||
v-on:mouseover="setActivityHover(activity)"
|
||||
v-on:mouseleave="setActivityHover(activity, false)"
|
||||
@click="
|
||||
showModale(project, activity, currentDay, index === 0)
|
||||
"
|
||||
@mouseover="setActivityHover(activity)"
|
||||
@mouseleave="setActivityHover(activity, false)"
|
||||
>
|
||||
<div :title="getActivityTooltip(activity)" data-bs-toggle="tooltip">
|
||||
<div
|
||||
:title="getActivityTooltip(activity)"
|
||||
data-bs-toggle="tooltip"
|
||||
>
|
||||
|
||||
</div>
|
||||
<template v-if="projectHasMarkersForTheDay(currentDay, project)">
|
||||
<template
|
||||
v-if="projectHasMarkersForTheDay(currentDay, project)"
|
||||
>
|
||||
<div
|
||||
class="marker"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-html="true"
|
||||
:title="getMarkersTooltip(currentDay, project)"
|
||||
></div>
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -159,15 +205,18 @@
|
|||
</tr>
|
||||
</template>
|
||||
<tr class="projectRow">
|
||||
<th scope="col" class="border-end-0 d-flex justify-content-between">
|
||||
<th
|
||||
scope="col"
|
||||
class="border-end-0 d-flex justify-content-between"
|
||||
>
|
||||
<span class="fw-bold h5">Disponibilité</span>
|
||||
</th>
|
||||
<td class="border-start-0"></td>
|
||||
<td class="border-start-0" />
|
||||
<template v-for="(currentDay, index) of daysToShow">
|
||||
<td
|
||||
:class="
|
||||
'p-0 border border-dark activities ' +
|
||||
(currentDay.isSame(todayMoment, 'day') ? 'today' : '')
|
||||
(currentDay.isSame(todayMoment, 'day') ? 'today' : '')
|
||||
"
|
||||
v-if="dayShouldbeenSeen(currentDay)"
|
||||
:key="index"
|
||||
|
|
@ -177,18 +226,22 @@
|
|||
class="activity text-center"
|
||||
:style="{
|
||||
'background-color':
|
||||
'rgba(0,0,0,' + getLoadPercent(getMorningMoment(currentDay)),
|
||||
'rgba(0,0,0,' +
|
||||
getLoadPercent(getMorningMoment(currentDay)),
|
||||
}"
|
||||
>
|
||||
{{
|
||||
getLoad(getMorningMoment(currentDay)) > 1 ? "🔥" : " "
|
||||
getLoad(getMorningMoment(currentDay)) > 1
|
||||
? "🔥"
|
||||
: " "
|
||||
}}
|
||||
</div>
|
||||
<div
|
||||
class="activity text-center"
|
||||
:style="{
|
||||
'background-color':
|
||||
'rgba(0,0,0,' + getLoadPercent(getAfterNoonMoment(currentDay)),
|
||||
'rgba(0,0,0,' +
|
||||
getLoadPercent(getAfterNoonMoment(currentDay)),
|
||||
}"
|
||||
>
|
||||
{{
|
||||
|
|
@ -203,10 +256,10 @@
|
|||
v-if="macroscheduleConfig !== null"
|
||||
:class="
|
||||
'activity text-center ' +
|
||||
(getLoad(getMorningMoment(currentDay)) >
|
||||
macroscheduleConfig.loadDevThreshold
|
||||
? 'bg-dark'
|
||||
: 'bg-light')
|
||||
(getLoad(getMorningMoment(currentDay)) >
|
||||
macroscheduleConfig.loadDevThreshold
|
||||
? 'bg-dark'
|
||||
: 'bg-light')
|
||||
"
|
||||
>
|
||||
|
||||
|
|
@ -215,10 +268,10 @@
|
|||
v-if="macroscheduleConfig !== null"
|
||||
:class="
|
||||
'activity text-center ' +
|
||||
(getLoad(getAfterNoonMoment(currentDay)) >
|
||||
macroscheduleConfig.loadDevThreshold
|
||||
? 'bg-dark'
|
||||
: 'bg-light')
|
||||
(getLoad(getAfterNoonMoment(currentDay)) >
|
||||
macroscheduleConfig.loadDevThreshold
|
||||
? 'bg-dark'
|
||||
: 'bg-light')
|
||||
"
|
||||
>
|
||||
|
||||
|
|
@ -248,19 +301,30 @@
|
|||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalLabel" ref="modalLabel">
|
||||
<h5
|
||||
class="modal-title"
|
||||
id="modalLabel"
|
||||
ref="modalLabel"
|
||||
>
|
||||
Activité pour {{ modaleProps.name }}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div v-if="error" class="alert alert-danger" role="alert">
|
||||
<div
|
||||
v-if="error"
|
||||
class="alert alert-danger"
|
||||
role="alert"
|
||||
>
|
||||
{{ error }}
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<div class="form-group mb-3">
|
||||
<label for="categorie" class="col-form-label text-md-right ms-5">
|
||||
<label
|
||||
for="categorie"
|
||||
class="col-form-label text-md-right ms-5"
|
||||
>
|
||||
Activité
|
||||
</label>
|
||||
<select
|
||||
|
|
@ -272,7 +336,10 @@
|
|||
v-model="modaleProps.activity"
|
||||
required
|
||||
>
|
||||
<option :value="undefined" disabled>
|
||||
<option
|
||||
:value="undefined"
|
||||
disabled
|
||||
>
|
||||
Sélectionnez une activité
|
||||
</option>
|
||||
<option
|
||||
|
|
@ -286,34 +353,41 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="start" class="col-form-label text-md-right ms-5"
|
||||
>Date début</label
|
||||
>
|
||||
<label
|
||||
for="start"
|
||||
class="col-form-label text-md-right ms-5"
|
||||
>Date début</label>
|
||||
<div class="input-group mb-3">
|
||||
<input
|
||||
class="form-control"
|
||||
id="start"
|
||||
type="date"
|
||||
name="start"
|
||||
:value="momentJs(modaleProps.start).format('YYYY-MM-DD')"
|
||||
v-on:input="updateDateField($event, 'start')"
|
||||
:value="
|
||||
momentJs(modaleProps.start).format('YYYY-MM-DD')
|
||||
"
|
||||
@input="updateDateField($event, 'start')"
|
||||
:disabled="modalLoading"
|
||||
/>
|
||||
>
|
||||
<select
|
||||
class="form-select"
|
||||
:disabled="modalLoading"
|
||||
v-model="modaleProps.startMorning"
|
||||
v-on:input="updateHourField($event, 'start')"
|
||||
@input="updateHourField($event, 'start')"
|
||||
>
|
||||
<option
|
||||
value="1"
|
||||
:selected="momentJs(modaleProps.start).format('HH') === '00'"
|
||||
:selected="
|
||||
momentJs(modaleProps.start).format('HH') === '00'
|
||||
"
|
||||
>
|
||||
Matin
|
||||
</option>
|
||||
<option
|
||||
value="0"
|
||||
:selected="momentJs(modaleProps.start).format('HH') === '12'"
|
||||
:selected="
|
||||
momentJs(modaleProps.start).format('HH') === '12'
|
||||
"
|
||||
>
|
||||
Midi
|
||||
</option>
|
||||
|
|
@ -321,9 +395,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="end" class="col-form-label text-md-right ms-5"
|
||||
>Date fin</label
|
||||
>
|
||||
<label
|
||||
for="end"
|
||||
class="col-form-label text-md-right ms-5"
|
||||
>Date fin</label>
|
||||
<div class="input-group mb-3">
|
||||
<input
|
||||
class="form-control"
|
||||
|
|
@ -331,24 +406,28 @@
|
|||
type="date"
|
||||
name="end"
|
||||
:value="momentJs(modaleProps.end).format('YYYY-MM-DD')"
|
||||
v-on:input="updateDateField($event, 'end')"
|
||||
@input="updateDateField($event, 'end')"
|
||||
:disabled="modalLoading"
|
||||
/>
|
||||
>
|
||||
<select
|
||||
class="form-select"
|
||||
:disabled="modalLoading"
|
||||
v-model="modaleProps.endMorning"
|
||||
v-on:input="updateHourField($event, 'end')"
|
||||
@input="updateHourField($event, 'end')"
|
||||
>
|
||||
<option
|
||||
value="1"
|
||||
:selected="momentJs(modaleProps.end).format('HH') === '11'"
|
||||
:selected="
|
||||
momentJs(modaleProps.end).format('HH') === '11'
|
||||
"
|
||||
>
|
||||
Midi
|
||||
</option>
|
||||
<option
|
||||
value="0"
|
||||
:selected="momentJs(modaleProps.end).format('HH') === '23'"
|
||||
:selected="
|
||||
momentJs(modaleProps.end).format('HH') === '23'
|
||||
"
|
||||
>
|
||||
Soir
|
||||
</option>
|
||||
|
|
@ -356,7 +435,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="comment" class="col-form-label text-md-right ms-5">
|
||||
<label
|
||||
for="comment"
|
||||
class="col-form-label text-md-right ms-5"
|
||||
>
|
||||
Commentaire
|
||||
</label>
|
||||
<textarea
|
||||
|
|
@ -366,16 +448,17 @@
|
|||
id="comment"
|
||||
rows="2"
|
||||
placeholder=""
|
||||
v-on:keydown="limitLines($event)"
|
||||
@keydown="limitLines($event)"
|
||||
v-model="modaleProps.comment"
|
||||
:disabled="modalLoading"
|
||||
></textarea>
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="load" class="col-form-label text-md-right ms-5"
|
||||
>Charge
|
||||
<i>(nombre de personnes consommées sur la période)</i></label
|
||||
>
|
||||
<label
|
||||
for="load"
|
||||
class="col-form-label text-md-right ms-5"
|
||||
>Charge
|
||||
<i>(nombre de personnes consommées sur la période)</i></label>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
|
|
@ -384,7 +467,7 @@
|
|||
v-model="modaleProps.load"
|
||||
:disabled="modalLoading"
|
||||
min="1"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -394,19 +477,19 @@
|
|||
class="btn btn-primary me-3"
|
||||
type="button"
|
||||
:disabled="modalLoading"
|
||||
v-on:click="saveActivity()"
|
||||
@click="saveActivity()"
|
||||
>
|
||||
<span
|
||||
v-if="modalLoading"
|
||||
class="spinner-border spinner-border-sm"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
/>
|
||||
{{ modalLoading ? "Chargement..." : "Valider" }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
v-on:click.prevent="
|
||||
@click.prevent="
|
||||
modale ? modale.hide() : null;
|
||||
$nextTick(refreshTooltips);
|
||||
"
|
||||
|
|
@ -441,7 +524,7 @@ export default defineComponent({
|
|||
window.Toastify = Toastify;
|
||||
|
||||
const json = String(this.$attrs.json ?? "{}"),
|
||||
data = JSON.parse(json);
|
||||
data = JSON.parse(json);
|
||||
|
||||
this.projects = data.projects;
|
||||
this.loadCollection = data.loadCollection;
|
||||
|
|
@ -452,7 +535,9 @@ export default defineComponent({
|
|||
this.startDay = data.startDay;
|
||||
this.isAdmin = data.isAdmin;
|
||||
this.$nextTick(this.refreshTooltips);
|
||||
this.modale = new window.bootstrap.Modal(this.$refs.editModal as HTMLElement);
|
||||
this.modale = new window.bootstrap.Modal(
|
||||
this.$refs.editModal as HTMLElement
|
||||
);
|
||||
(this.$refs.editModal as HTMLElement).addEventListener(
|
||||
"hide.bs.modal",
|
||||
function (e: Event) {
|
||||
|
|
@ -547,7 +632,7 @@ export default defineComponent({
|
|||
},
|
||||
daysToShow(): Moment[] {
|
||||
let days = [],
|
||||
startMoment = this.selectedMoment.clone();
|
||||
startMoment = this.selectedMoment.clone();
|
||||
if (!this.macroscheduleConfig) {
|
||||
return [];
|
||||
}
|
||||
|
|
@ -561,8 +646,8 @@ export default defineComponent({
|
|||
},
|
||||
daysThisMonth(): Moment[] {
|
||||
let days = this.daysToShow,
|
||||
currentMonth = days[0]?.month(),
|
||||
out = [];
|
||||
currentMonth = days[0]?.month(),
|
||||
out = [];
|
||||
for (let day of days) {
|
||||
if (currentMonth === day.month() && this.dayShouldbeenSeen(day)) {
|
||||
out.push(day);
|
||||
|
|
@ -572,8 +657,8 @@ export default defineComponent({
|
|||
},
|
||||
daysNextMonth(): Moment[] {
|
||||
let days = this.daysToShow,
|
||||
currentMonth = days[0]?.month(),
|
||||
out = [];
|
||||
currentMonth = days[0]?.month(),
|
||||
out = [];
|
||||
for (let day of days) {
|
||||
if (currentMonth !== day.month() && this.dayShouldbeenSeen(day)) {
|
||||
out.push(day);
|
||||
|
|
@ -620,12 +705,14 @@ export default defineComponent({
|
|||
},
|
||||
updateDateField(e: Event, fieldName: string): void {
|
||||
const date = this.momentJs(this.modaleProps[fieldName]),
|
||||
target = e.target,
|
||||
time =
|
||||
Number.parseInt(String(this.modaleProps[`${fieldName}Morning`])) === 1
|
||||
? this.getMorningMoment(date, fieldName === "start")
|
||||
: this.getAfterNoonMoment(date, fieldName === "start"),
|
||||
input = target ? this.momentJs((target as HTMLInputElement).value) : null;
|
||||
target = e.target,
|
||||
time =
|
||||
Number.parseInt(String(this.modaleProps[`${fieldName}Morning`])) === 1
|
||||
? this.getMorningMoment(date, fieldName === "start")
|
||||
: this.getAfterNoonMoment(date, fieldName === "start"),
|
||||
input = target
|
||||
? this.momentJs((target as HTMLInputElement).value)
|
||||
: null;
|
||||
|
||||
if (!input) {
|
||||
throw new Error("updateDateField target input is undefined");
|
||||
|
|
@ -639,23 +726,23 @@ export default defineComponent({
|
|||
},
|
||||
updateHourField(e: Event, fieldName: string): void {
|
||||
const date = this.momentJs(this.modaleProps[fieldName]),
|
||||
target = e.target;
|
||||
target = e.target;
|
||||
if (target && Number.parseInt((target as HTMLInputElement).value) === 1) {
|
||||
this.modaleProps[fieldName] = this.getMorningMoment(
|
||||
date,
|
||||
fieldName === "start"
|
||||
).format("YYYY-MM-DD\THH:mm:ss");
|
||||
).format("YYYY-MM-DDTHH:mm:ss");
|
||||
} else {
|
||||
this.modaleProps[fieldName] = this.getAfterNoonMoment(
|
||||
date,
|
||||
fieldName === "start"
|
||||
).format("YYYY-MM-DD\THH:mm:ss");
|
||||
).format("YYYY-MM-DDTHH:mm:ss");
|
||||
}
|
||||
},
|
||||
saveActivity(): void {
|
||||
const self = this,
|
||||
activity = Object.assign({}, this.currentActivity) as LaravelModel,
|
||||
routeUri = self.route("macroplanning.activity");
|
||||
activity = Object.assign({}, this.currentActivity) as LaravelModel,
|
||||
routeUri = self.route("macroplanning.activity");
|
||||
|
||||
if (self.error?.length) {
|
||||
return;
|
||||
|
|
@ -727,7 +814,7 @@ export default defineComponent({
|
|||
project: LaravelModel,
|
||||
activity: LaravelModel,
|
||||
selectedMoment: Moment,
|
||||
isMorning: boolean = true
|
||||
isMorning = true
|
||||
) {
|
||||
selectedMoment = selectedMoment.clone();
|
||||
|
||||
|
|
@ -736,22 +823,24 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
const self = this,
|
||||
startMoment = activity.start
|
||||
? this.momentJs(String(activity.start))
|
||||
: isMorning
|
||||
? this.getMorningMoment(selectedMoment, true)
|
||||
: this.getAfterNoonMoment(selectedMoment, true),
|
||||
endMoment = activity.end
|
||||
? this.momentJs(String(activity.end))
|
||||
: isMorning
|
||||
? this.getMorningMoment(selectedMoment, false)
|
||||
: this.getAfterNoonMoment(selectedMoment, false);
|
||||
startMoment = activity.start
|
||||
? this.momentJs(String(activity.start))
|
||||
: isMorning
|
||||
? this.getMorningMoment(selectedMoment, true)
|
||||
: this.getAfterNoonMoment(selectedMoment, true),
|
||||
endMoment = activity.end
|
||||
? this.momentJs(String(activity.end))
|
||||
: isMorning
|
||||
? this.getMorningMoment(selectedMoment, false)
|
||||
: this.getAfterNoonMoment(selectedMoment, false);
|
||||
|
||||
this.modaleProps = {
|
||||
activity: activity.activity as number | null,
|
||||
start: String(activity.start ?? startMoment.format("YYYY-MM-DD\THH:mm:ss")),
|
||||
start: String(
|
||||
activity.start ?? startMoment.format("YYYY-MM-DDTHH:mm:ss")
|
||||
),
|
||||
startMorning: startMoment.format("HH") === "00" ? 1 : 0,
|
||||
end: String(activity.end ?? endMoment.format("YYYY-MM-DD\THH:mm:ss")),
|
||||
end: String(activity.end ?? endMoment.format("YYYY-MM-DDTHH:mm:ss")),
|
||||
endMorning: endMoment.format("HH") === "11" ? 1 : 0,
|
||||
load: Number.parseInt(String(activity.load)),
|
||||
comment: String(activity.comment ?? ""),
|
||||
|
|
@ -781,7 +870,8 @@ export default defineComponent({
|
|||
if (!activate) {
|
||||
this.hoverActivityId = null;
|
||||
} else {
|
||||
this.hoverActivityId = activity.id !== undefined ? String(activity.id) : "";
|
||||
this.hoverActivityId =
|
||||
activity.id !== undefined ? String(activity.id) : "";
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -817,7 +907,9 @@ export default defineComponent({
|
|||
return this.projects[project_id];
|
||||
},
|
||||
getActivity(moment: Moment, project: LaravelModel): LaravelModel {
|
||||
for (let activity of Object.values(project.activities) as LaravelModelList) {
|
||||
for (let activity of Object.values(
|
||||
project.activities
|
||||
) as LaravelModelList) {
|
||||
if (
|
||||
moment.isBetween(
|
||||
this.momentJs(
|
||||
|
|
@ -837,13 +929,13 @@ export default defineComponent({
|
|||
}
|
||||
return {};
|
||||
},
|
||||
getMorningMoment(moment: Moment, start: boolean = true): Moment {
|
||||
getMorningMoment(moment: Moment, start = true): Moment {
|
||||
moment = moment.clone();
|
||||
return start
|
||||
? moment.hours(0).minutes(0).seconds(0)
|
||||
: moment.hours(11).minutes(59).seconds(0);
|
||||
},
|
||||
getAfterNoonMoment(moment: Moment, start: boolean = true): Moment {
|
||||
getAfterNoonMoment(moment: Moment, start = true): Moment {
|
||||
moment = moment.clone();
|
||||
return start
|
||||
? moment.hours(12).minutes(0).seconds(0)
|
||||
|
|
@ -853,15 +945,17 @@ export default defineComponent({
|
|||
let tooltip = "";
|
||||
for (let marker of project.markers as LaravelModelList) {
|
||||
if (moment.isSame(String(marker.marker), "day")) {
|
||||
tooltip += `${this.momentJs(String(marker.marker)).format("DD/MM/YYYY")} ${
|
||||
marker.label
|
||||
}<br>`;
|
||||
tooltip += `${this.momentJs(String(marker.marker)).format(
|
||||
"DD/MM/YYYY"
|
||||
)} ${marker.label}<br>`;
|
||||
}
|
||||
}
|
||||
return tooltip;
|
||||
},
|
||||
getProjectRoute(project: LaravelModel): string {
|
||||
const route = this.route("projects.show", { PROJECT: project.id as number });
|
||||
const route = this.route("projects.show", {
|
||||
PROJECT: project.id as number,
|
||||
});
|
||||
if (!route) {
|
||||
throw new Error("undefined route projects.show");
|
||||
}
|
||||
|
|
@ -869,7 +963,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
// * FILTERS
|
||||
str_limit(value: string, size: number = 25) {
|
||||
str_limit(value: string, size = 25) {
|
||||
if (!value) return "";
|
||||
value = value.toString();
|
||||
if (value.length <= size) {
|
||||
|
|
@ -892,7 +986,10 @@ export default defineComponent({
|
|||
moment = this.momentJs(moment.week(), "w");
|
||||
this.showMacroScheduleDate("", moment.add(1, "week"));
|
||||
},
|
||||
showMacroScheduleDate(dateString: string, moment: Moment | null = null): void {
|
||||
showMacroScheduleDate(
|
||||
dateString: string,
|
||||
moment: Moment | null = null
|
||||
): void {
|
||||
const url = new URL(String(window.location));
|
||||
moment = moment ?? this.momentJs(dateString);
|
||||
(window as Window).location =
|
||||
|
|
@ -914,7 +1011,9 @@ export default defineComponent({
|
|||
}).showToast();
|
||||
},
|
||||
refreshTooltips(): void {
|
||||
let exisitingToolips = document.querySelectorAll('.tooltip[role="tooltip"]');
|
||||
let exisitingToolips = document.querySelectorAll(
|
||||
".tooltip[role=\"tooltip\"]"
|
||||
);
|
||||
for (let tooltip of exisitingToolips) {
|
||||
tooltip.remove();
|
||||
}
|
||||
|
|
@ -923,7 +1022,7 @@ export default defineComponent({
|
|||
limitLines(e: KeyboardEvent) {
|
||||
const comment = this.$refs.comment as HTMLTextAreaElement;
|
||||
let keynum,
|
||||
lines = comment.value.split("\n").length;
|
||||
lines = comment.value.split("\n").length;
|
||||
if (e.key !== undefined) {
|
||||
keynum = e.key;
|
||||
} else if (e.keyCode !== undefined) {
|
||||
|
|
@ -953,7 +1052,9 @@ export default defineComponent({
|
|||
initTooltips(): void {
|
||||
// * INIT Bootstrap tooltips
|
||||
let tooltipTriggerList = [].slice.call(
|
||||
document.querySelectorAll('.color-picker-component [data-bs-toggle="tooltip"]')
|
||||
document.querySelectorAll(
|
||||
".color-picker-component [data-bs-toggle=\"tooltip\"]"
|
||||
)
|
||||
);
|
||||
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new window.bootstrap.Tooltip(tooltipTriggerEl, {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
<template>
|
||||
<div>
|
||||
<VueSelect v-model="value" :options="labels" @search="addOption" />
|
||||
<input type="hidden" :value="inputValue" :name="name" />
|
||||
<VueSelect
|
||||
v-model="value"
|
||||
:options="labels"
|
||||
@search="addOption"
|
||||
/>
|
||||
<input
|
||||
type="hidden"
|
||||
:value="inputValue"
|
||||
:name="name"
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -15,7 +23,7 @@ export default defineComponent({
|
|||
},
|
||||
mounted() {
|
||||
const json = String(this.$attrs.json ?? "{}"),
|
||||
data = JSON.parse(json);
|
||||
data = JSON.parse(json);
|
||||
|
||||
this.name = data.name;
|
||||
this.labels = data.labels;
|
||||
|
|
|
|||
|
|
@ -4,16 +4,17 @@
|
|||
<div class="col-1 text-center actions_col">
|
||||
<a
|
||||
class="sticky-top btn btn-primary mt-5"
|
||||
v-on:click.prevent="goToPlanning(false)"
|
||||
>←</a
|
||||
>
|
||||
@click.prevent="goToPlanning(false)"
|
||||
>←</a>
|
||||
</div>
|
||||
|
||||
<div class="col-10">
|
||||
<table class="table table-bordered align-middle text-center schedules_table">
|
||||
<table
|
||||
class="table table-bordered align-middle text-center schedules_table"
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2"></th>
|
||||
<th rowspan="2" />
|
||||
<th
|
||||
:colspan="showWeekends ? 7 : 5"
|
||||
v-for="item in weeksCells"
|
||||
|
|
@ -24,15 +25,26 @@
|
|||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th v-for="day in days" :class="`day${day.eday}`" :key="day.num">
|
||||
<th
|
||||
v-for="day in days"
|
||||
:class="`day${day.eday}`"
|
||||
:key="day.num"
|
||||
>
|
||||
{{ day.day }} {{ day.num }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(user, index) in schedules">
|
||||
<tr v-for="(slot, key) in user" :key="`${String(index)} ${String(key)}`">
|
||||
<td :rowspan="daySlots" class="resource_ident" v-if="key == 1">
|
||||
<tr
|
||||
v-for="(slot, key) in user"
|
||||
:key="`${String(index)} ${String(key)}`"
|
||||
>
|
||||
<td
|
||||
:rowspan="daySlots"
|
||||
class="resource_ident"
|
||||
v-if="key == 1"
|
||||
>
|
||||
{{ String(users[index].name) }}
|
||||
</td>
|
||||
<td
|
||||
|
|
@ -43,9 +55,9 @@
|
|||
<div
|
||||
:class="
|
||||
'cellsizer ' +
|
||||
(user[key][day.key as any].type.value
|
||||
? String(user[key][day.key as any].type.value)
|
||||
: 'empty')
|
||||
(user[key][day.key as any].type.value
|
||||
? String(user[key][day.key as any].type.value)
|
||||
: 'empty')
|
||||
"
|
||||
>
|
||||
<b v-if="user[key][day.key as any]['model_lie']['value']">
|
||||
|
|
@ -54,9 +66,10 @@
|
|||
class="text-light bg-dark"
|
||||
:href="String(getCellObjectInfo(user[key][day.key as any])?.url)"
|
||||
>
|
||||
{{ String(user[key][day.key as any]["id_lie"]["label"]) }}
|
||||
</a> </b
|
||||
><br />
|
||||
{{
|
||||
String(user[key][day.key as any]["id_lie"]["label"])
|
||||
}}
|
||||
</a> </b><br>
|
||||
{{ String(user[key][day.key as any]["text"]) }}
|
||||
|
||||
<button
|
||||
|
|
@ -64,8 +77,13 @@
|
|||
type="button"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#editModal"
|
||||
v-on:click.prevent="
|
||||
setModalData(index, key, day.key, user[key][day.key as any]['id'])
|
||||
@click.prevent="
|
||||
setModalData(
|
||||
index,
|
||||
key,
|
||||
day.key,
|
||||
user[key][day.key as any]['id']
|
||||
)
|
||||
"
|
||||
>
|
||||
✎
|
||||
|
|
@ -73,8 +91,13 @@
|
|||
<button
|
||||
:class="'btn btn-paste ' + (!clipBoard.set ? 'hide' : '')"
|
||||
type="button"
|
||||
v-on:click.prevent="
|
||||
pasteCell(index, key, day.key, user[key][day.key as any]['id'])
|
||||
@click.prevent="
|
||||
pasteCell(
|
||||
index,
|
||||
key,
|
||||
day.key,
|
||||
user[key][day.key as any]['id']
|
||||
)
|
||||
"
|
||||
>
|
||||
📋
|
||||
|
|
@ -82,8 +105,13 @@
|
|||
<button
|
||||
class="btn btn-copy"
|
||||
type="button"
|
||||
v-on:click.prevent="
|
||||
copyCell(index, key, day.key, user[key][day.key as any]['id'])
|
||||
@click.prevent="
|
||||
copyCell(
|
||||
index,
|
||||
key,
|
||||
day.key,
|
||||
user[key][day.key as any]['id']
|
||||
)
|
||||
"
|
||||
>
|
||||
<span
|
||||
|
|
@ -96,7 +124,9 @@
|
|||
"
|
||||
>
|
||||
📄
|
||||
<span style="position: absolute; top: 0.25em; left: 0.25em">
|
||||
<span
|
||||
style="position: absolute; top: 0.25em; left: 0.25em"
|
||||
>
|
||||
📄
|
||||
</span>
|
||||
</span>
|
||||
|
|
@ -105,8 +135,13 @@
|
|||
:class="
|
||||
'btn btn-clear ' + (!user[key][day.key as any]['id'] ? 'hide' : '')
|
||||
"
|
||||
v-on:click.prevent="
|
||||
eraseCell(index, key, day.key, user[key][day.key as any]['id'])
|
||||
@click.prevent="
|
||||
eraseCell(
|
||||
index,
|
||||
key,
|
||||
day.key,
|
||||
user[key][day.key as any]['id']
|
||||
)
|
||||
"
|
||||
>
|
||||
⌫
|
||||
|
|
@ -119,7 +154,10 @@
|
|||
</table>
|
||||
</div>
|
||||
<div class="col-1 text-center actions_col">
|
||||
<a class="sticky-top btn btn-primary mt-5" @click="goToPlanning(true)">→</a>
|
||||
<a
|
||||
class="sticky-top btn btn-primary mt-5"
|
||||
@click="goToPlanning(true)"
|
||||
>→</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -134,7 +172,11 @@
|
|||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalLabel" ref="modalLabel">
|
||||
<h5
|
||||
class="modal-title"
|
||||
id="modalLabel"
|
||||
ref="modalLabel"
|
||||
>
|
||||
{{ modale.title }}
|
||||
</h5>
|
||||
<button
|
||||
|
|
@ -143,17 +185,24 @@
|
|||
class="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
/>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div v-if="error" class="alert alert-danger" role="alert">
|
||||
<div
|
||||
v-if="error"
|
||||
class="alert alert-danger"
|
||||
role="alert"
|
||||
>
|
||||
{{ error }}
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<div class="form-group mb-3">
|
||||
<label for="categorie" class="col-form-label text-md-right ms-5">
|
||||
<label
|
||||
for="categorie"
|
||||
class="col-form-label text-md-right ms-5"
|
||||
>
|
||||
Categorie
|
||||
</label>
|
||||
<select
|
||||
|
|
@ -162,7 +211,9 @@
|
|||
class="form-select"
|
||||
aria-label="Sélectionnez une catégorie"
|
||||
>
|
||||
<option value="">Sélectionnez une catégorie</option>
|
||||
<option value="">
|
||||
Sélectionnez une catégorie
|
||||
</option>
|
||||
<option
|
||||
v-for="(activity, index) of activities"
|
||||
:key="index"
|
||||
|
|
@ -175,7 +226,10 @@
|
|||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="morph" class="col-form-label text-md-right ms-5">
|
||||
<label
|
||||
for="morph"
|
||||
class="col-form-label text-md-right ms-5"
|
||||
>
|
||||
Type d'élément lié
|
||||
</label>
|
||||
<select
|
||||
|
|
@ -185,7 +239,9 @@
|
|||
@change="selectChange"
|
||||
aria-label="Sélectionnez un élément à lier"
|
||||
>
|
||||
<option value="">Sélectionnez un type d'objet à lier</option>
|
||||
<option value="">
|
||||
Sélectionnez un type d'objet à lier
|
||||
</option>
|
||||
<option
|
||||
v-for="(model, index) of models"
|
||||
:key="index"
|
||||
|
|
@ -196,8 +252,14 @@
|
|||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-3" v-if="modale.dDisplay">
|
||||
<label for="select_id_lie" class="col-form-label text-md-right ms-5">
|
||||
<div
|
||||
class="form-group mb-3"
|
||||
v-if="modale.dDisplay"
|
||||
>
|
||||
<label
|
||||
for="select_id_lie"
|
||||
class="col-form-label text-md-right ms-5"
|
||||
>
|
||||
Élément lié
|
||||
</label>
|
||||
<VueSelect
|
||||
|
|
@ -214,9 +276,12 @@
|
|||
:searchable="true"
|
||||
@input="setSelected"
|
||||
>
|
||||
<li slot="list-footer" class="pagination">
|
||||
<li
|
||||
slot="list-footer"
|
||||
class="pagination"
|
||||
>
|
||||
<button
|
||||
v-on:click.prevent="
|
||||
@click.prevent="
|
||||
$event.preventDefault();
|
||||
page -= 1;
|
||||
"
|
||||
|
|
@ -226,7 +291,7 @@
|
|||
Précédent
|
||||
</button>
|
||||
<button
|
||||
v-on:click.prevent="
|
||||
@click.prevent="
|
||||
$event.preventDefault();
|
||||
page += 1;
|
||||
"
|
||||
|
|
@ -239,7 +304,10 @@
|
|||
</VueSelect>
|
||||
</div>
|
||||
<div class="form-group mb-3">
|
||||
<label for="text" class="col-form-label text-md-right ms-5">
|
||||
<label
|
||||
for="text"
|
||||
class="col-form-label text-md-right ms-5"
|
||||
>
|
||||
Description courte
|
||||
</label>
|
||||
<textarea
|
||||
|
|
@ -251,18 +319,21 @@
|
|||
placeholder=""
|
||||
@keydown="limitLines($event)"
|
||||
v-model="modale.text"
|
||||
></textarea>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-8 text-center">
|
||||
<button class="btn btn-primary me-3" v-on:click.prevent="saveCell()">
|
||||
<button
|
||||
class="btn btn-primary me-3"
|
||||
@click.prevent="saveCell()"
|
||||
>
|
||||
Valider
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
v-on:click.prevent="($refs.close as HTMLButtonElement).click()"
|
||||
@click.prevent="($refs.close as HTMLButtonElement).click()"
|
||||
>
|
||||
Fermer
|
||||
</button>
|
||||
|
|
@ -359,10 +430,11 @@ export default defineComponent({
|
|||
window.Toastify = Toastify;
|
||||
|
||||
const json = String(this.$attrs.json ?? "{}"),
|
||||
data = JSON.parse(json);
|
||||
data = JSON.parse(json);
|
||||
|
||||
this.daySlots =
|
||||
Number.parseInt(data.daySlots) !== NaN ? Number.parseInt(data.daySlots) : 4;
|
||||
this.daySlots = Number.isNaN(Number.parseInt(data.daySlots))
|
||||
? Number.parseInt(data.daySlots)
|
||||
: 4;
|
||||
this.showWeekends = data.daySlots == "true" ? true : false;
|
||||
this.currentDate = data.browseDate ?? new Date();
|
||||
this.weeksCells = data.weeks;
|
||||
|
|
@ -530,7 +602,9 @@ export default defineComponent({
|
|||
throw new Error("undefined route schedule.index");
|
||||
}
|
||||
// console.log(forward);
|
||||
let date = this.momentJs(this.currentDate).startOf("week").subtract(7, "day");
|
||||
let date = this.momentJs(this.currentDate)
|
||||
.startOf("week")
|
||||
.subtract(7, "day");
|
||||
if (forward) {
|
||||
date = this.momentJs(this.currentDate).add(7, "day");
|
||||
}
|
||||
|
|
@ -542,12 +616,12 @@ export default defineComponent({
|
|||
let mydays = [];
|
||||
for (let i = 0; i < this.numweeks * 7; i++) {
|
||||
const date = this.momentJs(this.currentDate).add(i, "day"),
|
||||
obj = {
|
||||
day: date.format("ddd"),
|
||||
num: date.format("DD"),
|
||||
eday: date.locale("en").format("ddd"),
|
||||
key: date.format("DD/MM/YYYY"),
|
||||
};
|
||||
obj = {
|
||||
day: date.format("ddd"),
|
||||
num: date.format("DD"),
|
||||
eday: date.locale("en").format("ddd"),
|
||||
key: date.format("DD/MM/YYYY"),
|
||||
};
|
||||
mydays.push(obj);
|
||||
if (!this.showWeekends) {
|
||||
if (date.day() == 5) {
|
||||
|
|
@ -606,19 +680,32 @@ export default defineComponent({
|
|||
},
|
||||
getCellObjectInfo(cellData: DaySlot) {
|
||||
for (let model of this.models) {
|
||||
if (cellData["model_lie"].value === model.value && model.value == "tickets") {
|
||||
if (
|
||||
cellData["model_lie"].value === model.value &&
|
||||
model.value == "tickets"
|
||||
) {
|
||||
return {
|
||||
url: this.route("ticket.show", { TICKET: String(cellData["id_lie"].value) }),
|
||||
url: this.route("ticket.show", {
|
||||
TICKET: String(cellData["id_lie"].value),
|
||||
}),
|
||||
text: cellData["model_lie"].label,
|
||||
};
|
||||
}
|
||||
if (cellData["model_lie"].value === model.value && model.value == "sites") {
|
||||
if (
|
||||
cellData["model_lie"].value === model.value &&
|
||||
model.value == "sites"
|
||||
) {
|
||||
return {
|
||||
url: this.route("sites.show", { SITE: String(cellData["id_lie"].value) }),
|
||||
url: this.route("sites.show", {
|
||||
SITE: String(cellData["id_lie"].value),
|
||||
}),
|
||||
text: cellData["model_lie"].label,
|
||||
};
|
||||
}
|
||||
if (cellData["model_lie"].value === model.value && model.value == "projects") {
|
||||
if (
|
||||
cellData["model_lie"].value === model.value &&
|
||||
model.value == "projects"
|
||||
) {
|
||||
return {
|
||||
url: this.route("projects.show", {
|
||||
PROJECT: String(cellData["id_lie"].value),
|
||||
|
|
@ -639,24 +726,24 @@ export default defineComponent({
|
|||
},
|
||||
setModalData(userid: number, slotkey: number, day: string, id: number) {
|
||||
let text = this.schedules[userid][slotkey][day as any]["text"],
|
||||
activity = this.schedules[userid][slotkey][day as any]["type"],
|
||||
model = this.schedules[userid][slotkey][day as any]["model_lie"],
|
||||
enumobject = {
|
||||
label: "",
|
||||
value: "",
|
||||
},
|
||||
currentModale: Modale = {
|
||||
id: this.schedules[userid][slotkey][day as any]["id"],
|
||||
userid: userid,
|
||||
slot: slotkey,
|
||||
day: day,
|
||||
title: String(id),
|
||||
dDisplay: false,
|
||||
text: text,
|
||||
activity: activity,
|
||||
model_lie: model ?? enumobject,
|
||||
id_lie: this.schedules[userid][slotkey][day as any]["id_lie"],
|
||||
};
|
||||
activity = this.schedules[userid][slotkey][day as any]["type"],
|
||||
model = this.schedules[userid][slotkey][day as any]["model_lie"],
|
||||
enumobject = {
|
||||
label: "",
|
||||
value: "",
|
||||
},
|
||||
currentModale: Modale = {
|
||||
id: this.schedules[userid][slotkey][day as any]["id"],
|
||||
userid: userid,
|
||||
slot: slotkey,
|
||||
day: day,
|
||||
title: String(id),
|
||||
dDisplay: false,
|
||||
text: text,
|
||||
activity: activity,
|
||||
model_lie: model ?? enumobject,
|
||||
id_lie: this.schedules[userid][slotkey][day as any]["id_lie"],
|
||||
};
|
||||
this.modale = currentModale;
|
||||
this.$nextTick(() => {
|
||||
if (this.modale.id_lie.value === null) {
|
||||
|
|
@ -664,26 +751,26 @@ export default defineComponent({
|
|||
}
|
||||
let route = null;
|
||||
switch (this.modale.model_lie.value) {
|
||||
case "tickets":
|
||||
this.modale.dDisplay = true;
|
||||
route = this.route("ticket.show", {
|
||||
TICKET: this.modale.id_lie.value,
|
||||
});
|
||||
break;
|
||||
case "projects":
|
||||
this.modale.dDisplay = true;
|
||||
route = this.route("projects.show", {
|
||||
PROJECT: this.modale.id_lie.value,
|
||||
});
|
||||
break;
|
||||
case "sites":
|
||||
this.modale.dDisplay = true;
|
||||
route = this.route("sites.show", {
|
||||
SITE: this.modale.id_lie.value,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
this.modale.dDisplay = false;
|
||||
case "tickets":
|
||||
this.modale.dDisplay = true;
|
||||
route = this.route("ticket.show", {
|
||||
TICKET: this.modale.id_lie.value,
|
||||
});
|
||||
break;
|
||||
case "projects":
|
||||
this.modale.dDisplay = true;
|
||||
route = this.route("projects.show", {
|
||||
PROJECT: this.modale.id_lie.value,
|
||||
});
|
||||
break;
|
||||
case "sites":
|
||||
this.modale.dDisplay = true;
|
||||
route = this.route("sites.show", {
|
||||
SITE: this.modale.id_lie.value,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
this.modale.dDisplay = false;
|
||||
}
|
||||
this.selectChange();
|
||||
this.value = this.schedules[userid][slotkey][day as any]["id_lie"];
|
||||
|
|
@ -770,15 +857,15 @@ export default defineComponent({
|
|||
this.error = "";
|
||||
let route;
|
||||
switch ((this.$refs.morph as HTMLSelectElement).value) {
|
||||
case "tickets":
|
||||
route = this.route("ticket.index");
|
||||
break;
|
||||
case "projects":
|
||||
route = this.route("projects.index");
|
||||
break;
|
||||
case "sites":
|
||||
route = this.route("sites.index");
|
||||
break;
|
||||
case "tickets":
|
||||
route = this.route("ticket.index");
|
||||
break;
|
||||
case "projects":
|
||||
route = this.route("projects.index");
|
||||
break;
|
||||
case "sites":
|
||||
route = this.route("sites.index");
|
||||
break;
|
||||
}
|
||||
if (route === null || route === undefined) {
|
||||
throw new Error(
|
||||
|
|
@ -830,7 +917,7 @@ export default defineComponent({
|
|||
saveCellOnServer(data: ServerData) {
|
||||
this.error = "";
|
||||
const self = this,
|
||||
routeUri = self.route("schedule.setCellContent");
|
||||
routeUri = self.route("schedule.setCellContent");
|
||||
if (self.error.length) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -890,9 +977,9 @@ export default defineComponent({
|
|||
},
|
||||
eraseCell(userid: number, slotkey: number, day: string, id: number) {
|
||||
const route = this.route("schedule.eraseCellContent"),
|
||||
data = {
|
||||
id: id,
|
||||
};
|
||||
data = {
|
||||
id: id,
|
||||
};
|
||||
if (!route) {
|
||||
throw new Error("undefined route schedule.eraseCellContent");
|
||||
}
|
||||
|
|
@ -900,7 +987,8 @@ export default defineComponent({
|
|||
.post(route, data)
|
||||
.then((response) => {
|
||||
if (response.data.status) {
|
||||
this.schedules[userid][slotkey][day as any] = this.emptyCell as DaySlot;
|
||||
this.schedules[userid][slotkey][day as any] = this
|
||||
.emptyCell as DaySlot;
|
||||
} else {
|
||||
console.error("Unknown response");
|
||||
}
|
||||
|
|
@ -918,20 +1006,20 @@ export default defineComponent({
|
|||
value: null,
|
||||
};
|
||||
switch ((this.$refs.morph as HTMLSelectElement).value) {
|
||||
case "tickets":
|
||||
case "projects":
|
||||
case "sites":
|
||||
this.modale.dDisplay = true;
|
||||
this.search(false);
|
||||
break;
|
||||
default:
|
||||
this.modale.dDisplay = false;
|
||||
case "tickets":
|
||||
case "projects":
|
||||
case "sites":
|
||||
this.modale.dDisplay = true;
|
||||
this.search(false);
|
||||
break;
|
||||
default:
|
||||
this.modale.dDisplay = false;
|
||||
}
|
||||
},
|
||||
limitLines(e: KeyboardEvent) {
|
||||
const comment = this.$refs.comment as HTMLTextAreaElement;
|
||||
let keynum,
|
||||
lines = comment.value.split("\n").length;
|
||||
lines = comment.value.split("\n").length;
|
||||
if (e.key !== undefined) {
|
||||
keynum = e.key;
|
||||
} else if (e.keyCode !== undefined) {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
"Voulez-vous vraiment supprimer cet élément ?"
|
||||
),
|
||||
el as HTMLFormElement,
|
||||
function (response: SweetAlertResult<any>) {
|
||||
function () {
|
||||
(el as HTMLFormElement).submit();
|
||||
},
|
||||
{ icon: "error" }
|
||||
|
|
@ -28,7 +28,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
});
|
||||
}
|
||||
elements = document.getElementsByClassName("confirmDoneJS");
|
||||
for (let element of elements) {
|
||||
for (const element of elements) {
|
||||
element.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
const el = e.target;
|
||||
|
|
@ -43,7 +43,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
"Voulez-vous vraiment marquer cet élément comme traité ?"
|
||||
),
|
||||
el as HTMLFormElement,
|
||||
function (response: SweetAlertResult<any>) {
|
||||
function () {
|
||||
(el as HTMLFormElement).submit();
|
||||
},
|
||||
{ icon: "info" }
|
||||
|
|
@ -52,7 +52,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
});
|
||||
}
|
||||
elements = document.getElementsByClassName("confirmSubmitJS");
|
||||
for (let element of elements) {
|
||||
for (const element of elements) {
|
||||
element.addEventListener("submit", function (e) {
|
||||
e.preventDefault();
|
||||
const el = e.target;
|
||||
|
|
@ -67,7 +67,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
"Voulez-vous enregistrer cet élément tel-quel ?"
|
||||
),
|
||||
el as HTMLFormElement,
|
||||
function (response: SweetAlertResult<any>) {
|
||||
function () {
|
||||
(el as HTMLFormElement).submit();
|
||||
},
|
||||
{ icon: "warning" }
|
||||
|
|
@ -76,7 +76,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
});
|
||||
}
|
||||
elements = document.getElementsByClassName("confirmJS");
|
||||
for (let element of elements) {
|
||||
for (const element of elements) {
|
||||
element.addEventListener(
|
||||
"click",
|
||||
function (e) {
|
||||
|
|
@ -90,13 +90,12 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
}
|
||||
(async () => {
|
||||
const promise = new Promise(
|
||||
(resolve: (value: boolean) => void, reject) => {
|
||||
console.log(el);
|
||||
(resolve: (value: boolean) => void) => {
|
||||
confirm.methods.confirm(
|
||||
trans.methods.__("Confirmez"),
|
||||
trans.methods.__("Êtes vous sure ?"),
|
||||
el,
|
||||
function (response: SweetAlertResult<any>) {
|
||||
function (response: SweetAlertResult) {
|
||||
resolve(response.isConfirmed);
|
||||
},
|
||||
{ icon: "warning" }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { dom, library, config, icon } from "@fortawesome/fontawesome-svg-core";
|
||||
import { dom, library, config } from "@fortawesome/fontawesome-svg-core";
|
||||
import {
|
||||
faTags,
|
||||
faSquarePlus,
|
||||
|
|
@ -17,9 +17,11 @@ import {
|
|||
faFileImage,
|
||||
faInbox,
|
||||
faArrowLeftLong,
|
||||
faPlus,
|
||||
faMinus,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faAccessibleIcon } from "@fortawesome/free-brands-svg-icons";
|
||||
import { faCalendarAlt } from "@fortawesome/free-regular-svg-icons";
|
||||
// import { faAccessibleIcon } from "@fortawesome/free-brands-svg-icons";
|
||||
// import { faCalendarAlt } from "@fortawesome/free-regular-svg-icons";
|
||||
|
||||
config.autoReplaceSvg = false;
|
||||
library.add(faTags);
|
||||
|
|
@ -39,4 +41,6 @@ library.add(faLock);
|
|||
library.add(faFileImage);
|
||||
library.add(faInbox);
|
||||
library.add(faArrowLeftLong);
|
||||
library.add(faPlus);
|
||||
library.add(faMinus);
|
||||
dom.watch();
|
||||
|
|
|
|||
14
resources/ts/index.d.ts
vendored
14
resources/ts/index.d.ts
vendored
|
|
@ -1,5 +1,6 @@
|
|||
export {};
|
||||
|
||||
import * as Swal from "sweetalert2";
|
||||
import { AxiosStatic } from "axios";
|
||||
import type { VueSelectProps } from "vue-select";
|
||||
|
||||
|
|
@ -10,13 +11,20 @@ type SelectModelType = {
|
|||
value: string;
|
||||
};
|
||||
|
||||
type EnumType = {
|
||||
label: string;
|
||||
value: number | string;
|
||||
};
|
||||
|
||||
// * Recursive List<string>
|
||||
type StringList = Record<PropertyKey, string>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface NestedStringListInterface
|
||||
extends Record<PropertyKey, NestedStringListInterface | StringList> {}
|
||||
|
||||
// * Recursive List<number>
|
||||
type NumberList = Record<PropertyKey, number>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface NestedNumberListInterface
|
||||
extends Record<PropertyKey, NestedNumberListInterface | NumberList> {}
|
||||
|
||||
|
|
@ -31,6 +39,7 @@ type Model = Record<
|
|||
| NestedNumberList
|
||||
| NestedModelInterface
|
||||
>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface NestedModelInterface extends Model {}
|
||||
|
||||
type NestedStringList = NestedStringListInterface | StringList | string;
|
||||
|
|
@ -44,13 +53,14 @@ declare global {
|
|||
|
||||
type VSelectProps = VueSelectProps;
|
||||
type SelectModel = SelectModelType;
|
||||
type Enum = EnumType;
|
||||
|
||||
interface Window {
|
||||
$displayMenu: (show: boolean) => void;
|
||||
$toggleBasketMenu: () => void;
|
||||
axios: AxiosStatic;
|
||||
Swal: Function;
|
||||
__SESSION_WATCH: any;
|
||||
Swal: typeof Swal;
|
||||
__SESSION_WATCH: Record<string, unknown>;
|
||||
__SYSTEM: {
|
||||
_asset: string;
|
||||
_locale: string;
|
||||
|
|
|
|||
|
|
@ -8,20 +8,18 @@ export default {
|
|||
methods: {
|
||||
confirm(
|
||||
title: string,
|
||||
text: string = "",
|
||||
self: Object,
|
||||
after: (response: SweetAlertResult<any>) => void = (
|
||||
response: SweetAlertResult<any>
|
||||
) => {},
|
||||
text = "",
|
||||
self: HTMLElement,
|
||||
after: (response: SweetAlertResult) => void,
|
||||
options: SweetAlertOptions = {}
|
||||
) {
|
||||
if (!self) {
|
||||
throw Error('self is needed to set "this" on callback');
|
||||
throw Error("self is needed to set 'this' on callback");
|
||||
}
|
||||
if (!after) {
|
||||
throw Error("callback is needed when using confirm");
|
||||
}
|
||||
let icon = options.icon ?? "warning";
|
||||
const icon = options.icon ?? "warning";
|
||||
Swal.fire({
|
||||
title: title,
|
||||
text: text,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const route = {
|
|||
const routes = route.flattenProperties(window.__SYSTEM._routes);
|
||||
const routeUrl =
|
||||
Object.keys(routes).indexOf(routeName) !== -1
|
||||
? routes[routeName]
|
||||
? routes[routeName] as string
|
||||
: null;
|
||||
if (!routeUrl) {
|
||||
return routeUrl;
|
||||
|
|
@ -31,8 +31,8 @@ const route = {
|
|||
delete parameters[paramName];
|
||||
}
|
||||
|
||||
for (let paramName in parameters) {
|
||||
let paramValue = parameters[paramName];
|
||||
for (const paramName in parameters) {
|
||||
const paramValue = parameters[paramName];
|
||||
if (search.indexOf(paramName + "=") >= 0) {
|
||||
const prefix = search.substring(
|
||||
0,
|
||||
|
|
@ -57,14 +57,18 @@ const route = {
|
|||
},
|
||||
},
|
||||
flattenProperties(
|
||||
obj: Record<PropertyKey, any>,
|
||||
obj: Record<PropertyKey, unknown>,
|
||||
parent: string | null = null,
|
||||
res: Record<PropertyKey, any> = {}
|
||||
): Record<PropertyKey, any> {
|
||||
res: Record<PropertyKey, unknown> = {}
|
||||
): Record<PropertyKey, unknown> {
|
||||
for (const key of Object.keys(obj)) {
|
||||
const propName = parent ? parent + "." + key : key;
|
||||
if (typeof obj[key] === "object") {
|
||||
route.flattenProperties(obj[key], propName, res);
|
||||
if (obj[key] instanceof Object) {
|
||||
route.flattenProperties(
|
||||
obj[key] as Record<PropertyKey, unknown>,
|
||||
propName,
|
||||
res
|
||||
);
|
||||
} else {
|
||||
res[propName] = obj[key];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export default {
|
|||
translation = key
|
||||
.split(".")
|
||||
.reduce(
|
||||
(t, i) => t[i as any] ?? null,
|
||||
(t, i) => t[i as never] ?? null,
|
||||
window.__SYSTEM._translations.php
|
||||
) as string;
|
||||
if (translation) {
|
||||
|
|
@ -27,8 +27,9 @@ export default {
|
|||
}
|
||||
|
||||
if (translationNotFound) {
|
||||
translation = (window.__SYSTEM._translations.json[key as any] ??
|
||||
key) as string;
|
||||
translation = (window.__SYSTEM._translations.json[
|
||||
key as never
|
||||
] ?? key) as string;
|
||||
}
|
||||
const vars = translation.match(/:[0-9A-Za-z_]+/g);
|
||||
if (vars) {
|
||||
|
|
|
|||
|
|
@ -1,45 +1,50 @@
|
|||
document.addEventListener("DOMContentLoaded", () => {
|
||||
// Page Project File Add
|
||||
if (document.querySelector(".content.pageFile")) {
|
||||
let selectFileType = document.getElementById(
|
||||
"type"
|
||||
) as HTMLSelectElement,
|
||||
inputUri = document.getElementById("uri") as HTMLInputElement,
|
||||
inputFile = document.getElementById("file") as HTMLInputElement;
|
||||
|
||||
let changeFields = () => {
|
||||
if (
|
||||
!selectFileType ||
|
||||
!inputUri ||
|
||||
!inputUri.parentElement ||
|
||||
!inputUri.parentElement.parentElement ||
|
||||
!inputFile ||
|
||||
!inputFile.parentElement ||
|
||||
!inputFile.parentElement.parentElement
|
||||
) {
|
||||
throw new Error(
|
||||
"Missing selectFileType or inputUri or inputFile on file page"
|
||||
);
|
||||
}
|
||||
if (selectFileType.value === "0") {
|
||||
inputUri.setAttribute("required", "");
|
||||
inputUri.removeAttribute("disabled");
|
||||
inputUri.parentElement.parentElement.classList.remove("d-none");
|
||||
inputFile.removeAttribute("required");
|
||||
inputFile.setAttribute("disabled", "");
|
||||
inputFile.parentElement.parentElement.classList.add("d-none");
|
||||
} else {
|
||||
inputUri.removeAttribute("required");
|
||||
inputUri.removeAttribute("required");
|
||||
inputUri.setAttribute("disabled", "");
|
||||
inputUri.parentElement.parentElement.classList.add("d-none");
|
||||
inputFile.setAttribute("required", "");
|
||||
inputFile.removeAttribute("disabled");
|
||||
inputFile.parentElement.parentElement.classList.remove(
|
||||
"d-none"
|
||||
);
|
||||
}
|
||||
};
|
||||
const selectFileType = document.getElementById(
|
||||
"type"
|
||||
) as HTMLSelectElement;
|
||||
const inputUri = document.getElementById("uri") as HTMLInputElement,
|
||||
inputFile = document.getElementById("file") as HTMLInputElement,
|
||||
changeFields = () => {
|
||||
if (
|
||||
!selectFileType ||
|
||||
!inputUri ||
|
||||
!inputUri.parentElement ||
|
||||
!inputUri.parentElement.parentElement ||
|
||||
!inputFile ||
|
||||
!inputFile.parentElement ||
|
||||
!inputFile.parentElement.parentElement
|
||||
) {
|
||||
throw new Error(
|
||||
"Missing selectFileType or inputUri or inputFile on file page"
|
||||
);
|
||||
}
|
||||
if (selectFileType.value === "0") {
|
||||
inputUri.setAttribute("required", "");
|
||||
inputUri.removeAttribute("disabled");
|
||||
inputUri.parentElement.parentElement.classList.remove(
|
||||
"d-none"
|
||||
);
|
||||
inputFile.removeAttribute("required");
|
||||
inputFile.setAttribute("disabled", "");
|
||||
inputFile.parentElement.parentElement.classList.add(
|
||||
"d-none"
|
||||
);
|
||||
} else {
|
||||
inputUri.removeAttribute("required");
|
||||
inputUri.removeAttribute("required");
|
||||
inputUri.setAttribute("disabled", "");
|
||||
inputUri.parentElement.parentElement.classList.add(
|
||||
"d-none"
|
||||
);
|
||||
inputFile.setAttribute("required", "");
|
||||
inputFile.removeAttribute("disabled");
|
||||
inputFile.parentElement.parentElement.classList.remove(
|
||||
"d-none"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
changeFields();
|
||||
selectFileType.addEventListener("change", changeFields);
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
document.querySelector(".content.ticketsIndex") ||
|
||||
document.querySelector(".content.ticketsShow")
|
||||
) {
|
||||
let labels = document.querySelectorAll(".label.colorize");
|
||||
const labels = document.querySelectorAll(".label.colorize");
|
||||
|
||||
labels.forEach((label, key) => {
|
||||
labels.forEach((label) => {
|
||||
if (!(label instanceof HTMLElement)) {
|
||||
throw new Error("label has to be a HTMLElement");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import Swal from "sweetalert2";
|
||||
import trans from "./modules/trans";
|
||||
import validateSession from "./modules/session_pinger";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
let validateSession = require("./modules/session_pinger").default.methods
|
||||
.validateSession,
|
||||
sessionInvalidAction = () => {
|
||||
let timeOut: ReturnType<typeof setTimeout> | undefined = undefined;
|
||||
const sessionInvalidAction = () => {
|
||||
Swal.fire({
|
||||
title: trans.methods.__("Session expirée"),
|
||||
text: trans.methods.__(
|
||||
|
|
@ -20,9 +20,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
clearTimeout(timeOut);
|
||||
},
|
||||
timer = 10000,
|
||||
timeOut: NodeJS.Timeout | undefined,
|
||||
timerAction = () => {
|
||||
validateSession(sessionInvalidAction);
|
||||
validateSession.methods.validateSession(sessionInvalidAction);
|
||||
timeOut = setTimeout(timerAction, timer);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
.replace(/^-/, "")
|
||||
.replace("-component", "");
|
||||
|
||||
let el = document.getElementById(htmlKey),
|
||||
const el = document.getElementById(htmlKey),
|
||||
elGroup = document.getElementsByClassName(htmlKey);
|
||||
// * Init using ID
|
||||
if (el) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"lib": [
|
||||
"es5", "es6", "dom", "dom.iterable"
|
||||
],
|
||||
"lib": ["es5", "es6", "dom", "dom.iterable"],
|
||||
"module": "esnext",
|
||||
// "isolatedModules": false,
|
||||
// "experimentalDecorators": true,
|
||||
|
|
@ -15,12 +13,9 @@
|
|||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"moduleResolution": "node",
|
||||
"typeRoots": ["resources/ts/@types", "node_modules/@types"],
|
||||
"typeRoots": ["resources/ts/@types", "node_modules/@types"]
|
||||
},
|
||||
"include": [
|
||||
"resources/**/*.js",
|
||||
"resources/**/*.ts",
|
||||
"resources/**/*.vue"
|
||||
],
|
||||
"include": ["resources/**/*.js", "resources/**/*.ts", "resources/**/*.vue"],
|
||||
"exclude": ["node_modules"],
|
||||
"compileOnSave": false
|
||||
}
|
||||
|
|
|
|||
65
webpack.mix.js
vendored
65
webpack.mix.js
vendored
|
|
@ -1,40 +1,41 @@
|
|||
const path = require('path')
|
||||
const mix = require('laravel-mix')
|
||||
const path = require("path");
|
||||
const mix = require("laravel-mix");
|
||||
|
||||
require('laravel-mix-polyfill')
|
||||
require('laravel-mix-clean')
|
||||
require("laravel-mix-polyfill");
|
||||
require("laravel-mix-clean");
|
||||
require("laravel-mix-eslint");
|
||||
|
||||
const assetDir = 'assets'
|
||||
const assetDir = "assets";
|
||||
const polyfill = {
|
||||
enabled: true,
|
||||
bugfixes: true,
|
||||
useBuiltIns: "usage",
|
||||
targets: 'last 3 version, not dead, >0.3%'
|
||||
}
|
||||
targets: "last 3 version, not dead, >0.3%",
|
||||
};
|
||||
|
||||
mix.webpackConfig({
|
||||
resolve: {
|
||||
extensions: ["*", ".js", ".vue", ".ts"],
|
||||
alias: {
|
||||
'@': path.resolve('resources/assets'),
|
||||
'vue$': 'vue/dist/vue.runtime.esm-bundler.js',
|
||||
}
|
||||
"@": path.resolve("resources/assets"),
|
||||
vue$: "vue/dist/vue.runtime.esm-bundler.js",
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
loader: 'ts-loader',
|
||||
loader: "ts-loader",
|
||||
options: {
|
||||
appendTsSuffixTo: [/\.vue$/],
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
loader: "vue-loader",
|
||||
options: {
|
||||
esModule: true
|
||||
}
|
||||
esModule: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -45,39 +46,39 @@ mix.webpackConfig({
|
|||
// /\-\-underline\-color/,
|
||||
// ]
|
||||
// },
|
||||
})
|
||||
});
|
||||
|
||||
mix.options({
|
||||
fileLoaderDirs: {
|
||||
fonts: `${assetDir}/fonts`,
|
||||
images: `${assetDir}/images`
|
||||
images: `${assetDir}/images`,
|
||||
},
|
||||
postCss: [
|
||||
require('postcss-discard-comments')({
|
||||
removeAll: true
|
||||
})
|
||||
require("postcss-discard-comments")({
|
||||
removeAll: true,
|
||||
}),
|
||||
],
|
||||
})
|
||||
});
|
||||
|
||||
mix.clean({
|
||||
cleanOnceBeforeBuildPatterns: [
|
||||
'css/*',
|
||||
'js/*',
|
||||
'assets/*',
|
||||
]
|
||||
})
|
||||
cleanOnceBeforeBuildPatterns: ["css/*", "js/*", "assets/*"],
|
||||
});
|
||||
|
||||
// mix Backend
|
||||
mix.ts('resources/ts/app.ts', 'public/js/app.js', { transpileOnly: true })
|
||||
mix.ts("resources/ts/app.ts", "public/js/app.js", { transpileOnly: true })
|
||||
.vue({
|
||||
runtimeOnly: true,
|
||||
extractStyles: true,
|
||||
globalStyles: false
|
||||
globalStyles: false,
|
||||
})
|
||||
.sass('resources/sass/app.scss', 'public/css')
|
||||
.eslint({
|
||||
fix: true,
|
||||
extensions: ["js", "ts"],
|
||||
})
|
||||
.sass("resources/sass/app.scss", "public/css")
|
||||
.polyfill(polyfill)
|
||||
.version()
|
||||
.sourceMaps(true, 'inline-source-map')
|
||||
.sourceMaps(true, "inline-source-map");
|
||||
|
||||
// Copy Blade Images Assets
|
||||
mix.copyDirectory('resources/assets', 'public/assets')
|
||||
mix.copyDirectory("resources/assets", "public/assets");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue