Files
Netcatty/domain/systemManager/dockerImageIcons.ts
陈大猫 36267717ac feat(terminal): add system manager side panel for processes, tmux, and Docker
Introduce workspace-aware System side panel with remote process/tmux/Docker management, terminal popup for interactive attach, capability warmup, review-hardened IPC, performance optimizations, toast action errors, and SSH channel recovery on reconnect.
2026-06-11 04:19:21 +08:00

608 lines
24 KiB
TypeScript

import { BUNDLED_DOCKER_ICON_IDS, DOCKER_ICON_FILES } from './dockerIconBundled';
const IMAGE_ICON_RULES: Array<{ pattern: RegExp; icon: string }> = [
// Service discovery / mesh (specific first)
{ pattern: /nacos/i, icon: 'nacos' },
{ pattern: /polaris/i, icon: 'polaris' },
{ pattern: /mosquitto/i, icon: 'mosquitto' },
{ pattern: /kong/i, icon: 'kong' },
{ pattern: /istio/i, icon: 'istio' },
{ pattern: /linkerd/i, icon: 'linkerd' },
{ pattern: /cilium/i, icon: 'cilium' },
{ pattern: /envoy/i, icon: 'envoy' },
// Orchestration / IaC
{ pattern: /kubernetes|k8s/i, icon: 'kubernetes' },
{ pattern: /k3s/i, icon: 'k3s' },
{ pattern: /helm/i, icon: 'helm' },
{ pattern: /rancher/i, icon: 'rancher' },
{ pattern: /argo-?cd|argocd/i, icon: 'argo' },
{ pattern: /nomad/i, icon: 'nomad' },
{ pattern: /terraform/i, icon: 'terraform' },
{ pattern: /ansible/i, icon: 'ansible' },
{ pattern: /pulumi/i, icon: 'pulumi' },
{ pattern: /packer/i, icon: 'packer' },
{ pattern: /containerd/i, icon: 'containerd' },
{ pattern: /podman/i, icon: 'podman' },
// Web / proxy
{ pattern: /nginx/i, icon: 'nginx' },
{ pattern: /traefik/i, icon: 'traefik' },
{ pattern: /caddy/i, icon: 'caddy' },
{ pattern: /apache|httpd/i, icon: 'apache' },
{ pattern: /tomcat/i, icon: 'tomcat' },
{ pattern: /wordpress/i, icon: 'wordpress' },
{ pattern: /ghost/i, icon: 'ghost' },
{ pattern: /drupal/i, icon: 'drupal' },
// Language runtimes
{ pattern: /golang|^go$|^go[-:]/i, icon: 'golang' },
{ pattern: /node|nodedotjs/i, icon: 'nodejs' },
{ pattern: /python/i, icon: 'python' },
{ pattern: /temurin|corretto|azul|openjdk|\bjava(?!script)\b/i, icon: 'openjdk' },
{ pattern: /springboot|spring-boot|spring/i, icon: 'springboot' },
{ pattern: /rust/i, icon: 'rust' },
{ pattern: /deno/i, icon: 'deno' },
{ pattern: /php(?!myadmin)/i, icon: 'php' },
{ pattern: /ruby/i, icon: 'ruby' },
// Databases
{ pattern: /postgres|postgresql/i, icon: 'postgresql' },
{ pattern: /mariadb|galera|percona/i, icon: 'mariadb' },
{ pattern: /mysql/i, icon: 'mysql' },
{ pattern: /mongo/i, icon: 'mongodb' },
{ pattern: /valkey/i, icon: 'valkey' },
{ pattern: /dragonfly/i, icon: 'dragonfly' },
{ pattern: /redis/i, icon: 'redis' },
{ pattern: /memcached/i, icon: 'memcached' },
{ pattern: /clickhouse/i, icon: 'clickhouse' },
{ pattern: /cockroach/i, icon: 'cockroachdb' },
{ pattern: /neo4j/i, icon: 'neo4j' },
{ pattern: /cassandra/i, icon: 'cassandra' },
{ pattern: /couchdb/i, icon: 'couchdb' },
{ pattern: /couchbase/i, icon: 'couchbase' },
{ pattern: /arangodb/i, icon: 'arangodb' },
{ pattern: /tidb/i, icon: 'tidb' },
{ pattern: /vitess/i, icon: 'vitess' },
{ pattern: /duckdb/i, icon: 'duckdb' },
{ pattern: /scylla/i, icon: 'scylladb' },
{ pattern: /singlestore/i, icon: 'singlestore' },
{ pattern: /trino/i, icon: 'trino' },
{ pattern: /presto/i, icon: 'presto' },
{ pattern: /influx/i, icon: 'influxdb' },
{ pattern: /timescale/i, icon: 'timescaledb' },
{ pattern: /snowflake/i, icon: 'snowflake' },
{ pattern: /databricks/i, icon: 'databricks' },
// Messaging / streaming
{ pattern: /rabbitmq/i, icon: 'rabbitmq' },
{ pattern: /kafka/i, icon: 'kafka' },
{ pattern: /pulsar/i, icon: 'pulsar' },
{ pattern: /rocketmq/i, icon: 'rocketmq' },
{ pattern: /nats/i, icon: 'nats' },
{ pattern: /emqx/i, icon: 'emqx' },
{ pattern: /hivemq/i, icon: 'hivemq' },
{ pattern: /flink/i, icon: 'flink' },
{ pattern: /nifi/i, icon: 'nifi' },
{ pattern: /temporal/i, icon: 'temporal' },
// Search / analytics
{ pattern: /opensearch/i, icon: 'opensearch' },
{ pattern: /elasticsearch/i, icon: 'elasticsearch' },
{ pattern: /meilisearch/i, icon: 'meilisearch' },
{ pattern: /kibana/i, icon: 'kibana' },
{ pattern: /logstash/i, icon: 'logstash' },
{ pattern: /solr/i, icon: 'solr' },
{ pattern: /druid/i, icon: 'druid' },
{ pattern: /hadoop/i, icon: 'hadoop' },
{ pattern: /hbase/i, icon: 'hbase' },
{ pattern: /hive(?!mq)/i, icon: 'hive' },
// Observability
{ pattern: /grafana/i, icon: 'grafana' },
{ pattern: /prometheus/i, icon: 'prometheus' },
{ pattern: /victoria(?:metrics)?|vmagent|vmalert/i, icon: 'victoriametrics' },
{ pattern: /thanos/i, icon: 'thanos' },
{ pattern: /jaeger/i, icon: 'jaeger' },
{ pattern: /opentelemetry|otel/i, icon: 'opentelemetry' },
{ pattern: /fluent-?bit/i, icon: 'fluentbit' },
{ pattern: /fluentd/i, icon: 'fluentd' },
{ pattern: /sentry/i, icon: 'sentry' },
{ pattern: /datadog/i, icon: 'datadog' },
{ pattern: /netdata/i, icon: 'netdata' },
{ pattern: /icinga/i, icon: 'icinga' },
{ pattern: /sonarqube/i, icon: 'sonarqube' },
// AI / ML
{ pattern: /ollama/i, icon: 'ollama' },
{ pattern: /milvus/i, icon: 'milvus' },
{ pattern: /qdrant/i, icon: 'qdrant' },
{ pattern: /pytorch/i, icon: 'pytorch' },
{ pattern: /tensorflow/i, icon: 'tensorflow' },
// Infra / secrets
{ pattern: /vaultwarden/i, icon: 'vaultwarden' },
{ pattern: /vault/i, icon: 'vault' },
{ pattern: /consul/i, icon: 'consul' },
{ pattern: /etcd/i, icon: 'etcd' },
{ pattern: /zookeeper|zoo-?keeper/i, icon: 'zookeeper' },
{ pattern: /portainer/i, icon: 'portainer' },
{ pattern: /harbor/i, icon: 'harbor' },
{ pattern: /jfrog|artifactory|nexus/i, icon: 'jfrog' },
{ pattern: /keycloak/i, icon: 'keycloak' },
{ pattern: /authelia/i, icon: 'authelia' },
{ pattern: /authentik/i, icon: 'authentik' },
{ pattern: /tailscale/i, icon: 'tailscale' },
{ pattern: /wireguard/i, icon: 'wireguard' },
{ pattern: /cloudflare/i, icon: 'cloudflare' },
// CI/CD & dev tools
{ pattern: /jenkins/i, icon: 'jenkins' },
{ pattern: /gitlab/i, icon: 'gitlab' },
{ pattern: /gitea/i, icon: 'gitea' },
{ pattern: /forgejo/i, icon: 'forgejo' },
{ pattern: /github/i, icon: 'github' },
{ pattern: /drone/i, icon: 'drone' },
{ pattern: /circleci/i, icon: 'circleci' },
{ pattern: /buildkite/i, icon: 'buildkite' },
{ pattern: /airflow/i, icon: 'airflow' },
{ pattern: /prefect/i, icon: 'prefect' },
{ pattern: /spark/i, icon: 'spark' },
// Apps / CMS / collaboration
{ pattern: /supabase/i, icon: 'supabase' },
{ pattern: /strapi/i, icon: 'strapi' },
{ pattern: /directus/i, icon: 'directus' },
{ pattern: /hasura/i, icon: 'hasura' },
{ pattern: /pocketbase/i, icon: 'pocketbase' },
{ pattern: /appwrite/i, icon: 'appwrite' },
{ pattern: /mattermost/i, icon: 'mattermost' },
{ pattern: /jitsi/i, icon: 'jitsi' },
{ pattern: /matrix|synapse|element/i, icon: 'matrix' },
{ pattern: /metabase/i, icon: 'metabase' },
{ pattern: /superset/i, icon: 'superset' },
{ pattern: /airbyte/i, icon: 'airbyte' },
{ pattern: /bookstack/i, icon: 'bookstack' },
{ pattern: /jira/i, icon: 'jira' },
{ pattern: /confluence/i, icon: 'confluence' },
{ pattern: /bitwarden/i, icon: 'bitwarden' },
{ pattern: /listmonk/i, icon: 'listmonk' },
{ pattern: /mautic/i, icon: 'mautic' },
{ pattern: /adminer/i, icon: 'adminer' },
{ pattern: /phpmyadmin/i, icon: 'phpmyadmin' },
// Storage / media / smart home
{ pattern: /minio/i, icon: 'minio' },
{ pattern: /nextcloud/i, icon: 'nextcloud' },
{ pattern: /homeassistant|home-assistant/i, icon: 'homeassistant' },
{ pattern: /homebridge/i, icon: 'homebridge' },
{ pattern: /nodered|node-red/i, icon: 'nodered' },
{ pattern: /esphome/i, icon: 'esphome' },
{ pattern: /tasmota/i, icon: 'tasmota' },
{ pattern: /immich/i, icon: 'immich' },
{ pattern: /jellyfin/i, icon: 'jellyfin' },
{ pattern: /plex/i, icon: 'plex' },
{ pattern: /emby/i, icon: 'emby' },
{ pattern: /sonarr/i, icon: 'sonarr' },
{ pattern: /radarr/i, icon: 'radarr' },
// Docker engine (before generic base images)
{ pattern: /^docker$|docker\/|dind/i, icon: 'docker' },
// Base images (broad — match last)
{ pattern: /alpine/i, icon: 'alpine' },
{ pattern: /ubuntu/i, icon: 'ubuntu' },
{ pattern: /debian/i, icon: 'debian' },
{ pattern: /centos/i, icon: 'centos' },
{ pattern: /fedora/i, icon: 'fedora' },
{ pattern: /rocky/i, icon: 'rockylinux' },
{ pattern: /alma/i, icon: 'almalinux' },
{ pattern: /redhat|red-hat|rhel/i, icon: 'redhat' },
{ pattern: /archlinux|arch-linux/i, icon: 'archlinux' },
{ pattern: /opensuse|suse/i, icon: 'opensuse' },
{ pattern: /gentoo/i, icon: 'gentoo' },
];
/** Local asset base — files live in public/docker-icons/ (see scripts/sync-docker-icons.mjs) */
const DOCKER_ICON_BASE = '/docker-icons';
/** Internal icon id → Simple Icons slug (https://simpleicons.org/) */
/** Only official Simple Icons slugs — no cross-brand substitutes. */
/** Parsed at build/sync time by scripts/sync-docker-icons.mjs (not referenced at runtime). */
// eslint-disable-next-line unused-imports/no-unused-vars -- consumed by scripts/sync-docker-icons.mjs
const SIMPLE_ICONS_SLUG: Record<string, string> = {
container: 'docker',
mosquitto: 'eclipsemosquitto',
kong: 'kong',
istio: 'istio',
linkerd: 'linkerd',
cilium: 'cilium',
envoy: 'envoyproxy',
kubernetes: 'kubernetes',
k3s: 'k3s',
helm: 'helm',
rancher: 'rancher',
argo: 'argo',
nomad: 'nomad',
terraform: 'terraform',
ansible: 'ansible',
pulumi: 'pulumi',
packer: 'packer',
containerd: 'containerd',
podman: 'podman',
nginx: 'nginx',
traefik: 'traefikproxy',
caddy: 'caddy',
apache: 'apache',
tomcat: 'apachetomcat',
wordpress: 'wordpress',
ghost: 'ghost',
drupal: 'drupal',
golang: 'go',
nodejs: 'nodedotjs',
python: 'python',
openjdk: 'openjdk',
springboot: 'springboot',
rust: 'rust',
deno: 'deno',
php: 'php',
ruby: 'ruby',
postgresql: 'postgresql',
mariadb: 'mariadb',
mysql: 'mysql',
mongodb: 'mongodb',
redis: 'redis',
clickhouse: 'clickhouse',
cockroachdb: 'cockroachlabs',
neo4j: 'neo4j',
cassandra: 'apachecassandra',
couchdb: 'apachecouchdb',
couchbase: 'couchbase',
arangodb: 'arangodb',
tidb: 'tidb',
vitess: 'vitess',
duckdb: 'duckdb',
scylladb: 'scylladb',
singlestore: 'singlestore',
trino: 'trino',
presto: 'presto',
influxdb: 'influxdb',
timescaledb: 'timescale',
snowflake: 'snowflake',
databricks: 'databricks',
rabbitmq: 'rabbitmq',
kafka: 'apachekafka',
pulsar: 'apachepulsar',
rocketmq: 'apacherocketmq',
nats: 'natsdotio',
hivemq: 'hivemq',
flink: 'apacheflink',
nifi: 'apachenifi',
temporal: 'temporal',
opensearch: 'opensearch',
elasticsearch: 'elasticsearch',
meilisearch: 'meilisearch',
kibana: 'kibana',
logstash: 'logstash',
solr: 'apachesolr',
druid: 'apachedruid',
hadoop: 'apachehadoop',
hbase: 'apachehbase',
hive: 'apachehive',
grafana: 'grafana',
prometheus: 'prometheus',
victoriametrics: 'victoriametrics',
thanos: 'thanos',
jaeger: 'jaeger',
opentelemetry: 'opentelemetry',
fluentbit: 'fluentbit',
fluentd: 'fluentd',
sentry: 'sentry',
datadog: 'datadog',
netdata: 'netdata',
icinga: 'icinga',
sonarqube: 'sonarqubeserver',
ollama: 'ollama',
milvus: 'milvus',
qdrant: 'qdrant',
pytorch: 'pytorch',
tensorflow: 'tensorflow',
vaultwarden: 'vaultwarden',
vault: 'vault',
consul: 'consul',
etcd: 'etcd',
portainer: 'portainer',
harbor: 'harbor',
jfrog: 'jfrog',
keycloak: 'keycloak',
authelia: 'authelia',
authentik: 'authentik',
tailscale: 'tailscale',
wireguard: 'wireguard',
cloudflare: 'cloudflare',
jenkins: 'jenkins',
gitlab: 'gitlab',
gitea: 'gitea',
forgejo: 'forgejo',
github: 'github',
drone: 'drone',
circleci: 'circleci',
buildkite: 'buildkite',
airflow: 'apacheairflow',
prefect: 'prefect',
spark: 'apachespark',
supabase: 'supabase',
strapi: 'strapi',
directus: 'directus',
hasura: 'hasura',
pocketbase: 'pocketbase',
appwrite: 'appwrite',
mattermost: 'mattermost',
jitsi: 'jitsi',
matrix: 'matrix',
metabase: 'metabase',
superset: 'apachesuperset',
airbyte: 'airbyte',
bookstack: 'bookstack',
jira: 'jira',
confluence: 'confluence',
bitwarden: 'bitwarden',
listmonk: 'listmonk',
mautic: 'mautic',
adminer: 'adminer',
phpmyadmin: 'phpmyadmin',
minio: 'minio',
nextcloud: 'nextcloud',
homeassistant: 'homeassistant',
homebridge: 'homebridge',
nodered: 'nodered',
esphome: 'esphome',
tasmota: 'tasmota',
immich: 'immich',
jellyfin: 'jellyfin',
plex: 'plex',
emby: 'emby',
sonarr: 'sonarr',
radarr: 'radarr',
docker: 'docker',
alpine: 'alpinelinux',
ubuntu: 'ubuntu',
debian: 'debian',
centos: 'centos',
fedora: 'fedora',
rockylinux: 'rockylinux',
almalinux: 'almalinux',
redhat: 'redhat',
archlinux: 'archlinux',
opensuse: 'opensuse',
gentoo: 'gentoo',
};
export interface DockerIconTileStyle {
/** Tile background (brand primary) */
background: string;
/** Logo fill baked into the local SVG — chosen for contrast on `background` */
iconColor: string;
}
/**
* Per-brand tile: brand-colored background + logo color that stays readable.
* Dark tiles → white/light logos; light tiles → dark logos.
*/
const ICON_TILE_STYLE: Record<string, DockerIconTileStyle> = {
container: { background: '#2496ED', iconColor: 'ffffff' },
nacos: { background: '#FF6A00', iconColor: 'ffffff' },
polaris: { background: '#006EFF', iconColor: 'ffffff' },
mosquitto: { background: '#3C5280', iconColor: 'ffffff' },
kong: { background: '#003459', iconColor: 'ffffff' },
istio: { background: '#466BB0', iconColor: 'ffffff' },
linkerd: { background: '#2BEDA7', iconColor: '000000' },
cilium: { background: '#F8C517', iconColor: '000000' },
envoy: { background: '#AC6199', iconColor: 'ffffff' },
kubernetes: { background: '#326CE5', iconColor: 'ffffff' },
k3s: { background: '#FFC61C', iconColor: '000000' },
helm: { background: '#0F1689', iconColor: 'ffffff' },
rancher: { background: '#0075A8', iconColor: 'ffffff' },
argo: { background: '#EF7B4D', iconColor: 'ffffff' },
nomad: { background: '#00CA8E', iconColor: '000000' },
terraform: { background: '#844FBA', iconColor: 'ffffff' },
ansible: { background: '#EE0000', iconColor: 'ffffff' },
pulumi: { background: '#8A3391', iconColor: 'ffffff' },
packer: { background: '#02A8EF', iconColor: 'ffffff' },
containerd: { background: '#575757', iconColor: 'ffffff' },
podman: { background: '#892CA0', iconColor: 'ffffff' },
nginx: { background: '#009639', iconColor: 'ffffff' },
traefik: { background: '#24A1C1', iconColor: 'ffffff' },
caddy: { background: '#1F88C0', iconColor: 'ffffff' },
apache: { background: '#D22128', iconColor: 'ffffff' },
tomcat: { background: '#30261C', iconColor: 'F8DC75' },
wordpress: { background: '#21759B', iconColor: 'ffffff' },
ghost: { background: '#15171A', iconColor: 'ffffff' },
drupal: { background: '#0678BE', iconColor: 'ffffff' },
golang: { background: '#00ADD8', iconColor: 'ffffff' },
nodejs: { background: '#339933', iconColor: 'ffffff' },
python: { background: '#3776AB', iconColor: 'ffffff' },
openjdk: { background: '#437291', iconColor: 'ffffff' },
springboot: { background: '#6DB33F', iconColor: 'ffffff' },
rust: { background: '#000000', iconColor: 'ffffff' },
deno: { background: '#000000', iconColor: 'ffffff' },
php: { background: '#777BB4', iconColor: 'ffffff' },
ruby: { background: '#CC342D', iconColor: 'ffffff' },
postgresql: { background: '#4169E1', iconColor: 'ffffff' },
mariadb: { background: '#003545', iconColor: 'ffffff' },
mysql: { background: '#4479A1', iconColor: 'ffffff' },
mongodb: { background: '#47A248', iconColor: 'ffffff' },
valkey: { background: '#A41E34', iconColor: 'ffffff' },
dragonfly: { background: '#5B4B8A', iconColor: 'ffffff' },
redis: { background: '#DC382D', iconColor: 'ffffff' },
memcached: { background: '#00AA00', iconColor: 'ffffff' },
emqx: { background: '#5C4B9E', iconColor: 'ffffff' },
clickhouse: { background: '#FFCC01', iconColor: '000000' },
cockroachdb: { background: '#6933FF', iconColor: 'ffffff' },
neo4j: { background: '#4581C3', iconColor: 'ffffff' },
cassandra: { background: '#1287B1', iconColor: 'ffffff' },
couchdb: { background: '#E42528', iconColor: 'ffffff' },
couchbase: { background: '#EA2328', iconColor: 'ffffff' },
arangodb: { background: '#D12C2F', iconColor: 'ffffff' },
tidb: { background: '#E7008A', iconColor: 'ffffff' },
vitess: { background: '#F16728', iconColor: 'ffffff' },
duckdb: { background: '#FFF000', iconColor: '000000' },
scylladb: { background: '#6C2BD9', iconColor: 'ffffff' },
singlestore: { background: '#AA00FF', iconColor: 'ffffff' },
trino: { background: '#DD00A1', iconColor: 'ffffff' },
presto: { background: '#5890FF', iconColor: 'ffffff' },
influxdb: { background: '#22ADF6', iconColor: 'ffffff' },
timescaledb: { background: '#FDB515', iconColor: '000000' },
snowflake: { background: '#29B5E8', iconColor: 'ffffff' },
databricks: { background: '#FF3621', iconColor: 'ffffff' },
rabbitmq: { background: '#FF6600', iconColor: 'ffffff' },
kafka: { background: '#231F20', iconColor: 'ffffff' },
pulsar: { background: '#188FFF', iconColor: 'ffffff' },
rocketmq: { background: '#D77310', iconColor: 'ffffff' },
nats: { background: '#27AAE1', iconColor: 'ffffff' },
hivemq: { background: '#FFCD00', iconColor: '000000' },
flink: { background: '#E6526F', iconColor: 'ffffff' },
nifi: { background: '#728E9B', iconColor: 'ffffff' },
temporal: { background: '#000000', iconColor: 'ffffff' },
opensearch: { background: '#005EB8', iconColor: 'ffffff' },
elasticsearch: { background: '#005571', iconColor: 'ffffff' },
meilisearch: { background: '#FF5CAA', iconColor: 'ffffff' },
kibana: { background: '#005571', iconColor: 'ffffff' },
logstash: { background: '#005571', iconColor: 'ffffff' },
solr: { background: '#D9411E', iconColor: 'ffffff' },
druid: { background: '#29F1FB', iconColor: '000000' },
hadoop: { background: '#66CCFF', iconColor: '000000' },
hbase: { background: '#BE160F', iconColor: 'ffffff' },
hive: { background: '#FDEE21', iconColor: '000000' },
grafana: { background: '#F46800', iconColor: 'ffffff' },
prometheus: { background: '#E6522C', iconColor: 'ffffff' },
victoriametrics: { background: '#621773', iconColor: 'ffffff' },
thanos: { background: '#6D41FF', iconColor: 'ffffff' },
jaeger: { background: '#2D2D2D', iconColor: '60D0E4' },
opentelemetry: { background: '#000000', iconColor: 'ffffff' },
fluentbit: { background: '#49BDA5', iconColor: 'ffffff' },
fluentd: { background: '#0E83C8', iconColor: 'ffffff' },
sentry: { background: '#362D59', iconColor: 'ffffff' },
datadog: { background: '#632CA6', iconColor: 'ffffff' },
netdata: { background: '#00AB44', iconColor: 'ffffff' },
icinga: { background: '#060606', iconColor: 'ffffff' },
sonarqube: { background: '#4E9BCD', iconColor: 'ffffff' },
ollama: { background: '#000000', iconColor: 'ffffff' },
milvus: { background: '#00A1EA', iconColor: 'ffffff' },
qdrant: { background: '#DC244C', iconColor: 'ffffff' },
pytorch: { background: '#EE4C2C', iconColor: 'ffffff' },
tensorflow: { background: '#FF6F00', iconColor: 'ffffff' },
vaultwarden: { background: '#175DDC', iconColor: 'ffffff' },
vault: { background: '#1B1F23', iconColor: 'FFEC6E' },
consul: { background: '#F24C53', iconColor: 'ffffff' },
etcd: { background: '#419EDA', iconColor: 'ffffff' },
zookeeper: { background: '#56290C', iconColor: 'ffffff' },
portainer: { background: '#13BEF9', iconColor: 'ffffff' },
harbor: { background: '#60B932', iconColor: 'ffffff' },
jfrog: { background: '#40BE46', iconColor: 'ffffff' },
keycloak: { background: '#4D4D4D', iconColor: 'ffffff' },
authelia: { background: '#113155', iconColor: 'ffffff' },
authentik: { background: '#FD4B2D', iconColor: 'ffffff' },
tailscale: { background: '#242424', iconColor: 'ffffff' },
wireguard: { background: '#88171A', iconColor: 'ffffff' },
cloudflare: { background: '#F38020', iconColor: 'ffffff' },
jenkins: { background: '#D24939', iconColor: 'ffffff' },
gitlab: { background: '#FC6D26', iconColor: 'ffffff' },
gitea: { background: '#609926', iconColor: 'ffffff' },
forgejo: { background: '#FB923C', iconColor: '000000' },
github: { background: '#181717', iconColor: 'ffffff' },
drone: { background: '#212121', iconColor: 'ffffff' },
circleci: { background: '#343434', iconColor: 'ffffff' },
buildkite: { background: '#14B8A6', iconColor: 'ffffff' },
airflow: { background: '#017CEE', iconColor: 'ffffff' },
prefect: { background: '#070E10', iconColor: 'ffffff' },
spark: { background: '#E25A1C', iconColor: 'ffffff' },
supabase: { background: '#3FCF8E', iconColor: '000000' },
strapi: { background: '#4945FF', iconColor: 'ffffff' },
directus: { background: '#6644FF', iconColor: 'ffffff' },
hasura: { background: '#1EB4D4', iconColor: 'ffffff' },
pocketbase: { background: '#B8DBE4', iconColor: '000000' },
appwrite: { background: '#FD366E', iconColor: 'ffffff' },
mattermost: { background: '#0058CC', iconColor: 'ffffff' },
jitsi: { background: '#97979A', iconColor: 'ffffff' },
matrix: { background: '#000000', iconColor: 'ffffff' },
metabase: { background: '#509EE3', iconColor: 'ffffff' },
superset: { background: '#20A6C9', iconColor: 'ffffff' },
airbyte: { background: '#615EFF', iconColor: 'ffffff' },
bookstack: { background: '#0288D1', iconColor: 'ffffff' },
jira: { background: '#0052CC', iconColor: 'ffffff' },
confluence: { background: '#172B4D', iconColor: 'ffffff' },
bitwarden: { background: '#175DDC', iconColor: 'ffffff' },
listmonk: { background: '#0052CC', iconColor: 'ffffff' },
mautic: { background: '#4E5E9E', iconColor: 'ffffff' },
adminer: { background: '#34567C', iconColor: 'ffffff' },
phpmyadmin: { background: '#F29111', iconColor: 'ffffff' },
minio: { background: '#C72E49', iconColor: 'ffffff' },
nextcloud: { background: '#0082C9', iconColor: 'ffffff' },
homeassistant: { background: '#18BCF2', iconColor: 'ffffff' },
homebridge: { background: '#491F59', iconColor: 'ffffff' },
nodered: { background: '#8F0000', iconColor: 'ffffff' },
esphome: { background: '#000000', iconColor: 'ffffff' },
tasmota: { background: '#1A1A1A', iconColor: 'ffffff' },
immich: { background: '#4250AF', iconColor: 'ffffff' },
jellyfin: { background: '#00A4DC', iconColor: 'ffffff' },
plex: { background: '#EBAF00', iconColor: '000000' },
emby: { background: '#52B54B', iconColor: 'ffffff' },
sonarr: { background: '#35C5F4', iconColor: '000000' },
radarr: { background: '#FFCC00', iconColor: '000000' },
docker: { background: '#2496ED', iconColor: 'ffffff' },
alpine: { background: '#0D597F', iconColor: 'ffffff' },
ubuntu: { background: '#E95420', iconColor: 'ffffff' },
debian: { background: '#A81D33', iconColor: 'ffffff' },
centos: { background: '#262577', iconColor: 'ffffff' },
fedora: { background: '#294172', iconColor: 'ffffff' },
rockylinux: { background: '#10B981', iconColor: 'ffffff' },
almalinux: { background: '#0F4266', iconColor: 'ffffff' },
redhat: { background: '#EE0000', iconColor: 'ffffff' },
archlinux: { background: '#1793D1', iconColor: 'ffffff' },
opensuse: { background: '#73BA25', iconColor: 'ffffff' },
gentoo: { background: '#54487A', iconColor: 'ffffff' },
};
const DEFAULT_TILE_STYLE: DockerIconTileStyle = {
background: '#52525b',
iconColor: 'ffffff',
};
export function resolveDockerImageIcon(image: string): string {
const repo = (image || '').split(':')[0].split('/').pop() || '';
for (const rule of IMAGE_ICON_RULES) {
if (rule.pattern.test(repo) || rule.pattern.test(image)) {
return rule.icon;
}
}
return 'container';
}
export function dockerIconTileStyle(iconId: string): DockerIconTileStyle {
return ICON_TILE_STYLE[iconId] ?? DEFAULT_TILE_STYLE;
}
const CONTAINER_ICON_ID = 'container';
function dockerIconFileName(iconId: string): string {
return DOCKER_ICON_FILES[iconId] ?? `${iconId}.svg`;
}
/** Local bundled asset, or null when no official icon is available. */
export function dockerIconUrl(iconId: string): string | null {
if (!BUNDLED_DOCKER_ICON_IDS.has(iconId)) return null;
return `${DOCKER_ICON_BASE}/${encodeURIComponent(dockerIconFileName(iconId))}`;
}
export interface DockerIconPresentation {
/** Icon id used for tile color and logo */
displayIconId: string;
iconUrl: string;
/** True when showing the matched brand icon (not Docker fallback) */
isBrandIcon: boolean;
}
/** Official brand icon when bundled; otherwise Docker logo + Docker tile. */
export function resolveDockerIconPresentation(
iconId: string,
options?: { imageFailed?: boolean },
): DockerIconPresentation {
const useBrand =
!options?.imageFailed &&
iconId !== CONTAINER_ICON_ID &&
BUNDLED_DOCKER_ICON_IDS.has(iconId);
const displayIconId = useBrand ? iconId : CONTAINER_ICON_ID;
return {
displayIconId,
iconUrl: `${DOCKER_ICON_BASE}/${encodeURIComponent(dockerIconFileName(displayIconId))}`,
isBrandIcon: useBrand,
};
}