12 Commits

Author SHA1 Message Date
gitea-actions
e0ab5b5961 chore: bump version to v0.1.27
All checks were successful
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 20s
2026-04-08 09:29:45 +00:00
Matthieu
560734d72c Revert "fix : resolve Docker port conflicts and fix var/ permissions on install"
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
This reverts commit 123d9b306f.
2026-04-08 11:29:38 +02:00
gitea-actions
18589823f3 chore: bump version to v0.1.26
All checks were successful
Auto Tag Develop / tag (push) Successful in 5s
Build & Push Docker Image / build (push) Successful in 35s
2026-04-08 09:28:03 +00:00
Matthieu
ab2b3fd9ef feat : display container port mappings in environment health
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Extract exposed ports from docker inspect and show them as badges (hostPort:containerPort)
in the environment health section.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 11:27:46 +02:00
Matthieu
123d9b306f fix : resolve Docker port conflicts and fix var/ permissions on install
Port PG 5436→5437, port frontend 3003→3005 to avoid conflicts with Coltura.
Add fix-permissions target in Makefile to create var/cache and var/log as root before composer install.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 11:27:37 +02:00
gitea-actions
ca3445103d chore: bump version to v0.1.25
All checks were successful
Auto Tag Develop / tag (push) Successful in 5s
Build & Push Docker Image / build (push) Successful in 3m11s
2026-04-08 07:23:47 +00:00
18f3de1ba9 Merge remote-tracking branch 'origin/develop' into develop
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
2026-04-08 09:23:39 +02:00
52571c651f fix : install docker-compose plugin from GitHub instead of apt
docker-compose-plugin package is not in Debian default repos.
Download the binary directly from GitHub releases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 09:18:44 +02:00
gitea-actions
b9712643de chore: bump version to v0.1.24
Some checks failed
Auto Tag Develop / tag (push) Successful in 5s
Build & Push Docker Image / build (push) Failing after 12s
2026-04-08 07:11:01 +00:00
e954402959 fix : install docker-compose-plugin in prod Dockerfile
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Deploy scripts use `docker compose` (Compose V2 plugin) which is not
included in docker.io package.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 09:10:33 +02:00
gitea-actions
98d9032068 chore: bump version to v0.1.23
All checks were successful
Auto Tag Develop / tag (push) Successful in 5s
Build & Push Docker Image / build (push) Successful in 53s
2026-04-07 12:38:52 +00:00
5f6277d412 feat : update Malio UI + CLAUDE.md
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
2026-04-07 14:38:42 +02:00
12 changed files with 75 additions and 23 deletions

View File

@@ -31,6 +31,10 @@ frontend/services/dto/ # Types TypeScript
frontend/i18n/locales/ # Fichiers de traduction
```
## Composants UI
La librairie `@malio/layer-ui` fournit les composants de formulaire et d'action. La documentation complète des props, events et exemples d'utilisation se trouve dans `frontend/node_modules/@malio/layer-ui/COMPONENTS.md`. Toujours s'y référer avant d'utiliser un composant Malio.
## Commandes
```bash

View File

@@ -1,2 +1,2 @@
parameters:
app.version: '0.1.22'
app.version: '0.1.27'

View File

