diff --git a/symfony/Makefile b/symfony/Makefile index 6e4e7f02..e85a53e0 100644 --- a/symfony/Makefile +++ b/symfony/Makefile @@ -28,10 +28,7 @@ sf: ## List all Symfony commands or pass the parameter "c=" to run a given comma cc: c=c:c ## Clear the cache cc: sf -reset-database-schema: - @$(SYMFONY) do:s:u -f - -recreate-database: restart-db-container drop-database create-database +recreate-database: restart-db-container drop-database create-database configure-database drop-database: @$(SYMFONY) do:da:dr -f --if-exists @@ -54,9 +51,13 @@ make-entity: regenerate-entity: @$(SYMFONY) make:entity --regenerate +enable-postgis: + @$(SYMFONY) dbal:run-sql 'CREATE extension postgis;' + make-run-migration: make-migration run-migration reset-database: recreate-database run-migration rerun-database: reset-database run-fixtures +configure-database: enable-postgis create-short-migration: recreate-database run-migration make-migration rerun-migration init-jwt-keypair: diff --git a/symfony/config/packages/hautelook_alice.yaml b/symfony/config/packages/hautelook_alice.yaml index 6e6d2fe1..fe94130e 100644 --- a/symfony/config/packages/hautelook_alice.yaml +++ b/symfony/config/packages/hautelook_alice.yaml @@ -3,3 +3,4 @@ when@dev: &dev fixtures_path: fixtures when@test: *dev +when@prod: *dev diff --git a/symfony/config/packages/security.yaml b/symfony/config/packages/security.yaml index 51910e6d..a027a303 100644 --- a/symfony/config/packages/security.yaml +++ b/symfony/config/packages/security.yaml @@ -44,6 +44,7 @@ security: - { path: ^/auth, roles: PUBLIC_ACCESS } - { path: ^/api/users, roles: PUBLIC_ACCESS, methods: [POST]} - { path: ^/api/actors, roles: PUBLIC_ACCESS, methods: [GET] } + - { path: ^/api/projects, roles: PUBLIC_ACCESS, methods: [GET] } - { path: ^/api/actor_expertises, roles: PUBLIC_ACCESS, methods: [GET] } - { path: ^/api/thematics, roles: PUBLIC_ACCESS, methods: [GET] } - { path: ^/api/administrative_scopes, roles: PUBLIC_ACCESS, methods: [GET] } diff --git a/symfony/fixtures/actors.yaml b/symfony/fixtures/actors.yaml index 31c3305b..0cff91fe 100644 --- a/symfony/fixtures/actors.yaml +++ b/symfony/fixtures/actors.yaml @@ -17,5 +17,5 @@ App\Entity\Actor: email: logo: projects: 'x @project_*' - created_at: '' - updated_at: '' \ No newline at end of file + createdAt: '' + updatedAt: '' diff --git a/symfony/fixtures/actorsExpertise.yaml b/symfony/fixtures/actorsExpertise.yaml new file mode 100644 index 00000000..43ad933d --- /dev/null +++ b/symfony/fixtures/actorsExpertise.yaml @@ -0,0 +1,7 @@ +App\Entity\ActorExpertise: + actorexpertise_1: + name: Planification urbaine + actorexpertise_2: + name: Elaboration et mise en œuvre de la politique algorithmique de la nation ainsi que de l’aménagement du territoire + actorexpertise_3: + name: Production de l’Information Géospatiale \ No newline at end of file diff --git a/symfony/fixtures/administrativeScopes.yaml b/symfony/fixtures/administrativeScopes.yaml new file mode 100644 index 00000000..765d6779 --- /dev/null +++ b/symfony/fixtures/administrativeScopes.yaml @@ -0,0 +1,9 @@ +App\Entity\AdministrativeScope: + administrative_scope_1: + name: National + administrative_scope_2: + name: Régional + administrative_scope_3: + name: Départemental + administrative_scope_4: + name: Communal \ No newline at end of file diff --git a/symfony/fixtures/projects.yaml b/symfony/fixtures/projects.yaml index 84519950..5d478c63 100644 --- a/symfony/fixtures/projects.yaml +++ b/symfony/fixtures/projects.yaml @@ -1,13 +1,14 @@ App\Entity\Project: - project_{1..100}: - title: Urban Development + project_{1..500}: + name: Urban Development location: - coords: 'POINT( )' - status: ')>' # Remplace par les valeurs de ton Enum Status + # coords: 'POINT( )' + coords: 'POINT( )' + status: ')>' description: images: [] partners: [] - interventionZone: ')>' # Remplace par les valeurs de ton Enum AdministrativeScopes + interventionZone: ')>' financialActors: 'x @actor_*' actor: '@actor_*' contractingActors: 'x @actor_*' diff --git a/symfony/migrations/Version20241001093511.php b/symfony/migrations/Version20241001093511.php deleted file mode 100644 index 5853e023..00000000 --- a/symfony/migrations/Version20241001093511.php +++ /dev/null @@ -1,28 +0,0 @@ -addSql('CREATE extension postgis;'); } - - public function down(Schema $schema): void - { - } -} diff --git a/symfony/migrations/Version20241008150316.php b/symfony/migrations/Version20241011202727.php similarity index 90% rename from symfony/migrations/Version20241008150316.php rename to symfony/migrations/Version20241011202727.php index 2f1efb63..7e8018c3 100644 --- a/symfony/migrations/Version20241008150316.php +++ b/symfony/migrations/Version20241011202727.php @@ -10,7 +10,7 @@ /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20241008150316 extends AbstractMigration +final class Version20241011202727 extends AbstractMigration { public function getDescription(): string { @@ -42,7 +42,7 @@ public function up(Schema $schema): void $this->addSql('COMMENT ON COLUMN actor_administrative_scope.actor_id IS \'(DC2Type:uuid)\''); $this->addSql('CREATE TABLE actor_expertise (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE TABLE administrative_scope (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); - $this->addSql('CREATE TABLE project (id INT NOT NULL, actor_id UUID NOT NULL, title VARCHAR(255) NOT NULL, location VARCHAR(255) NOT NULL, coords geometry(POINT, 0) NOT NULL, status VARCHAR(255) NOT NULL, description TEXT DEFAULT NULL, images JSON DEFAULT NULL, partners JSON DEFAULT NULL, intervention_zone VARCHAR(255) NOT NULL, project_manager_name VARCHAR(255) DEFAULT NULL, project_manager_position VARCHAR(255) DEFAULT NULL, project_manager_email VARCHAR(255) DEFAULT NULL, project_manager_tel VARCHAR(255) DEFAULT NULL, project_manager_photo VARCHAR(255) DEFAULT NULL, website VARCHAR(255) DEFAULT NULL, logo VARCHAR(255) DEFAULT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updated_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE TABLE project (id INT NOT NULL, actor_id UUID NOT NULL, name VARCHAR(255) NOT NULL, location VARCHAR(255) NOT NULL, coords geometry(POINT, 0) NOT NULL, status VARCHAR(255) NOT NULL, description TEXT DEFAULT NULL, images JSON DEFAULT NULL, partners JSON DEFAULT NULL, intervention_zone VARCHAR(255) NOT NULL, project_manager_name VARCHAR(255) DEFAULT NULL, project_manager_position VARCHAR(255) DEFAULT NULL, project_manager_email VARCHAR(255) DEFAULT NULL, project_manager_tel VARCHAR(255) DEFAULT NULL, project_manager_photo VARCHAR(255) DEFAULT NULL, website VARCHAR(255) DEFAULT NULL, logo VARCHAR(255) DEFAULT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updated_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE INDEX IDX_2FB3D0EE10DAF24A ON project (actor_id)'); $this->addSql('COMMENT ON COLUMN project.actor_id IS \'(DC2Type:uuid)\''); $this->addSql('CREATE TABLE project_thematic (project_id INT NOT NULL, thematic_id INT NOT NULL, PRIMARY KEY(project_id, thematic_id))'); @@ -57,7 +57,7 @@ public function up(Schema $schema): void $this->addSql('CREATE INDEX IDX_E73AB79010DAF24A ON contracted_projects_actors (actor_id)'); $this->addSql('COMMENT ON COLUMN contracted_projects_actors.actor_id IS \'(DC2Type:uuid)\''); $this->addSql('CREATE TABLE thematic (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); - $this->addSql('CREATE TABLE "user" (id INT NOT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) NOT NULL, is_validated BOOLEAN NOT NULL, requested_roles JSON DEFAULT NULL, organisation VARCHAR(255) DEFAULT NULL, position VARCHAR(255) DEFAULT NULL, phone VARCHAR(20) DEFAULT NULL, sign_up_message TEXT DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE TABLE "user" (id INT NOT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, email VARCHAR(180) NOT NULL, roles JSON NOT NULL, password VARCHAR(255) DEFAULT NULL, is_validated BOOLEAN NOT NULL, requested_roles JSON DEFAULT NULL, organisation VARCHAR(255) DEFAULT NULL, position VARCHAR(255) DEFAULT NULL, phone VARCHAR(20) DEFAULT NULL, sign_up_message TEXT DEFAULT NULL, PRIMARY KEY(id))'); $this->addSql('ALTER TABLE actor ADD CONSTRAINT FK_447556F9B03A8386 FOREIGN KEY (created_by_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE actor_actor_expertise ADD CONSTRAINT FK_4A438EAD10DAF24A FOREIGN KEY (actor_id) REFERENCES actor (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE actor_actor_expertise ADD CONSTRAINT FK_4A438EAD916905AC FOREIGN KEY (actor_expertise_id) REFERENCES actor_expertise (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); diff --git a/symfony/src/Entity/Actor.php b/symfony/src/Entity/Actor.php index 210a92af..e33bbd6f 100644 --- a/symfony/src/Entity/Actor.php +++ b/symfony/src/Entity/Actor.php @@ -21,7 +21,6 @@ use ApiPlatform\Metadata\GetCollection; use App\Entity\Trait\TimestampableEntity; use Doctrine\Common\Collections\Collection; -use Symfony\Bundle\SecurityBundle\Security; use App\Services\State\Provider\ActorProvider; use App\Services\State\Processor\ActorProcessor; use Doctrine\Common\Collections\ArrayCollection; @@ -74,11 +73,11 @@ class Actor private ?Uuid $id = null; #[ORM\Column(length: 255)] - #[Groups([self::ACTOR_READ_ITEM_COLLECTION, self::ACTOR_READ_ITEM, self::ACTOR_WRITE])] + #[Groups([self::ACTOR_READ_ITEM_COLLECTION, self::ACTOR_READ_ITEM, self::ACTOR_WRITE, Project::PROJECT_READ_ALL])] private ?string $name = null; #[ORM\Column(length: 255)] - #[Groups([self::ACTOR_READ_ITEM_COLLECTION, self::ACTOR_READ_ITEM, self::ACTOR_WRITE])] + #[Groups([self::ACTOR_READ_ITEM_COLLECTION, self::ACTOR_READ_ITEM, self::ACTOR_WRITE, Project::PROJECT_READ_ALL])] private ?string $acronym = null; #[ORM\ManyToOne(inversedBy: 'actorsCreated')] diff --git a/symfony/src/Entity/Project.php b/symfony/src/Entity/Project.php index fc8c9661..e0b4d90b 100644 --- a/symfony/src/Entity/Project.php +++ b/symfony/src/Entity/Project.php @@ -2,10 +2,11 @@ namespace App\Entity; +use ApiPlatform\Metadata\GetCollection; +use App\Enum\AdministrativeScope; use App\Enum\Status; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; -use App\Enum\AdministrativeScopes; use ApiPlatform\Metadata\ApiResource; use App\Repository\ProjectRepository; use App\Entity\Trait\TimestampableEntity; @@ -15,30 +16,44 @@ use Symfony\Component\Serializer\Attribute\Groups; #[ORM\Entity(repositoryClass: ProjectRepository::class)] -#[ApiResource] +#[ApiResource( + paginationEnabled: false, + operations: [ + new GetCollection( + normalizationContext: ['groups' => [self::PROJECT_READ_ALL]] + ) + ] +)] class Project { use TimestampableEntity; + public const PROJECT_READ = 'project:read'; + public const PROJECT_READ_ALL = 'project:read:all'; + #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] + #[Groups([self::PROJECT_READ_ALL])] private ?int $id = null; #[ORM\Column(length: 255)] - #[Groups([Actor::ACTOR_READ_ITEM])] - private ?string $title = null; + #[Groups([self::PROJECT_READ_ALL, Actor::ACTOR_READ_ITEM])] + private ?string $name = null; #[ORM\Column(length: 255)] + #[Groups([self::PROJECT_READ_ALL])] private ?string $location = null; #[ORM\Column( type: PostGISType::GEOMETRY, options: ['geometry_type' => 'POINT'], )] + #[Groups([self::PROJECT_READ_ALL])] private ?string $coords = null; #[ORM\Column(enumType: Status::class)] + #[Groups([self::PROJECT_READ_ALL])] private ?Status $status = null; #[ORM\Column(type: Types::TEXT, nullable: true)] @@ -50,13 +65,15 @@ class Project #[ORM\Column(type: Types::JSON, nullable: true)] private ?array $partners = null; - #[ORM\Column(enumType: AdministrativeScopes::class)] - private ?AdministrativeScopes $interventionZone = null; + #[ORM\Column(enumType: AdministrativeScope::class)] + #[Groups([self::PROJECT_READ_ALL])] + private ?AdministrativeScope $interventionZone = null; /** * @var Collection */ #[ORM\ManyToMany(targetEntity: Thematic::class, inversedBy: 'projects')] + #[Groups([self::PROJECT_READ_ALL])] private Collection $thematics; #[ORM\Column(length: 255, nullable: true)] @@ -78,6 +95,7 @@ class Project private ?string $website = null; #[ORM\Column(length: 255, nullable: true)] + #[Groups([self::PROJECT_READ_ALL])] private ?string $logo = null; /** @@ -85,6 +103,7 @@ class Project */ #[ORM\JoinTable(name: 'financed_projects_actors')] #[ORM\ManyToMany(targetEntity: Actor::class)] + #[Groups([self::PROJECT_READ_ALL])] private Collection $financialActors; /** @@ -93,10 +112,12 @@ class Project #[ORM\JoinTable(name: 'contracted_projects_actors')] #[ORM\ManyToMany(targetEntity: Actor::class)] + #[Groups([self::PROJECT_READ_ALL])] private Collection $contractingActors; #[ORM\ManyToOne(inversedBy: 'projects')] #[ORM\JoinColumn(nullable: false)] + #[Groups([self::PROJECT_READ_ALL])] private ?Actor $actor = null; public function __construct() @@ -111,14 +132,14 @@ public function getId(): ?int return $this->id; } - public function getTitle(): ?string + public function getName(): ?string { - return $this->title; + return $this->name; } - public function setTitle(string $title): static + public function setName(string $name): static { - $this->title = $title; + $this->name = $name; return $this; } @@ -135,9 +156,14 @@ public function setLocation(string $location): static return $this; } - public function getCoords(): ?string - { - return $this->coords; + public function getCoords(): ?array { + if (preg_match('/POINT\(([-\d\.]+) ([-\d\.]+)\)/', $this->coords, $matches)) { + return [ + 'lat' => (float)$matches[1], + 'long' => (float)$matches[2], + ]; + } + return null; } public function setCoords(string $coords): static @@ -195,12 +221,12 @@ public function setPartners(?array $partners): static return $this; } - public function getInterventionZone(): ?AdministrativeScopes + public function getInterventionZone(): ?AdministrativeScope { return $this->interventionZone; } - public function setInterventionZone(AdministrativeScopes $interventionZone): static + public function setInterventionZone(AdministrativeScope $interventionZone): static { $this->interventionZone = $interventionZone; diff --git a/symfony/src/Entity/Thematic.php b/symfony/src/Entity/Thematic.php index e345d6e1..407e607a 100644 --- a/symfony/src/Entity/Thematic.php +++ b/symfony/src/Entity/Thematic.php @@ -16,6 +16,7 @@ #[ORM\Entity(repositoryClass: ThematicRepository::class)] #[UniqueEntity('name')] #[ApiResource( + paginationEnabled: false, operations: [ new GetCollection(), new Post( @@ -28,13 +29,16 @@ )] class Thematic { + public const THEMATIC_READ = 'thematic:read'; + #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] + #[Groups([self::THEMATIC_READ, Project::PROJECT_READ_ALL])] private ?int $id = null; #[ORM\Column(length: 255)] - #[Groups([Actor::ACTOR_READ_ITEM])] + #[Groups([self::THEMATIC_READ, Actor::ACTOR_READ_ITEM, Project::PROJECT_READ_ALL])] private ?string $name = null; /** diff --git a/symfony/src/Entity/Trait/TimestampableEntity.php b/symfony/src/Entity/Trait/TimestampableEntity.php index acf13441..522e318f 100644 --- a/symfony/src/Entity/Trait/TimestampableEntity.php +++ b/symfony/src/Entity/Trait/TimestampableEntity.php @@ -2,9 +2,11 @@ namespace App\Entity\Trait; +use App\Entity\Project; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Gedmo\Mapping\Annotation as Gedmo; +use Symfony\Component\Serializer\Attribute\Groups; trait TimestampableEntity { @@ -14,6 +16,7 @@ trait TimestampableEntity #[Gedmo\Timestampable(on: 'update')] #[ORM\Column(type: Types::DATETIME_MUTABLE)] + #[Groups([Project::PROJECT_READ_ALL])] protected ?\DateTimeInterface $updatedAt; public function getCreatedAt(): ?\DateTimeInterface diff --git a/symfony/src/Enum/AdministrativeScope.php b/symfony/src/Enum/AdministrativeScope.php new file mode 100644 index 00000000..6b3dd612 --- /dev/null +++ b/symfony/src/Enum/AdministrativeScope.php @@ -0,0 +1,14 @@ + -
- - - - - +
+ + + + + + :timeout="2000"> {{ appStore.snackBarMessage }} -
- - +
+ + +
+}) + \ No newline at end of file diff --git a/vue/src/components/generic-components/content/ContentBanner.vue b/vue/src/components/content/ContentBanner.vue similarity index 82% rename from vue/src/components/generic-components/content/ContentBanner.vue rename to vue/src/components/content/ContentBanner.vue index 0c59943a..91e985ff 100644 --- a/vue/src/components/generic-components/content/ContentBanner.vue +++ b/vue/src/components/content/ContentBanner.vue @@ -26,10 +26,10 @@ - - \ No newline at end of file diff --git a/vue/src/components/generic-components/global/Autocomplete.vue b/vue/src/components/global/Autocomplete.vue similarity index 100% rename from vue/src/components/generic-components/global/Autocomplete.vue rename to vue/src/components/global/Autocomplete.vue diff --git a/vue/src/components/generic-components/global/BasicCard.vue b/vue/src/components/global/BasicCard.vue similarity index 51% rename from vue/src/components/generic-components/global/BasicCard.vue rename to vue/src/components/global/BasicCard.vue index da3a4a24..7fee1667 100644 --- a/vue/src/components/generic-components/global/BasicCard.vue +++ b/vue/src/components/global/BasicCard.vue @@ -1,12 +1,10 @@ @@ -17,7 +15,7 @@ defineProps<{ \ No newline at end of file diff --git a/vue/src/components/generic-components/global/CheckPoint.vue b/vue/src/components/global/CheckPoint.vue similarity index 100% rename from vue/src/components/generic-components/global/CheckPoint.vue rename to vue/src/components/global/CheckPoint.vue diff --git a/vue/src/components/generic-components/global/Dialog.vue b/vue/src/components/global/Dialog.vue similarity index 97% rename from vue/src/components/generic-components/global/Dialog.vue rename to vue/src/components/global/Dialog.vue index e95efc75..fb8cc24f 100644 --- a/vue/src/components/generic-components/global/Dialog.vue +++ b/vue/src/components/global/Dialog.vue @@ -72,11 +72,6 @@ const closeDialog = () => router.replace({ query: { dialog: undefined }}); align-items: center; justify-content: center; - button { - min-width: 0; - min-height: 2.75rem; - } - .Link--withoutUnderline { width: fit-content; } diff --git a/vue/src/components/generic-components/global/DialogController.vue b/vue/src/components/global/DialogController.vue similarity index 72% rename from vue/src/components/generic-components/global/DialogController.vue rename to vue/src/components/global/DialogController.vue index af1427a1..49ca198f 100644 --- a/vue/src/components/generic-components/global/DialogController.vue +++ b/vue/src/components/global/DialogController.vue @@ -8,12 +8,12 @@ import { VScaleTransition } from 'vuetify/components'; import { useApplicationStore } from '@/stores/applicationStore'; -import AuthSignIn from '@/components/views-components/auth/AuthSignIn.vue'; -import AuthBecomeMember from '@/components/views-components/auth/AuthBecomeMember.vue'; -import AuthBecomeMemberWhy from '@/components/views-components/auth/AuthBecomeMemberWhy.vue'; -import AuthBecomeMemberThanks from '@/components/views-components/auth/AuthBecomeMemberThanks.vue'; -import AuthForgotPassword from '@/components/views-components/auth/AuthForgotPassword.vue'; -import AuthForgotPasswordOk from '@/components/views-components/auth/AuthForgotPasswordOk.vue'; +import AuthSignIn from '@/views/auth/AuthSignIn.vue'; +import AuthBecomeMember from '@/views/auth/AuthBecomeMember.vue'; +import AuthBecomeMemberWhy from '@/views/auth/AuthBecomeMemberWhy.vue'; +import AuthBecomeMemberThanks from '@/views/auth/AuthBecomeMemberThanks.vue'; +import AuthForgotPassword from '@/views/auth/AuthForgotPassword.vue'; +import AuthForgotPasswordOk from '@/views/auth/AuthForgotPasswordOk.vue'; import { DialogKey } from '@/models/enums/app/DialogKey'; diff --git a/vue/src/components/generic-components/global/Form.vue b/vue/src/components/global/Form.vue similarity index 100% rename from vue/src/components/generic-components/global/Form.vue rename to vue/src/components/global/Form.vue diff --git a/vue/src/components/global/InfoCard.vue b/vue/src/components/global/InfoCard.vue new file mode 100644 index 00000000..6de1b7aa --- /dev/null +++ b/vue/src/components/global/InfoCard.vue @@ -0,0 +1,82 @@ + + + + + \ No newline at end of file diff --git a/vue/src/components/generic-components/global/InputImage.vue b/vue/src/components/global/InputImage.vue similarity index 100% rename from vue/src/components/generic-components/global/InputImage.vue rename to vue/src/components/global/InputImage.vue diff --git a/vue/src/components/generic-components/global/LikeButton.vue b/vue/src/components/global/LikeButton.vue similarity index 53% rename from vue/src/components/generic-components/global/LikeButton.vue rename to vue/src/components/global/LikeButton.vue index d2d31fb8..41933ae3 100644 --- a/vue/src/components/generic-components/global/LikeButton.vue +++ b/vue/src/components/global/LikeButton.vue @@ -1,6 +1,6 @@ diff --git a/vue/src/components/global/Modal.vue b/vue/src/components/global/Modal.vue new file mode 100644 index 00000000..71e159b1 --- /dev/null +++ b/vue/src/components/global/Modal.vue @@ -0,0 +1,96 @@ + + + + + \ No newline at end of file diff --git a/vue/src/components/generic-components/global/ShareButton.vue b/vue/src/components/global/ShareButton.vue similarity index 67% rename from vue/src/components/generic-components/global/ShareButton.vue rename to vue/src/components/global/ShareButton.vue index 57aad918..b2e8696a 100644 --- a/vue/src/components/generic-components/global/ShareButton.vue +++ b/vue/src/components/global/ShareButton.vue @@ -1,14 +1,14 @@ + + \ No newline at end of file diff --git a/vue/src/components/map/controls/ResetMapExtentControl.ts b/vue/src/components/map/controls/ResetMapExtentControl.ts new file mode 100644 index 00000000..a826f026 --- /dev/null +++ b/vue/src/components/map/controls/ResetMapExtentControl.ts @@ -0,0 +1,28 @@ +import { useApplicationStore } from "@/stores/applicationStore"; + +export default class ResetMapExtentControl { + _map: any + _container: any + + onAdd(map: any) { + this._map = map; + this._container = document.createElement('div'); + this._container.className = 'maplibregl-ctrl maplibregl-ctrl-group'; + const btn = document.createElement("button"); + btn.className = 'maplibregl-ctrl-zoom-extent' + const span = document.createElement("span"); + span.className = 'maplibregl-ctrl-icon' + btn.appendChild(span) + this._container.appendChild(btn); + this._container.addEventListener('click', () => { + useApplicationStore().triggerZoomReset = !useApplicationStore().triggerZoomReset + }) + + return this._container; + } + + onRemove() { + this._container.parentNode.removeChild(this._container); + this._map = undefined; + } +} diff --git a/vue/src/components/map/controls/ToggleSidebarControl.ts b/vue/src/components/map/controls/ToggleSidebarControl.ts new file mode 100644 index 00000000..b5720cfa --- /dev/null +++ b/vue/src/components/map/controls/ToggleSidebarControl.ts @@ -0,0 +1,28 @@ +import { useProjectStore } from "@/stores/projectStore"; +export default class ToggleSidebarControl { + _map: any + _container: any + + onAdd(map: any) { + this._map = map; + this._container = document.createElement('div'); + this._container.className = 'maplibregl-ctrl maplibregl-ctrl-group'; + const btn = document.createElement("button"); + btn.className = 'maplibregl-ctrl-toggle-sidebar' + const span = document.createElement("span"); + span.className = 'maplibregl-ctrl-icon' + btn.appendChild(span) + this._container.appendChild(btn); + this._container.addEventListener('click', () => { + useProjectStore().isProjectMapFullWidth = !useProjectStore().isProjectMapFullWidth + btn.setAttribute('active', useProjectStore().isProjectMapFullWidth.toString()) + }) + + return this._container; + } + + onRemove() { + this._container.parentNode.removeChild(this._container); + this._map = undefined; + } +} diff --git a/vue/src/components/generic-components/text-elements/FormSectionTitle.vue b/vue/src/components/text-elements/FormSectionTitle.vue similarity index 100% rename from vue/src/components/generic-components/text-elements/FormSectionTitle.vue rename to vue/src/components/text-elements/FormSectionTitle.vue diff --git a/vue/src/components/generic-components/text-elements/PageTitle.vue b/vue/src/components/text-elements/PageTitle.vue similarity index 100% rename from vue/src/components/generic-components/text-elements/PageTitle.vue rename to vue/src/components/text-elements/PageTitle.vue diff --git a/vue/src/components/generic-components/text-elements/SectionTitle.vue b/vue/src/components/text-elements/SectionTitle.vue similarity index 100% rename from vue/src/components/generic-components/text-elements/SectionTitle.vue rename to vue/src/components/text-elements/SectionTitle.vue diff --git a/vue/src/components/views-components/actors/ActorCard.vue b/vue/src/components/views-components/actors/ActorCard.vue deleted file mode 100644 index beb13d3b..00000000 --- a/vue/src/components/views-components/actors/ActorCard.vue +++ /dev/null @@ -1,51 +0,0 @@ - - - - - \ No newline at end of file diff --git a/vue/src/components/views-components/actors/ActorEditionForm.vue b/vue/src/components/views-components/actors/ActorEditionForm.vue deleted file mode 100644 index acb30bff..00000000 --- a/vue/src/components/views-components/actors/ActorEditionForm.vue +++ /dev/null @@ -1,209 +0,0 @@ - - diff --git a/vue/src/components/views-components/projects/ProjectCard.vue b/vue/src/components/views-components/projects/ProjectCard.vue deleted file mode 100644 index 0aa492cd..00000000 --- a/vue/src/components/views-components/projects/ProjectCard.vue +++ /dev/null @@ -1,50 +0,0 @@ - - - - - \ No newline at end of file diff --git a/vue/src/components/views/ProjectsView.vue b/vue/src/components/views/ProjectsView.vue deleted file mode 100644 index 49c0e1f7..00000000 --- a/vue/src/components/views/ProjectsView.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - - \ No newline at end of file diff --git a/vue/src/composables/useDate.ts b/vue/src/composables/useDate.ts new file mode 100644 index 00000000..3312719e --- /dev/null +++ b/vue/src/composables/useDate.ts @@ -0,0 +1,9 @@ +import { ref } from "vue" + +export function useDate(date: Date) { + const localeDate = ref('') + + localeDate.value = date.toLocaleDateString('fr-FR', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }) + + return { localeDate } +} \ No newline at end of file diff --git a/vue/src/models/enums/AdministrativeScope.ts b/vue/src/models/enums/AdministrativeScope.ts new file mode 100644 index 00000000..29f67212 --- /dev/null +++ b/vue/src/models/enums/AdministrativeScope.ts @@ -0,0 +1,6 @@ +export enum AdministrativeScope { + NATIONAL = 'national', + REGIONAL = 'regional', + STATE = 'state', + CITY = 'city', +} \ No newline at end of file diff --git a/vue/src/models/enums/SortKey.ts b/vue/src/models/enums/SortKey.ts new file mode 100644 index 00000000..4613a19e --- /dev/null +++ b/vue/src/models/enums/SortKey.ts @@ -0,0 +1,7 @@ +export enum SortKey { + PROJECTS_AZ = 'projects_az', + PROJECTS_ZA = 'projects_za', + UPDATED_AT_AZ = 'updated_at_az', + ACTORS_AZ = 'actors_az', + ACTORS_ZA = 'actors_za', +} \ No newline at end of file diff --git a/vue/src/models/enums/app/StoresList.ts b/vue/src/models/enums/app/StoresList.ts index 1434b810..af993fe6 100644 --- a/vue/src/models/enums/app/StoresList.ts +++ b/vue/src/models/enums/app/StoresList.ts @@ -2,5 +2,7 @@ export enum StoresList { APPLICATION = "application", ADMIN = "admin", USER = "user", - ACTORS = "actors" + ACTORS = "actors", + PROJECTS = "projects", + THEMATICS = "thematics", } \ No newline at end of file diff --git a/vue/src/models/interfaces/Project.ts b/vue/src/models/interfaces/Project.ts index 23beffca..dacec22e 100644 --- a/vue/src/models/interfaces/Project.ts +++ b/vue/src/models/interfaces/Project.ts @@ -1,17 +1,20 @@ +import type { Actor } from "@/models/interfaces/Actor"; +import type { Thematic } from "@/models/interfaces/Thematic"; +import type { AdministrativeScope } from "@/models/enums/AdministrativeScope"; +import type { Timestampable } from "@/models/interfaces/common/Timestampable"; import type { Status } from "@/models/enums/contents/Status"; -import type { SymfonyRelation } from "./SymfonyRelation"; -export interface Project { +export interface Project extends Timestampable { id: number; - title: string; + name: string; location: string; coords: string; status: Status; description: string; images: string[]; partners: string[]; - interventionZone: SymfonyRelation[]; - thematics: SymfonyRelation[]; + interventionZone: AdministrativeScope; + thematics: Thematic[]; projectManagerName: string; projectManagerPosition: string; projectManagerEmail: string; @@ -19,7 +22,7 @@ export interface Project { projectManagerPhoto: string; website: string; logo: string; - financialActors: SymfonyRelation[]; - contractingActors: SymfonyRelation[]; - actor: SymfonyRelation; + financialActors: Actor[]; + contractingActors: Actor[]; + actor: Actor; } \ No newline at end of file diff --git a/vue/src/models/interfaces/Thematic.ts b/vue/src/models/interfaces/Thematic.ts index e28ff5ab..04df2f34 100644 --- a/vue/src/models/interfaces/Thematic.ts +++ b/vue/src/models/interfaces/Thematic.ts @@ -1,3 +1,5 @@ -import type { SymfonyRelation } from "./SymfonyRelation"; +import type { SymfonyRelation } from "@/models/interfaces/SymfonyRelation"; -export interface Thematic extends SymfonyRelation {} \ No newline at end of file +export interface Thematic extends SymfonyRelation { + id: number; +} diff --git a/vue/src/models/interfaces/common/Timestampable.ts b/vue/src/models/interfaces/common/Timestampable.ts new file mode 100644 index 00000000..4e818ef3 --- /dev/null +++ b/vue/src/models/interfaces/common/Timestampable.ts @@ -0,0 +1,4 @@ +export interface Timestampable { + createdAt: Date + updatedAt: Date +} diff --git a/vue/src/router/index.ts b/vue/src/router/index.ts index c692d794..b5bb8c32 100644 --- a/vue/src/router/index.ts +++ b/vue/src/router/index.ts @@ -1,10 +1,10 @@ import { createRouter, createWebHistory } from 'vue-router' -import HomeView from '@/components/views/HomeView.vue' +import HomeView from '@/views/home/HomeView.vue' import { useApplicationStore } from '@/stores/applicationStore' -import ActorProfile from '@/components/views-components/actors/ActorProfile.vue' -import AdminMembers from '@/components/views-components/admin/AdminMembers.vue' -import AdminContent from '@/components/views-components/admin/AdminContent.vue' -import AdminComments from '@/components/views-components/admin/AdminComments.vue' +import ActorProfile from '@/views/actors/components/ActorProfile.vue' +import AdminMembers from '@/views/admin/components/AdminMembers.vue' +import AdminContent from '@/views/admin/components/AdminContent.vue' +import AdminComments from '@/views/admin/components/AdminComments.vue' import { useAdminStore } from '@/stores/adminStore' import { AdministrationPanels } from '@/models/enums/app/AdministrationPanels' import { DialogKey } from '@/models/enums/app/DialogKey' @@ -20,10 +20,7 @@ const router = createRouter({ { path: '/actors', name: 'actors', - // route level code-splitting - // this generates a separate chunk (About.[hash].js) for this route - // which is lazy-loaded when the route is visited. - component: () => import('../components/views/ActorsView.vue') + component: () => import('@/views/actors/ActorsView.vue') }, { path: '/actors/:name', @@ -33,27 +30,27 @@ const router = createRouter({ { path: '/projects', name: 'projects', - component: () => import('../components/views/ProjectsView.vue') + component: () => import('@/views/projects/ProjectsView.vue') }, { path: '/resources', name: 'resources', - component: () => import('../components/views/ResourcesView.vue') + component: () => import('@/views/resources/ResourcesView.vue') }, { path: '/services', name: 'services', - component: () => import('../components/views/ServicesView.vue') + component: () => import('@/views/services/ServicesView.vue') }, { path: '/map', name: 'map', - component: () => import('../components/views/MapView.vue') + component: () => import('@/views/map/MapView.vue') }, { path: '/members', name: 'members', - component: () => import('../components/views/MemberView.vue') + component: () => import('@/views/member/MemberView.vue') }, { path: '/administration', @@ -65,7 +62,7 @@ const router = createRouter({ path: '/administration/membersPanel' } }, - component: () => import('../components/views/AdminView.vue'), + component: () => import('@/views/admin/AdminView.vue'), children: [ { path: 'membersPanel', diff --git a/vue/src/services/actors/ActorsForm.ts b/vue/src/services/actors/ActorsForm.ts index 5e561c76..23d2820b 100644 --- a/vue/src/services/actors/ActorsForm.ts +++ b/vue/src/services/actors/ActorsForm.ts @@ -3,7 +3,6 @@ import { toTypedSchema } from "@vee-validate/zod"; import { useField, useForm } from "vee-validate"; import { z, ZodType } from "zod"; import { i18n } from "@/assets/plugins/i18n"; -import { ActorsCategories } from '@/models/enums/contents/actors/ActorsCategories' import type { SymfonyRelation } from "@/models/interfaces/SymfonyRelation"; export class ActorsFormService { diff --git a/vue/src/services/map/MapService.ts b/vue/src/services/map/MapService.ts new file mode 100644 index 00000000..aec71461 --- /dev/null +++ b/vue/src/services/map/MapService.ts @@ -0,0 +1,33 @@ +import maplibregl from "maplibre-gl"; + +export default class MapService { + + static getGeojson(data: any[]): any { + const geojson: any = []; + Array.prototype.forEach.call(data , (item: any) => { + geojson.push({ + 'id': item.id, + 'properties': { + 'id': item.id, + 'name': item.name, + }, + 'geometry': { + 'type': 'Point', + 'coordinates': [item.coords.long, item.coords.lat] + } + }) + }) + + return { + 'type': 'FeatureCollection', + 'features': geojson + }; + } + + static getBounds (features: any) { + const coordinates = features.map((f: any) => f.geometry.coordinates) + return coordinates.reduce((bounds: any, coord: any) => { + return bounds.extend(coord); + }, new maplibregl.LngLatBounds(coordinates[0], coordinates[0])); + } +} \ No newline at end of file diff --git a/vue/src/services/projects/ProjectService.ts b/vue/src/services/projects/ProjectService.ts new file mode 100644 index 00000000..f04b7b9d --- /dev/null +++ b/vue/src/services/projects/ProjectService.ts @@ -0,0 +1,9 @@ +import { apiClient } from "@/assets/plugins/axios"; +import type { Project } from "@/models/interfaces/Project"; + +export class ProjectService { + static async getAll(): Promise { + return await apiClient.get('/api/projects') + .then((response) => response.data['hydra:member']) + } +} \ No newline at end of file diff --git a/vue/src/services/thematics/ThematicService.ts b/vue/src/services/thematics/ThematicService.ts new file mode 100644 index 00000000..de408c46 --- /dev/null +++ b/vue/src/services/thematics/ThematicService.ts @@ -0,0 +1,9 @@ +import { apiClient } from "@/assets/plugins/axios"; +import type { Thematic } from '@/models/interfaces/Thematic'; + +export class ThematicService { + static async getAll(): Promise { + return await apiClient.get('/api/thematics') + .then((response) => response.data['hydra:member']) + } +} \ No newline at end of file diff --git a/vue/src/services/utils/UtilsService.ts b/vue/src/services/utils/UtilsService.ts new file mode 100644 index 00000000..e32c6a37 --- /dev/null +++ b/vue/src/services/utils/UtilsService.ts @@ -0,0 +1,4 @@ +export const uniqueArray = (array: any[], key = 'id') => { + return array.filter((obj1, i, arr) => + arr.findIndex(obj2 => (obj2[key] === obj1[key])) === i +)}; \ No newline at end of file diff --git a/vue/src/stores/actorsStore.ts b/vue/src/stores/actorsStore.ts index aa7497f6..d547d8e4 100644 --- a/vue/src/stores/actorsStore.ts +++ b/vue/src/stores/actorsStore.ts @@ -45,7 +45,7 @@ export const useActorsStore = defineStore(StoresList.ACTORS, () => { function setActorEditionMode(actor: Actor | null) { actorEdition.actor = actor actorEdition.active = true - useApplicationStore().showEditContentDialog = true + useApplicationStore().showEditContentDialog = actor == null ? false : true } async function createOrEditActor(actor: Actor, edit: boolean) { diff --git a/vue/src/stores/applicationStore.ts b/vue/src/stores/applicationStore.ts index 07b37583..0a201360 100644 --- a/vue/src/stores/applicationStore.ts +++ b/vue/src/stores/applicationStore.ts @@ -5,6 +5,7 @@ import { defineStore } from 'pinia' import { computed, ref } from 'vue' import { useRoute } from 'vue-router' import { useDisplay } from 'vuetify' +import { useProjectStore } from '@/stores/projectStore' import { DialogKey } from '@/models/enums/app/DialogKey' import type { Ref } from 'vue' @@ -14,12 +15,23 @@ export const useApplicationStore = defineStore(StoresList.APPLICATION, () => { const activeDialog: Ref = ref(null) const showEditContentDialog = ref(false) const route = useRoute(); + const triggerZoomReset = ref(false) + const showSnackBar = ref(false) + const snackBarMessage = ref('') + const breadcrumbs = computed(() => { activeTab.value = NavigationTabsService.getTabsNumberFromRoute(route, activeTab.value) return BreadcrumbsService.getBreadcrumbsItems(route) }) - const showSnackBar = ref(false) - const snackBarMessage = ref('') - return { mobile, activeTab, activeDialog, breadcrumbs, showEditContentDialog, showSnackBar, snackBarMessage } + const is100vh = computed(() => { + return useProjectStore().isProjectMapFullWidth + }) + + const isLightHeader = computed(() => { + const lightUiRoutes: string[] = ['projects'] + return route.name && typeof route.name === 'string' && lightUiRoutes.includes(route.name) + }) + + return { mobile, showSnackBar, snackBarMessage, activeTab, activeDialog, breadcrumbs, is100vh, isLightHeader, triggerZoomReset, showEditContentDialog } }) diff --git a/vue/src/stores/projectStore.ts b/vue/src/stores/projectStore.ts new file mode 100644 index 00000000..4aecc261 --- /dev/null +++ b/vue/src/stores/projectStore.ts @@ -0,0 +1,106 @@ +import { StoresList } from '@/models/enums/app/StoresList' +import { defineStore } from 'pinia' +import { computed, reactive, ref, type Ref, type Reactive } from 'vue'; +import type { Project } from '@/models/interfaces/Project' +import { ProjectService } from '@/services/projects/ProjectService' +import maplibregl from 'maplibre-gl'; +import { SortKey } from '@/models/enums/SortKey' +import type { Status } from '@/models/enums/contents/Status'; +import type { Thematic } from '@/models/interfaces/Thematic'; +import type { AdministrativeScope } from '@/models/enums/AdministrativeScope'; +import type { Actor } from '@/models/interfaces/Actor'; + +export const useProjectStore = defineStore(StoresList.PROJECTS, () => { + const projects: Ref = ref([]) + const hoveredProjectId: Ref = ref(null) + const activeProjectId: Ref = ref(null) + const map: Ref = ref(null) + const isFilterModalShown: Ref = ref(false) + const sortingProjectsSelectedMethod = ref(SortKey.PROJECTS_AZ) + const isProjectMapFullWidth = ref(false) + + const filters: Reactive<{ + searchValue: string, + thematics: Thematic['id'][], + statuses: Status[], + interventionZones: AdministrativeScope[], + contractingActors: Actor['id'][], + financialActors: Actor['id'][], + }> = reactive({ + searchValue: '', + thematics: [], + statuses: [], + interventionZones: [], + contractingActors: [], + financialActors: [], + }) + + async function getAll(): Promise { + if (projects.value.length === 0) { + projects.value = await ProjectService.getAll() + } + } + + const hoveredProject = computed(() => { + if (hoveredProjectId.value) { + return projects.value.find((project) => project.id === hoveredProjectId.value) + } + return null + }) + + const activeProject = computed(() => { + if (activeProjectId.value) { + return projects.value.find((project) => project.id === activeProjectId.value) ?? null + } + return null + }) + + const filteredProjects = computed(() => { + return projects.value.filter((project) => { + const projectThematicIds = project.thematics.map((projectThematic) => projectThematic.id) + const projectContractingActorIds = project.contractingActors.map((contractingActor) => contractingActor.id) + const projectFinancialActorIds = project.financialActors.map((financialActor) => financialActor.id) + + return ( + project.name.toLowerCase().includes(filters.searchValue.toLowerCase()) && + (filters.thematics.length === 0 || filters.thematics.some((thematic) => projectThematicIds.includes(thematic))) && + (filters.statuses.length === 0 || filters.statuses.some((status) => project.status === status)) && + (filters.interventionZones.length === 0 || filters.interventionZones.some((interventionZone) => project.interventionZone === interventionZone)) && + (filters.contractingActors.length === 0 || filters.contractingActors.some((contractingActor) => projectContractingActorIds.includes(contractingActor))) && + (filters.financialActors.length === 0 || filters.financialActors.some((financialActor) => projectFinancialActorIds.includes(financialActor))) + ) + }) + }) + + const orderedProjects = computed(() => { + const sortedProjects = [...filteredProjects.value]; + switch (sortingProjectsSelectedMethod.value) { + case SortKey.PROJECTS_AZ: + return sortedProjects.sort((a, b) => a.name.localeCompare(b.name)); + case SortKey.PROJECTS_ZA: + return sortedProjects.sort((a, b) => b.name.localeCompare(a.name)); + case SortKey.UPDATED_AT_AZ: + return sortedProjects.sort((a, b) => (new Date(b.updatedAt).valueOf() - new Date(a.updatedAt).valueOf())); + case SortKey.ACTORS_AZ: + return sortedProjects.sort((a, b) => a.actor.name.localeCompare(b.actor.name)); + case SortKey.ACTORS_ZA: + return sortedProjects.sort((a, b) => b.actor.name.localeCompare(a.actor.name)); + default: + return sortedProjects + } + }) + + const resetFilters = () => { + filters.searchValue = '' + filters.thematics = [] + filters.statuses = [] + filters.interventionZones = [] + filters.contractingActors = [] + filters.financialActors = [] + } + + return { + projects, filters, isProjectMapFullWidth, isFilterModalShown, sortingProjectsSelectedMethod, hoveredProjectId, hoveredProject, activeProjectId, activeProject, filteredProjects, orderedProjects, map, + getAll, resetFilters + } +}) diff --git a/vue/src/stores/thematicStore.ts b/vue/src/stores/thematicStore.ts new file mode 100644 index 00000000..e4d5d860 --- /dev/null +++ b/vue/src/stores/thematicStore.ts @@ -0,0 +1,17 @@ +import { StoresList } from '@/models/enums/app/StoresList' +import { defineStore } from 'pinia' +import { ref, type Ref } from 'vue' +import type { Thematic } from '@/models/interfaces/Thematic' +import { ThematicService } from '@/services/thematics/ThematicService' + +export const useThematicStore = defineStore(StoresList.THEMATICS, () => { + const thematics: Ref = ref([]) + + async function getAll(): Promise { + if (thematics.value.length === 0) { + thematics.value = await ThematicService.getAll() + } + } + + return { thematics, getAll } +}) diff --git a/vue/src/components/views-components/header/Header.vue b/vue/src/views/_layout/header/Header.vue similarity index 100% rename from vue/src/components/views-components/header/Header.vue rename to vue/src/views/_layout/header/Header.vue diff --git a/vue/src/components/views-components/header/HeaderDesktop.vue b/vue/src/views/_layout/header/HeaderDesktop.vue similarity index 98% rename from vue/src/components/views-components/header/HeaderDesktop.vue rename to vue/src/views/_layout/header/HeaderDesktop.vue index 126c7dc9..83f3df2b 100644 --- a/vue/src/components/views-components/header/HeaderDesktop.vue +++ b/vue/src/views/_layout/header/HeaderDesktop.vue @@ -99,6 +99,7 @@ const appStore = useApplicationStore(); &--left { .Header__appLogo { z-index: 10; + position: relative; height: $dim-logo; transform: translateY(-$dim-banner) } diff --git a/vue/src/components/views-components/header/HeaderMobile.vue b/vue/src/views/_layout/header/HeaderMobile.vue similarity index 100% rename from vue/src/components/views-components/header/HeaderMobile.vue rename to vue/src/views/_layout/header/HeaderMobile.vue diff --git a/vue/src/components/views-components/header/LoginButton.vue b/vue/src/views/_layout/header/LoginButton.vue similarity index 100% rename from vue/src/components/views-components/header/LoginButton.vue rename to vue/src/views/_layout/header/LoginButton.vue diff --git a/vue/src/components/views/ActorsView.vue b/vue/src/views/actors/ActorsView.vue similarity index 87% rename from vue/src/components/views/ActorsView.vue rename to vue/src/views/actors/ActorsView.vue index 304aa80e..7a1f571a 100644 --- a/vue/src/components/views/ActorsView.vue +++ b/vue/src/views/actors/ActorsView.vue @@ -41,11 +41,11 @@ + + \ No newline at end of file diff --git a/vue/src/views/actors/components/ActorEditionForm.vue b/vue/src/views/actors/components/ActorEditionForm.vue new file mode 100644 index 00000000..21002fc4 --- /dev/null +++ b/vue/src/views/actors/components/ActorEditionForm.vue @@ -0,0 +1,122 @@ + + diff --git a/vue/src/components/views-components/actors/ActorProfile.vue b/vue/src/views/actors/components/ActorProfile.vue similarity index 89% rename from vue/src/components/views-components/actors/ActorProfile.vue rename to vue/src/views/actors/components/ActorProfile.vue index 84c6f132..edc67d63 100644 --- a/vue/src/components/views-components/actors/ActorProfile.vue +++ b/vue/src/views/actors/components/ActorProfile.vue @@ -12,7 +12,7 @@
- +
@@ -40,13 +40,13 @@ import type { Actor } from '@/models/interfaces/Actor'; import { useActorsStore } from '@/stores/actorsStore'; import { computed, onMounted, watchEffect } from 'vue'; import { useRoute } from 'vue-router'; -import ContentBanner from '@/components/generic-components/content/ContentBanner.vue'; -import SectionTitle from '@/components/generic-components/text-elements/SectionTitle.vue'; -import ContentDivider from '@/components/generic-components/content/ContentDivider.vue'; +import ContentBanner from '@/components/content/ContentBanner.vue'; +import SectionTitle from '@/components/text-elements/SectionTitle.vue'; +import ContentDivider from '@/components/content/ContentDivider.vue'; import ActorRelatedContent from './ActorRelatedContent.vue'; -import ThematicChip from '@/components/generic-components/content/ThematicChip.vue'; import { useApplicationStore } from '@/stores/applicationStore'; import { useUserStore } from '@/stores/userStore'; +import ChipList from '@/components/content/ChipList.vue'; const appStore = useApplicationStore(); const userStore = useUserStore(); diff --git a/vue/src/components/views-components/actors/ActorRelatedContent.vue b/vue/src/views/actors/components/ActorRelatedContent.vue similarity index 86% rename from vue/src/components/views-components/actors/ActorRelatedContent.vue rename to vue/src/views/actors/components/ActorRelatedContent.vue index f818bd94..a2217188 100644 --- a/vue/src/components/views-components/actors/ActorRelatedContent.vue +++ b/vue/src/views/actors/components/ActorRelatedContent.vue @@ -8,7 +8,7 @@ \ No newline at end of file diff --git a/vue/src/views/projects/components/ProjectCard.vue b/vue/src/views/projects/components/ProjectCard.vue new file mode 100644 index 00000000..474cdef6 --- /dev/null +++ b/vue/src/views/projects/components/ProjectCard.vue @@ -0,0 +1,131 @@ + + + + + \ No newline at end of file diff --git a/vue/src/views/projects/components/ProjectFilterModal.vue b/vue/src/views/projects/components/ProjectFilterModal.vue new file mode 100644 index 00000000..e4a9d6cb --- /dev/null +++ b/vue/src/views/projects/components/ProjectFilterModal.vue @@ -0,0 +1,82 @@ + + \ No newline at end of file diff --git a/vue/src/views/projects/components/ProjectMap.vue b/vue/src/views/projects/components/ProjectMap.vue new file mode 100644 index 00000000..51a454c6 --- /dev/null +++ b/vue/src/views/projects/components/ProjectMap.vue @@ -0,0 +1,168 @@ + + + + + + \ No newline at end of file diff --git a/vue/src/views/projects/components/map-controls/ShowProjectFiltersModalControl.ts b/vue/src/views/projects/components/map-controls/ShowProjectFiltersModalControl.ts new file mode 100644 index 00000000..666ca1b7 --- /dev/null +++ b/vue/src/views/projects/components/map-controls/ShowProjectFiltersModalControl.ts @@ -0,0 +1,34 @@ +import { i18n } from "@/assets/plugins/i18n"; +import { useApplicationStore } from "@/stores/applicationStore"; +import { useProjectStore } from "@/stores/projectStore"; + +export default class ShowProjectFiltersModalControl { + _map: any + _container: any + + onAdd(map: any) { + this._map = map; + this._container = document.createElement('div'); + this._container.className = 'maplibregl-ctrl maplibregl-ctrl-group maplibregl-ctrl-show-project-filters-ctn'; + const btn = document.createElement("button"); + btn.className = 'maplibregl-ctrl-show-project-filters' + const span = document.createElement("span"); + span.textContent = i18n.t('projects.map.filterProjects'); + span.className = 'maplibregl-ctrl-text' + const icon = document.createElement("span"); + icon.className = 'maplibregl-ctrl-icon' + btn.appendChild(icon) + btn.appendChild(span) + this._container.appendChild(btn); + this._container.addEventListener('click', () => { + useProjectStore().isFilterModalShown = true + }) + + return this._container; + } + + onRemove() { + this._container.parentNode.removeChild(this._container); + this._map = undefined; + } +} diff --git a/vue/src/components/views/ResourcesView.vue b/vue/src/views/resources/ResourcesView.vue similarity index 100% rename from vue/src/components/views/ResourcesView.vue rename to vue/src/views/resources/ResourcesView.vue diff --git a/vue/src/components/views/ServicesView.vue b/vue/src/views/services/ServicesView.vue similarity index 100% rename from vue/src/components/views/ServicesView.vue rename to vue/src/views/services/ServicesView.vue diff --git a/vue/yarn.lock b/vue/yarn.lock index 74dacf37..19fb8a66 100644 --- a/vue/yarn.lock +++ b/vue/yarn.lock @@ -96,11 +96,21 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz#5b3329c9a58803d5df425e5785865881a81ca48d" integrity sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ== +"@babel/helper-string-parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" + integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== + "@babel/helper-validator-identifier@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== +"@babel/helper-validator-identifier@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" + integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== + "@babel/helper-validator-option@^7.24.8": version "7.24.8" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz#3725cdeea8b480e86d34df15304806a06975e33d" @@ -136,6 +146,13 @@ dependencies: "@babel/types" "^7.25.6" +"@babel/parser@^7.25.3": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.7.tgz#99b927720f4ddbfeb8cd195a363ed4532f87c590" + integrity sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw== + dependencies: + "@babel/types" "^7.25.7" + "@babel/template@^7.25.0": version "7.25.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.0.tgz#e733dc3134b4fede528c15bc95e89cb98c52592a" @@ -167,6 +184,15 @@ "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" +"@babel/types@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.7.tgz#1b7725c1d3a59f328cb700ce704c46371e6eef9b" + integrity sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ== + dependencies: + "@babel/helper-string-parser" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + to-fast-properties "^2.0.0" + "@esbuild/aix-ppc64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" @@ -378,7 +404,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== @@ -979,7 +1005,26 @@ estree-walker "^2.0.2" source-map-js "^1.2.0" -"@vue/compiler-dom@3.4.33", "@vue/compiler-dom@^3.4.0": +"@vue/compiler-core@3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.10.tgz#dc382e4173c5ad6d309887f5cb02983dfd88cfee" + integrity sha512-iXWlk+Cg/ag7gLvY0SfVucU8Kh2CjysYZjhhP70w9qI4MvSox4frrP+vDGvtQuzIcgD8+sxM6lZvCtdxGunTAA== + dependencies: + "@babel/parser" "^7.25.3" + "@vue/shared" "3.5.10" + entities "^4.5.0" + estree-walker "^2.0.2" + source-map-js "^1.2.0" + +"@vue/compiler-dom@3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.10.tgz#233c660289ce289a48e8fe759b07b95f607cd98e" + integrity sha512-DyxHC6qPcktwYGKOIy3XqnHRrrXyWR2u91AjP+nLkADko380srsC2DC3s7Y1Rk6YfOlxOlvEQKa9XXmLI+W4ZA== + dependencies: + "@vue/compiler-core" "3.5.10" + "@vue/shared" "3.5.10" + +"@vue/compiler-dom@^3.4.0": version "3.4.33" resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.4.33.tgz#1ceea5408a0e06c857a78d7a2be7fe3b63cf9f64" integrity sha512-GzB8fxEHKw0gGet5BKlpfXEqoBnzSVWwMnT+dc25wE7pFEfrU/QsvjZMP9rD4iVXHBBoemTct8mN0GJEI6ZX5A== @@ -987,28 +1032,28 @@ "@vue/compiler-core" "3.4.33" "@vue/shared" "3.4.33" -"@vue/compiler-sfc@3.4.33": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.4.33.tgz#6ea43dee6bb341967be26b47786f1f73a8e089a2" - integrity sha512-7rk7Vbkn21xMwIUpHQR4hCVejwE6nvhBOiDgoBcR03qvGqRKA7dCBSsHZhwhYUsmjlbJ7OtD5UFIyhP6BY+c8A== +"@vue/compiler-sfc@3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.10.tgz#95e262a5ed836521a5aeee9492cc265ad3f1c787" + integrity sha512-to8E1BgpakV7224ZCm8gz1ZRSyjNCAWEplwFMWKlzCdP9DkMKhRRwt0WkCjY7jkzi/Vz3xgbpeig5Pnbly4Tow== dependencies: - "@babel/parser" "^7.24.7" - "@vue/compiler-core" "3.4.33" - "@vue/compiler-dom" "3.4.33" - "@vue/compiler-ssr" "3.4.33" - "@vue/shared" "3.4.33" + "@babel/parser" "^7.25.3" + "@vue/compiler-core" "3.5.10" + "@vue/compiler-dom" "3.5.10" + "@vue/compiler-ssr" "3.5.10" + "@vue/shared" "3.5.10" estree-walker "^2.0.2" - magic-string "^0.30.10" - postcss "^8.4.39" + magic-string "^0.30.11" + postcss "^8.4.47" source-map-js "^1.2.0" -"@vue/compiler-ssr@3.4.33": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.4.33.tgz#59ed58f97abb691e6c3973616bb27a12b8c5b135" - integrity sha512-0WveC9Ai+eT/1b6LCV5IfsufBZ0HP7pSSTdDjcuW302tTEgoBw8rHVHKPbGUtzGReUFCRXbv6zQDDgucnV2WzQ== +"@vue/compiler-ssr@3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.10.tgz#195f83ae7c52174be37fd7a4a0217132c1c0ed11" + integrity sha512-hxP4Y3KImqdtyUKXDRSxKSRkSm1H9fCvhojEYrnaoWhE4w/y8vwWhnosJoPPe2AXm5sU7CSbYYAgkt2ZPhDz+A== dependencies: - "@vue/compiler-dom" "3.4.33" - "@vue/shared" "3.4.33" + "@vue/compiler-dom" "3.5.10" + "@vue/shared" "3.5.10" "@vue/devtools-api@^6.5.0", "@vue/devtools-api@^6.5.1": version "6.6.3" @@ -1051,44 +1096,49 @@ path-browserify "^1.0.1" vue-template-compiler "^2.7.14" -"@vue/reactivity@3.4.33": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.4.33.tgz#9d258a8bab369ce57402c51728d3769ecf7adb99" - integrity sha512-B24QIelahDbyHipBgbUItQblbd4w5HpG3KccL+YkGyo3maXyS253FzcTR3pSz739OTphmzlxP7JxEMWBpewilA== +"@vue/reactivity@3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.10.tgz#81140ef0b05096973356d3c8fc32f48c79940b9c" + integrity sha512-kW08v06F6xPSHhid9DJ9YjOGmwNDOsJJQk0ax21wKaUYzzuJGEuoKNU2Ujux8FLMrP7CFJJKsHhXN9l2WOVi2g== dependencies: - "@vue/shared" "3.4.33" + "@vue/shared" "3.5.10" -"@vue/runtime-core@3.4.33": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.4.33.tgz#c9481aa6d0785f7349a69f3e971082ac0ff720ee" - integrity sha512-6wavthExzT4iAxpe8q37/rDmf44nyOJGISJPxCi9YsQO+8w9v0gLCFLfH5TzD1V1AYrTAdiF4Y1cgUmP68jP6w== +"@vue/runtime-core@3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.10.tgz#e902eb2640fa6ab4cc4589af263818a898812668" + integrity sha512-9Q86I5Qq3swSkFfzrZ+iqEy7Vla325M7S7xc1NwKnRm/qoi1Dauz0rT6mTMmscqx4qz0EDJ1wjB+A36k7rl8mA== dependencies: - "@vue/reactivity" "3.4.33" - "@vue/shared" "3.4.33" + "@vue/reactivity" "3.5.10" + "@vue/shared" "3.5.10" -"@vue/runtime-dom@3.4.33": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.4.33.tgz#1a36e05478fd24c718f9c5ea9f4bac7d0481c779" - integrity sha512-iHsMCUSFJ+4z432Bn9kZzHX+zOXa6+iw36DaVRmKYZpPt9jW9riF32SxNwB124i61kp9+AZtheQ/mKoJLerAaQ== +"@vue/runtime-dom@3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.10.tgz#dca26d7761147373c6929f1370cf2733aa19f3de" + integrity sha512-t3x7ht5qF8ZRi1H4fZqFzyY2j+GTMTDxRheT+i8M9Ph0oepUxoadmbwlFwMoW7RYCpNQLpP2Yx3feKs+fyBdpA== dependencies: - "@vue/reactivity" "3.4.33" - "@vue/runtime-core" "3.4.33" - "@vue/shared" "3.4.33" + "@vue/reactivity" "3.5.10" + "@vue/runtime-core" "3.5.10" + "@vue/shared" "3.5.10" csstype "^3.1.3" -"@vue/server-renderer@3.4.33": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.4.33.tgz#b0c4981b2d7758356811fc9d7314a576de2a6d25" - integrity sha512-jTH0d6gQcaYideFP/k0WdEu8PpRS9MF8d0b6SfZzNi+ap972pZ0TNIeTaESwdOtdY0XPVj54XEJ6K0wXxir4fw== +"@vue/server-renderer@3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.10.tgz#90462492c30c8cae499b9149d1b90af2ebfe7599" + integrity sha512-IVE97tt2kGKwHNq9yVO0xdh1IvYfZCShvDSy46JIh5OQxP1/EXSpoDqetVmyIzL7CYOWnnmMkVqd7YK2QSWkdw== dependencies: - "@vue/compiler-ssr" "3.4.33" - "@vue/shared" "3.4.33" + "@vue/compiler-ssr" "3.5.10" + "@vue/shared" "3.5.10" "@vue/shared@3.4.33", "@vue/shared@^3.4.0": version "3.4.33" resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.4.33.tgz#2c4f2cfa988bb81e05372f6de556b254ff13e92a" integrity sha512-aoRY0jQk3A/cuvdkodTrM4NMfxco8n55eG4H7ML/CRy7OryHfiqvug4xrCBBMbbN+dvXAetDDwZW9DXWWjBntA== +"@vue/shared@3.5.10": + version "3.5.10" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.10.tgz#066f7dde31e09d700123e92e63eaa126cda21a17" + integrity sha512-VkkBhU97Ki+XJ0xvl4C9YJsIZ2uIlQ7HqPpZOS3m9VCvmROPaChZU6DexdMJqvz9tbgG+4EtFVrSuailUq5KGQ== + "@vue/tsconfig@^0.5.1": version "0.5.1" resolved "https://registry.yarnpkg.com/@vue/tsconfig/-/tsconfig-0.5.1.tgz#3124ec16cc0c7e04165b88dc091e6b97782fffa9" @@ -2037,12 +2087,12 @@ magic-string@0.30.8: dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" -magic-string@^0.30.10: - version "0.30.10" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.10.tgz#123d9c41a0cb5640c892b041d4cfb3bd0aa4b39e" - integrity sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ== +magic-string@^0.30.11: + version "0.30.11" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.11.tgz#301a6f93b3e8c2cb13ac1a7a673492c0dfd12954" + integrity sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A== dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" + "@jridgewell/sourcemap-codec" "^1.5.0" maplibre-gl@^4.5.2: version "4.5.2" @@ -2295,7 +2345,7 @@ pbf@^3.2.1, pbf@^3.3.0: ieee754 "^1.1.12" resolve-protobuf-schema "^2.1.0" -picocolors@^1.0.0: +picocolors@^1.0.0, picocolors@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== @@ -2340,6 +2390,15 @@ postcss@^8.4.39: picocolors "^1.0.1" source-map-js "^1.2.0" +postcss@^8.4.47: + version "8.4.47" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" + integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== + dependencies: + nanoid "^3.3.7" + picocolors "^1.1.0" + source-map-js "^1.2.1" + potpack@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/potpack/-/potpack-2.0.0.tgz#61f4dd2dc4b3d5e996e3698c0ec9426d0e169104" @@ -2551,6 +2610,11 @@ sort-object@^3.0.3: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + split-string@^3.0.1: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -2804,16 +2868,16 @@ vue-tsc@^2.0.21: "@vue/language-core" "2.0.28" semver "^7.5.4" -vue@^3.4.29: - version "3.4.33" - resolved "https://registry.yarnpkg.com/vue/-/vue-3.4.33.tgz#42a186220c96b93143076871d0c7d7bc46540e4a" - integrity sha512-VdMCWQOummbhctl4QFMcW6eNtXHsFyDlX60O/tsSQuCcuDOnJ1qPOhhVla65Niece7xq/P2zyZReIO5mP+LGTQ== +vue@^3.5.10: + version "3.5.10" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.10.tgz#14be9d4655e07be8d5e8295d017815ed14337f96" + integrity sha512-Vy2kmJwHPlouC/tSnIgXVg03SG+9wSqT1xu1Vehc+ChsXsRd7jLkKgMltVEFOzUdBr3uFwBCG+41LJtfAcBRng== dependencies: - "@vue/compiler-dom" "3.4.33" - "@vue/compiler-sfc" "3.4.33" - "@vue/runtime-dom" "3.4.33" - "@vue/server-renderer" "3.4.33" - "@vue/shared" "3.4.33" + "@vue/compiler-dom" "3.5.10" + "@vue/compiler-sfc" "3.5.10" + "@vue/runtime-dom" "3.5.10" + "@vue/server-renderer" "3.5.10" + "@vue/shared" "3.5.10" vuetify@^3.7.0: version "3.7.0"