@@ -138,6 +138,7 @@
"uptime": "Uptime",
"cpu": "CPU",
"memory": "Memoire",
"ports": "Ports",
"noData": "Aucune donnee disponible"
},
"deploy": {

View File

@@ -7,7 +7,7 @@
"name": "nuxt-app",
"hasInstallScript": true,
"dependencies": {
"@malio/layer-ui": "^1.2.2",
"@malio/layer-ui": "^1.2.3",
"@nuxt/icon": "^2.2.1",
"@nuxtjs/i18n": "^10.2.3",
"@nuxtjs/tailwindcss": "^6.14.0",
@@ -1668,9 +1668,9 @@
"license": "MIT"
},
"node_modules/@malio/layer-ui": {
"version": "1.2.2",
"resolved": "https://gitea.malio.fr/api/packages/MALIO-DEV/npm/%40malio%2Flayer-ui/-/1.2.2/layer-ui-1.2.2.tgz",
"integrity": "sha512-nV4FL19rYSiXqMDTUlAtp6AYdj7YiwpHbf7/usiOPj7llpjHIC3GmcOX0X7oQeOMTtSU1aKL8k8wn1bhptrHYg==",
"version": "1.2.3",
"resolved": "https://gitea.malio.fr/api/packages/MALIO-DEV/npm/%40malio%2Flayer-ui/-/1.2.3/layer-ui-1.2.3.tgz",
"integrity": "sha512-5nRnBzRkXfs3PfKwKl6sH2ikrmSK7lTifcd0TX1QZP3rFRVRTgcT6mrsrpsbR9PwI27OeCNm0X6d0Ii92Rq7Yg==",
"dependencies": {
"@nuxt/icon": "^2.2.1",
"@nuxtjs/tailwindcss": "^6.14.0",

View File

@@ -11,7 +11,7 @@
"build:dist": "nuxt generate && rm -rf dist && cp -R .output/public dist"
},
"dependencies": {
"@malio/layer-ui": "^1.2.2",
"@malio/layer-ui": "^1.2.3",
"@nuxt/icon": "^2.2.1",
"@nuxtjs/i18n": "^10.2.3",
"@nuxtjs/tailwindcss": "^6.14.0",

View File

@@ -427,7 +427,7 @@ onMounted(loadApplication)
<!-- Health metrics -->
<div v-if="healthByEnvId[env.id!]" class="mt-4 border-t border-neutral-200 py-3">
<p class="text-sm font-bold uppercase tracking-wider mb-2">{{ t('environments.health.title') }}</p>
<div class="grid grid-cols-2 sm:grid-cols-5 gap-3">
<div class="grid grid-cols-2 sm:grid-cols-6 gap-3">
<div>
<p class="text-xs text-neutral-400">{{ t('environments.health.status') }}</p>
<span
@@ -456,6 +456,19 @@ onMounted(loadApplication)
<span class="text-neutral-400">({{ healthByEnvId[env.id!].memoryPercent }}%)</span>
</p>
</div>
<div>
<p class="text-xs text-neutral-400">{{ t('environments.health.ports') }}</p>
<div v-if="healthByEnvId[env.id!].ports?.length" class="mt-1 flex flex-wrap gap-1">
<span
v-for="(p, i) in healthByEnvId[env.id!].ports"
:key="i"
class="inline-block rounded bg-neutral-100 px-2 py-0.5 text-xs font-mono text-neutral-700"
>
{{ p.hostPort }}:{{ p.containerPort }}
</span>
</div>
<p v-else class="text-sm text-neutral-400 mt-1">-</p>
</div>
</div>
</div>
<div class="flex justify-center gap-4 mt-4">

View File

@@ -20,18 +20,12 @@
v-model="username"
/>
<div>
<label class="text-sm font-semibold text-neutral-700" for="password">
Mot de passe
</label>
<input
id="password"
v-model="password"
type="password"
autocomplete="current-password"
class="mt-2 w-full rounded-md border border-neutral-300 bg-white px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-secondary-500/20"
/>
</div>
<MalioInputPassword
v-model="password"
label="Mot de passe"
autocomplete="current-password"
inputClass="w-full"
/>
<MalioButton
label="Se connecter"

View File

@@ -16,6 +16,12 @@ type DashboardResponse = {
applications: DashboardApplication[]
}
type PortMapping = {
hostPort: string
containerPort: string
protocol: string
}
type EnvironmentHealth = {
status: string
version: string
@@ -24,4 +30,5 @@ type EnvironmentHealth = {
memoryUsage: string
memoryLimit: string
memoryPercent: number
ports: PortMapping[]
}

View File

@@ -40,10 +40,16 @@ FROM php:8.4-fpm AS production
RUN apt-get update && apt-get install -y \
libicu-dev libpq-dev libpng-dev libzip-dev libxml2-dev \
nginx supervisor docker.io \
nginx supervisor docker.io curl \
&& docker-php-ext-install -j$(nproc) intl pdo_pgsql zip gd opcache \
&& rm -rf /var/lib/apt/lists/*
# Install Docker Compose plugin
RUN DOCKER_COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep '"tag_name"' | sed 's/.*"v\(.*\)".*/\1/') \
&& mkdir -p /usr/local/lib/docker/cli-plugins \
&& curl -SL "https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64" -o /usr/local/lib/docker/cli-plugins/docker-compose \
&& chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
# PHP production config
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"

View File

@@ -26,4 +26,6 @@ final class EnvironmentHealth
public string $memoryUsage = '';
public string $memoryLimit = '';
public float $memoryPercent = 0.0;
/** @var list<array{hostPort: string, containerPort: string, protocol: string}> */
public array $ports = [];
}

View File

@@ -23,7 +23,7 @@ final class DockerService
}
/**
* @return array{status: string, image: string, version: string, startedAt: string}
* @return array{status: string, image: string, version: string, startedAt: string, ports: list<array{hostPort: string, containerPort: string, protocol: string}>}
*/
public function getContainerStatus(string $containerName): array
{
@@ -33,12 +33,13 @@ final class DockerService
'image' => '',
'version' => '',
'startedAt' => '',
'ports' => [],
];
}
$process = new Process([
'docker', 'inspect',
'--format', '{{.State.Status}}||{{.Config.Image}}||{{.State.StartedAt}}',
'--format', '{{.State.Status}}||{{.Config.Image}}||{{.State.StartedAt}}||{{json .NetworkSettings.Ports}}',
$containerName,
]);
$process->setTimeout(10);
@@ -50,10 +51,11 @@ final class DockerService
'image' => '',
'version' => '',
'startedAt' => '',
'ports' => [],
];
}
$parts = explode('||', trim($process->getOutput()));
$parts = explode('||', trim($process->getOutput()), 4);
if (\count($parts) < 3) {
return [
@@ -61,6 +63,7 @@ final class DockerService
'image' => '',
'version' => '',
'startedAt' => '',
'ports' => [],
];
}
@@ -70,11 +73,32 @@ final class DockerService
$version = substr($image, strrpos($image, ':') + 1);
}
$ports = [];
if (isset($parts[3])) {
$portsJson = json_decode($parts[3], true);
if (\is_array($portsJson)) {
foreach ($portsJson as $containerPort => $bindings) {
if (!\is_array($bindings)) {
continue;
}
[$port, $protocol] = explode('/', $containerPort) + [1 => 'tcp'];
foreach ($bindings as $binding) {
$ports[] = [
'hostPort' => $binding['HostPort'] ?? '',
'containerPort' => $port,
'protocol' => $protocol,
];
}
}
}
}
return [
'status' => $parts[0],
'image' => $image,
'version' => $version,
'startedAt' => $parts[2],
'ports' => $ports,
];
}

View File

@@ -39,6 +39,7 @@ final readonly class EnvironmentHealthProvider implements ProviderInterface
$dto->memoryUsage = $stats['memoryUsage'];
$dto->memoryLimit = $stats['memoryLimit'];
$dto->memoryPercent = $stats['memoryPercent'];
$dto->ports = $status['ports'];
return $dto;
}