Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa5dcc5fbc | ||
|
|
e1e9a19f78 | ||
|
|
240021b754 | ||
|
|
be323edf10 | ||
|
|
6cdb1858a2 | ||
|
|
7e6b08774b | ||
|
|
51b6691caa | ||
|
|
45dc53155b | ||
|
|
7abe9023f9 | ||
|
|
e7b00288ed | ||
|
|
d3bd5b20c2 | ||
|
|
3cb43f5149 | ||
|
|
26b6fd8938 | ||
|
|
965c456dee | ||
|
|
9ac56d671b | ||
|
|
f47baa553a | ||
|
|
1d5a136dff | ||
|
|
580827f7ca | ||
|
|
6f33c7277a | ||
|
|
6f1dfedde2 | ||
|
|
c0774b5f58 | ||
|
|
4fdad89fa6 | ||
|
|
80fcf6c227 | ||
|
|
f4995e5882 | ||
|
|
e21a895390 | ||
|
|
c51b68194a | ||
|
|
6b0261d66c |
@@ -5,6 +5,11 @@
|
||||
/lib
|
||||
node_modules
|
||||
/.npmrc
|
||||
# ThreadNet-Fork: unsere .npmrc IST versioniert. Sie bindet nur den Scope @sorb an
|
||||
# die Registry auf rohana und enthaelt kein Geheimnis (Lesezugriff ist anonym).
|
||||
# Ohne diese Ausnahme bliebe die Datei lokal, und CI wie frischer Klon loesten
|
||||
# @sorb weiter gegen npmjs auf - siehe management#0055.
|
||||
!/.npmrc
|
||||
/*.log
|
||||
package-lock.json
|
||||
.DS_Store
|
||||
|
||||
@@ -7,6 +7,44 @@
|
||||
# - webpack braucht ~4 GB Heap -> NODE_OPTIONS
|
||||
# - Desktop-Build laeuft im dockerbuild-Image (rust:bullseye + node, glibc-2.31-Ziel)
|
||||
|
||||
# --- Wann ueberhaupt eine Pipeline entsteht ------------------------------------
|
||||
# Ohne diesen Block erzeugt ein Commit, der nur docs/ anfasst, eine Pipeline mit
|
||||
# NULL Jobs - und die zaehlt in GitLab als "failed". Real passiert am 2026-08-06
|
||||
# (Pipelines 203 und 204): zwei Doku-Commits, zweimal rot, nichts kaputt.
|
||||
#
|
||||
# Der Grund liegt an der needs-Kette: web laeuft wegen changes: nicht, und
|
||||
# desktop_linux/desktop_windows haengen per needs daran - damit faellt die ganze
|
||||
# Pipeline in sich zusammen, auch die manuellen Jobs ohne needs.
|
||||
#
|
||||
# ⚠️ Warum das keine Kosmetik ist: In gitops/CLAUDE.md ist die rote Pipeline die
|
||||
# ALARMANLAGE fuer die TURN-Rotation ("es gibt keinen separaten Reminder"). Rot,
|
||||
# das nichts bedeutet, gewoehnt einem das Hinsehen ab.
|
||||
#
|
||||
# Preis: Nach einem reinen Doku-Commit entsteht keine Pipeline von selbst. Damit
|
||||
# die manuellen Wartungsjobs (desktop_image, windows_provision) trotzdem
|
||||
# erreichbar bleiben, laesst die Regel CI_PIPELINE_SOURCE == "web" durch - eine
|
||||
# ueber "Run pipeline" in der Oberflaeche gestartete Pipeline entsteht immer.
|
||||
.pfade_mit_pipeline: &pfade_mit_pipeline
|
||||
- apps/**/*
|
||||
- packages/**/*
|
||||
- patches/**/*
|
||||
- scripts/**/*
|
||||
- pnpm-lock.yaml
|
||||
- pnpm-workspace.yaml
|
||||
# .npmrc bindet den Scope @sorb an rohana. Aendert sich die Datei, aendert
|
||||
# sich, WOHER Abhaengigkeiten kommen - das gehoert gebaut, nicht durchgewunken.
|
||||
- .npmrc
|
||||
- .gitlab-ci.yml
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
- if: $CI_COMMIT_TAG =~ /^v/
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
- if: $CI_PIPELINE_SOURCE == "web"
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
changes: *pfade_mit_pipeline
|
||||
- when: never
|
||||
|
||||
stages:
|
||||
- build
|
||||
- package
|
||||
@@ -82,14 +120,8 @@ web:
|
||||
when: never
|
||||
# Pushes nur, wenn build-relevante Pfade betroffen sind - Doku-Commits kosten nichts
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
changes:
|
||||
- apps/**/*
|
||||
- packages/**/*
|
||||
- patches/**/*
|
||||
- scripts/**/*
|
||||
- pnpm-lock.yaml
|
||||
- pnpm-workspace.yaml
|
||||
- .gitlab-ci.yml
|
||||
# derselbe Anker wie im workflow-Block oben - zwei Listen wuerden driften
|
||||
changes: *pfade_mit_pipeline
|
||||
variables:
|
||||
NODE_OPTIONS: "--max-old-space-size=6144"
|
||||
CI_PACKAGE: "true"
|
||||
@@ -123,8 +155,31 @@ docker_web:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
script:
|
||||
- echo "$REGISTRY_PASSWORD" | docker login rohana.axion1337.de -u "$REGISTRY_USER" --password-stdin
|
||||
# Ein veroeffentlichtes Release darf sich nicht rueckwirkend aendern.
|
||||
#
|
||||
# Am 2026-08-09 hat das Force-Push umgezogener Tags (History-Anonymisierung)
|
||||
# drei Release-Pipelines neu gestartet - darunter v0.4.0. Ohne diese Sperre
|
||||
# haette der Lauf das laengst veroeffentlichte Image aus altem Code mit
|
||||
# heutigen Basis-Images und Abhaengigkeiten neu gebaut und ueberschrieben.
|
||||
# Dass es damals nicht passierte, lag nur daran, dass die geschuetzten
|
||||
# Registry-Variablen in dem Moment nicht verfuegbar waren - Glueck, nicht
|
||||
# Absicht (ThreadNet-Web#14).
|
||||
#
|
||||
# Ein Tag ist hier kein Verwaltungseintrag, sondern ein Build-Ausloeser. Wer
|
||||
# einen Tag verschiebt, loest einen Build aus, ob er will oder nicht. Deshalb
|
||||
# Unveraenderlichkeit erzwingen statt auf Vorsicht zu hoffen.
|
||||
- |
|
||||
if docker manifest inspect "$IMAGE:$CI_COMMIT_TAG" >/dev/null 2>&1; then
|
||||
echo "FEHLER: $IMAGE:$CI_COMMIT_TAG existiert in der Registry bereits."
|
||||
echo "Ein veroeffentlichtes Release wird nicht ueberschrieben."
|
||||
echo "Gewollt? Dann das Image bewusst aus der Registry entfernen oder eine"
|
||||
echo "neue Version taggen - siehe ThreadNet-Web#14."
|
||||
exit 1
|
||||
fi
|
||||
- docker build -f apps/web/Dockerfile -t "$IMAGE:$CI_COMMIT_TAG" -t "$IMAGE:latest-ci" .
|
||||
- docker push "$IMAGE:$CI_COMMIT_TAG"
|
||||
# latest-ci bleibt bewusst ueberschreibbar - der Tag bezeichnet "der neueste
|
||||
# Stand", nicht eine Version, und traegt deshalb kein Versprechen.
|
||||
- docker push "$IMAGE:latest-ci"
|
||||
|
||||
# Einmalig/selten: Build-Image fuer den Desktop-Build (rust:bullseye + node + tcl/sqlcipher,
|
||||
@@ -162,6 +217,10 @@ desktop_linux:
|
||||
MAX_GLIBC: "2.31"
|
||||
USE_HARD_LINKS: "false"
|
||||
SQLCIPHER_BUNDLED: "1"
|
||||
# Eigene Build-Variante: Produktname ThreadNet statt Element. Ohne das nutzt
|
||||
# electron-builder element.io/release/build.json und die Pakete heissen weiter
|
||||
# "element-desktop" (real passiert 2026-08-02).
|
||||
VARIANT_PATH: axion1337/build.json
|
||||
script:
|
||||
- pnpm install --frozen-lockfile --filter element-desktop
|
||||
- cp -r apps/web/webapp apps/desktop/webapp
|
||||
@@ -201,6 +260,8 @@ desktop_windows:
|
||||
SQLCIPHER_BUNDLED: "1"
|
||||
ELECTRON_CACHE: C:\electron-cache
|
||||
ELECTRON_BUILDER_CACHE: C:\eb-cache
|
||||
# Eigene Build-Variante (Produktname ThreadNet) - siehe desktop_linux
|
||||
VARIANT_PATH: axion1337/build.json
|
||||
script:
|
||||
- pnpm install --frozen-lockfile --filter element-desktop
|
||||
# GitHub-CDN-Downloads (Electron-Binary, winCodeSign, NSIS) reissen im Gast
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Der Scope @sorb liegt in der Gitea-Registry auf rohana, nicht auf npmjs.
|
||||
#
|
||||
# Ohne diese Zeile loest pnpm @sorb/threadnet-call-embedded gegen
|
||||
# registry.npmjs.org auf. Dass das bisher gutging, lag allein am Lockfile: es
|
||||
# pinnt die vollstaendige Tarball-URL, und die CI installiert mit
|
||||
# --frozen-lockfile. Beim ersten Anheben der Version faellt dieser Schutz weg.
|
||||
#
|
||||
# Heute endet das in einem 404, weil der Name auf npmjs frei ist. Genau darauf
|
||||
# darf man sich nicht verlassen: registriert dort jemand @sorb, loest derselbe
|
||||
# Befehl still gegen ein fremdes Paket auf (dependency confusion) - und zwar in
|
||||
# dem Moment, in dem ein neuer Download ohnehin erwartet wird.
|
||||
#
|
||||
# Kein Geheimnis in dieser Datei: der Lesezugriff auf die Registry ist anonym.
|
||||
# Siehe management#0055.
|
||||
@sorb:registry=https://rohana.axion1337.de/api/packages/sorb/npm/
|
||||
@@ -0,0 +1,33 @@
|
||||
# AGENTS.md — ThreadNet-Web
|
||||
|
||||
> **Die Gruppenregeln sind kanonisch im `management`-Repo:**
|
||||
> [`AGENTS.md`](https://git.lab/axion1337.chat/management/-/blob/main/AGENTS.md)
|
||||
> — von außerhalb des Labs über den Gitea-Mirror lesbar:
|
||||
> `https://rohana.axion1337.de/sorb/management`. Dort stehen Repo-Topologie und
|
||||
> Mirror-Regeln, das Kanban-Framework (Status-Labels, WIP-Limit 2, ADR-Pflicht),
|
||||
> Deploy-Übergabe und AAR-Verfahren, Secrets-Handhabung und die
|
||||
> Karpathy-Leitlinien. Sie gelten für **jede** Session in diesem Repo.
|
||||
> Hier steht nur, was zusätzlich für dieses Repository gilt.
|
||||
|
||||
## Was dieses Repo ist
|
||||
|
||||
Fork von **Element Web/Desktop** (Basis `1.12.17`) für axion1337.chat.
|
||||
|
||||
⚠️ **`README.md` und der Großteil von `docs/` sind unverändertes Upstream-Material** und
|
||||
beschreiben diesen Fork ausdrücklich **nicht**. Wer sich danach richtet, übersieht jede
|
||||
Anpassung.
|
||||
|
||||
## Der eine Ort, der zählt
|
||||
|
||||
**[`docs/axion1337-fork.md`](docs/axion1337-fork.md)** ist die vollständige Liste dessen, was
|
||||
dieser Fork gegenüber Upstream ändert — und zugleich die **Portier-Checkliste** für jedes
|
||||
Upstream-Upgrade: dort stehen die kritischen Dateien, an denen die Merge-Reibung entsteht.
|
||||
|
||||
**Jede Änderung am Fork gehört dort hinein.** Eine Anpassung, die nur im Code steht, geht beim
|
||||
nächsten Rebase verloren — genau dafür existiert die Datei.
|
||||
|
||||
## Bauen & Ausrollen
|
||||
|
||||
Image wird in die Registry auf `rohana.axion1337.de` publiziert; die laufende Version zieht der
|
||||
Cluster über den Tag im gitops-Repo (`apps/production/`). Ein Upgrade ist deshalb zweistufig:
|
||||
erst hier rebasen und bauen, dann dort den Tag anheben.
|
||||
@@ -0,0 +1 @@
|
||||
Read AGENTS.md — the canonical instruction file for this repository. All rules live there.
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"appId": "im.riot.app",
|
||||
"name": "threadnet-desktop",
|
||||
"productName": "ThreadNet",
|
||||
"description": "ThreadNet — powered by Element",
|
||||
"protocols": ["io.element.desktop", "element"],
|
||||
"mac.icon": "build/icon.icns",
|
||||
"dmg.badgeIcon": "build/icon.icns"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 315 KiB After Width: | Height: | Size: 395 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 395 KiB |
@@ -48,6 +48,8 @@ interface Variant extends Metadata {
|
||||
"appId": string;
|
||||
"linux.executableName"?: string;
|
||||
"linux.deb.name"?: string;
|
||||
"mac.icon"?: string;
|
||||
"dmg.badgeIcon"?: string;
|
||||
"protocols": string[];
|
||||
}
|
||||
|
||||
@@ -202,6 +204,31 @@ if (variant["linux.deb.name"]) {
|
||||
config.deb.fpm.push("--name", variant["linux.deb.name"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* ThreadNet-Fork: Icon-Pfade fuer macOS ueberschreibbar machen.
|
||||
*
|
||||
* Upstream setzt `mac.icon` auf das Icon-Composer-Bundle `build/icon.icon`
|
||||
* (macOS 26). Dessen Verarbeitung ruft `actool` auf, das es nur mit dem vollen
|
||||
* Xcode gibt (~10 GB, App-Store-Login) - mit blossen CommandLineTools scheitert
|
||||
* damit JEDER macOS-Build, nicht nur das DMG:
|
||||
*
|
||||
* ⨯ Failed to check actool version. Is Xcode 26 or higher installed?
|
||||
*
|
||||
* Ueber die Variante laesst sich stattdessen das klassische `.icns` waehlen.
|
||||
* Bewusst hier als Variantenoption statt als Aenderung an den Defaults oben:
|
||||
* So bleibt Upstreams Wert unberuehrt und ein Upstream-Merge erzeugt keinen
|
||||
* Konflikt an dieser Zeile.
|
||||
*
|
||||
* Preis: kein macOS-26-Icon-Rendering. Ohne Xcode gaebe es ohnehin keinen Build.
|
||||
*/
|
||||
if (variant["mac.icon"]) {
|
||||
config.mac.icon = variant["mac.icon"];
|
||||
}
|
||||
|
||||
if (variant["dmg.badgeIcon"]) {
|
||||
config.dmg.badgeIcon = variant["dmg.badgeIcon"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow specifying windows signing cert via env vars
|
||||
* @param {string} process.env.ED_SIGNTOOL_SUBJECT_NAME
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "element-desktop",
|
||||
"productName": "Element",
|
||||
"productName": "ThreadNet",
|
||||
"main": "lib/electron-main.js",
|
||||
"exports": "./lib/electron-main.js",
|
||||
"version": "1.12.17",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"disable_login_language_selector": false,
|
||||
"disable_3pid_login": false,
|
||||
"force_verification": false,
|
||||
"brand": "Element",
|
||||
"brand": "aXion1337.Chat",
|
||||
"integrations_ui_url": "https://scalar.vector.im/",
|
||||
"integrations_rest_url": "https://scalar.vector.im/api",
|
||||
"integrations_widgets_urls": [
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
"@babel/preset-react": "^7.12.10",
|
||||
"@babel/preset-typescript": "^7.12.7",
|
||||
"@casualbot/jest-sonar-reporter": "2.7.0",
|
||||
"@sorb/threadnet-call-embedded": "0.19.2-threadnet.5",
|
||||
"@sorb/threadnet-call-embedded": "0.19.2-threadnet.12",
|
||||
"@element-hq/element-web-playwright-common": "workspace:*",
|
||||
"@fetch-mock/jest": "^0.2.20",
|
||||
"@jest/globals": "^30.2.0",
|
||||
|
||||
@@ -10,3 +10,12 @@ Please see LICENSE files in the repository root for full details.
|
||||
.mx_HelpUserSettingsTab_accessTokenDetails {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
/* ThreadNet-Fork: Attribution unter den Versionsangaben. Zurueckhaltend
|
||||
gesetzt - sie soll auffindbar sein, nicht um Aufmerksamkeit konkurrieren
|
||||
mit der Version darueber, die Nutzer hier tatsaechlich suchen. */
|
||||
.mx_HelpUserSettingsTab_attribution {
|
||||
margin-top: var(--cpd-space-2x);
|
||||
color: var(--cpd-color-text-secondary);
|
||||
font: var(--cpd-font-body-sm-regular);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "Element",
|
||||
"short_name": "Element",
|
||||
"name": "ThreadNet",
|
||||
"short_name": "ThreadNet",
|
||||
"display": "standalone",
|
||||
"theme_color": "#76CFA6",
|
||||
"theme_color": "#ed4f4c",
|
||||
"start_url": "index.html",
|
||||
"icons": [
|
||||
{
|
||||
|
||||
|
After Width: | Height: | Size: 590 KiB |
|
Before Width: | Height: | Size: 596 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 395 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 829 B After Width: | Height: | Size: 901 B |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 54 KiB |
@@ -20,7 +20,11 @@ export const DEFAULTS: DeepReadonly<IConfigOptions> = {
|
||||
branding: {
|
||||
logo_link_url: "https://element.io",
|
||||
auth_header_logo_url: "themes/element/img/logos/element-logo.svg",
|
||||
welcome_background_url: "themes/element/img/backgrounds/lake.jpg",
|
||||
// ThreadNet-Fork: eigenes Titelbild statt Elements lake.jpg. Steht hier im
|
||||
// Default und nicht in element-values.yaml, weil die Bilddatei ohnehin nur
|
||||
// ueber einen Build in den Container kommt - eine zusaetzliche Config-Zeile
|
||||
// waere eine zweite Stelle, die mitwandern muesste.
|
||||
welcome_background_url: "themes/element/img/backgrounds/alpenglow.jpg",
|
||||
},
|
||||
help_url: "https://element.io/help",
|
||||
help_encryption_url: "https://element.io/help#encryption",
|
||||
@@ -44,9 +48,10 @@ export const DEFAULTS: DeepReadonly<IConfigOptions> = {
|
||||
// be preferred over their config.
|
||||
desktopBuilds: {
|
||||
available: true,
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
logo: require("../res/img/element-desktop-logo.svg").default,
|
||||
url: "https://element.io/get-started",
|
||||
// ThreadNet-Fork: eigene Marke und eigener Download-Pfad statt
|
||||
// element.io - wir liefern eigene Desktop-Builds aus.
|
||||
logo: "vector-icons/512.png",
|
||||
url: "https://git.lab/axion1337.chat/ThreadNet-Web/-/releases",
|
||||
},
|
||||
|
||||
feedback: {
|
||||
|
||||
@@ -32,8 +32,8 @@ export const ErrorView: React.FC<IProps> = ({ title, messages, footer, children
|
||||
<img
|
||||
className="mx_ErrorView_logo"
|
||||
height="160"
|
||||
src="themes/element/img/logos/element-app-logo.png"
|
||||
alt="Element"
|
||||
src="vector-icons/512.png"
|
||||
alt="ThreadNet"
|
||||
/>
|
||||
<div className="mx_ErrorView_container">
|
||||
<Heading size="md" weight="semibold">
|
||||
|
||||
@@ -106,34 +106,42 @@ export default class HelpUserSettingsTab extends React.Component<EmptyObject, IS
|
||||
<SettingsSubsection heading={_t("common|credits")}>
|
||||
<SettingsSubsectionText>
|
||||
<ul>
|
||||
{/* ThreadNet-Fork: eigenes Titelbild, deshalb eigene Danksagung.
|
||||
Bewusst OHNE _t(): der Schluessel credits|default_cover_photo
|
||||
steckt in 32 Sprachdateien, 31 davon nennen Elements Fotografen
|
||||
namentlich. Wuerden wir nur en/de anpassen, stuende in 29
|
||||
Sprachen eine falsche Attribution — und die uebrigen 29 koennen
|
||||
wir nicht pflegen, sie kommen aus Elements Uebersetzungsdienst.
|
||||
Ein Fotografenname und eine Lizenzbezeichnung werden ohnehin
|
||||
nicht uebersetzt. Der ungenutzte Schluessel bleibt in den
|
||||
Sprachdateien stehen — ihn aus 32 Dateien zu entfernen waere
|
||||
Laerm im naechsten Upstream-Merge. */}
|
||||
<li>
|
||||
{_t(
|
||||
"credits|default_cover_photo",
|
||||
{},
|
||||
{
|
||||
photo: (sub) => (
|
||||
<ExternalLink
|
||||
href="themes/element/img/backgrounds/lake.jpg"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
{sub}
|
||||
</ExternalLink>
|
||||
),
|
||||
author: (sub) => (
|
||||
<ExternalLink href="https://www.flickr.com/golan">{sub}</ExternalLink>
|
||||
),
|
||||
terms: (sub) => (
|
||||
<ExternalLink
|
||||
href="https://creativecommons.org/licenses/by-sa/4.0/"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
{sub}
|
||||
</ExternalLink>
|
||||
),
|
||||
},
|
||||
)}
|
||||
The{" "}
|
||||
<ExternalLink
|
||||
href="themes/element/img/backgrounds/alpenglow.jpg"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
default cover photo
|
||||
</ExternalLink>{" "}
|
||||
is by <ExternalLink href="https://unsplash.com/@heytowner">John Towner</ExternalLink> on{" "}
|
||||
<ExternalLink
|
||||
href="https://unsplash.com/photos/JgOeRuGD_Y4"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Unsplash
|
||||
</ExternalLink>
|
||||
, used under the{" "}
|
||||
<ExternalLink
|
||||
href="https://unsplash.com/license"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
Unsplash License
|
||||
</ExternalLink>
|
||||
.
|
||||
</li>
|
||||
<li>
|
||||
{_t(
|
||||
@@ -259,6 +267,15 @@ export default class HelpUserSettingsTab extends React.Component<EmptyObject, IS
|
||||
{cryptoVersion}
|
||||
<br />
|
||||
</CopyableText>
|
||||
{/* ThreadNet-Fork: Attribution an Element. Bewusst NICHT in
|
||||
getVersionTextToCopy — der Text dort geht in Fehlerberichte,
|
||||
dort ist die Herkunft des Forks nur Rauschen. Ebenso bewusst
|
||||
ohne _t(): ein Markenhinweis wird nicht übersetzt, und jeder
|
||||
zusätzliche i18n-Schlüssel ist Reibung beim Upstream-Merge. */}
|
||||
<div className="mx_HelpUserSettingsTab_attribution">
|
||||
ThreadNet — powered by{" "}
|
||||
<ExternalLink href="https://element.io">Element</ExternalLink>
|
||||
</div>
|
||||
{updateButton}
|
||||
</SettingsSubsectionText>
|
||||
</SettingsSubsection>
|
||||
|
||||
@@ -2,19 +2,20 @@
|
||||
<html lang="en" style="height: 100%;">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Element</title>
|
||||
<title>ThreadNet</title>
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="<%= require('../../res/vector-icons/120.png') %>">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="<%= require('../../res/vector-icons/144.png') %>">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="<%= require('../../res/vector-icons/152.png') %>">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="<%= require('../../res/vector-icons/180.png') %>">
|
||||
<link rel="icon" href="vector-icons/favicon.ico" sizes="any">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<link rel="icon" type="image/png" sizes="24x24" href="<%= require('../../res/vector-icons/24.png') %>">
|
||||
<link rel="icon" type="image/png" sizes="144x144" href="<%= require('../../res/vector-icons/144.png') %>">
|
||||
<link rel="icon" type="image/png" sizes="512x512" href="<%= require('../../res/vector-icons/512.png') %>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="apple-mobile-web-app-title" content="Element">
|
||||
<meta name="application-name" content="Element">
|
||||
<meta name="apple-mobile-web-app-title" content="ThreadNet">
|
||||
<meta name="application-name" content="ThreadNet">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta property="og:image" content="<%= og_image_url %>" />
|
||||
<meta http-equiv="Content-Security-Policy" content="
|
||||
|
||||
@@ -53,6 +53,112 @@ statt 755 committet (nicht ausführbar); (2) der `matrix-js-sdk#develop`-Git-Ref
|
||||
`pnpm-lock.yaml` war veraltet (fehlte `src/oidc/authorize.ts`, das `apps/web` importiert).
|
||||
Beide behoben.
|
||||
|
||||
## 4. Merge-Reibung: was ein Upstream-Update wirklich kostet
|
||||
|
||||
*Arbeitspaket 3 aus ThreadNet-Web#7. Gemessen am 2026-08-06, nicht geschätzt.*
|
||||
|
||||
### Die unangenehme Grundlage zuerst
|
||||
|
||||
**Dieses Repo enthält keine Upstream-Historie.** Am 2026-05-10 wurde ein kompletter
|
||||
Element-Web-Baum importiert — in `3da3635`, zusammen mit dem ersten eigenen Feature im
|
||||
selben Commit. Davor liegt nur ein `Initial commit` mit zwei Dateien.
|
||||
|
||||
⚠️ **Korrektur 2026-08-19: Der Import ist NICHT der Tag `v1.12.17`.** Gemessen nach
|
||||
Aufnahme von `upstream` als zweitem Remote (management #0099, Schritt 2):
|
||||
|
||||
- `git diff v1.12.17 3da3635` ergibt **783 Dateien, +17443/−10371** — weit mehr als
|
||||
unser damaliges Feature.
|
||||
- **115 Dateien existieren nur bei uns, 62 nur im Tag.** Darunter MVVM-Dateien wie
|
||||
`apps/web/src/viewmodels/room/timeline/event-tile/body/TextualBodyViewModel.tsx` und
|
||||
`packages/shared-components/src/core/roving/RovingTabIndex.tsx`: im Tag `v1.12.17`
|
||||
**nicht vorhanden**, in `v1.12.26` und in unserem Import **vorhanden**.
|
||||
- Der `CHANGELOG.md` unseres Imports endet bei 1.12.17 (2026-04-30) — er wird erst
|
||||
beim Release fortgeschrieben.
|
||||
|
||||
Zusammen heißt das: Die Grundlage ist ein **`develop`-Stand nach dem 1.12.17-Release**
|
||||
(1.12.18 erschien am 2026-05-12), nicht der Tag. Praktische Folge: **Ein Graft auf
|
||||
`v1.12.17` wäre falsch** und würde jede künftige Zusammenführung auf eine erfundene
|
||||
Ahnenreihe stellen. Wer den gemeinsamen Vorfahren nachträglich herstellen will, muss
|
||||
den passenden `develop`-Commit suchen — das braucht die volle Upstream-Historie, ein
|
||||
flacher Fetch der Tags genügt dafür nicht.
|
||||
|
||||
Daraus folgt das Wesentliche: **es gibt keinen gemeinsamen Vorfahren mit
|
||||
`element-hq/element-web`.** Ein `git merge upstream/develop` ist nicht möglich; mit
|
||||
`--allow-unrelated-histories` erzwungen, kollidiert praktisch jede Datei. Wer „mal
|
||||
eben Upstream nachziehen" sagt, meint in diesem Repo also: neuen Upstream-Stand
|
||||
beschaffen und unsere Änderungen darauf neu auftragen.
|
||||
|
||||
Das ist der Grund, warum die Zahl unten überhaupt zählt — sie ist der Aufwand jedes
|
||||
Updates.
|
||||
|
||||
### Unser Delta: 102 Dateien, davon 12 kritische
|
||||
|
||||
`git diff --name-only 3da3635..main`:
|
||||
|
||||
| Menge | Bereich | Konfliktrisiko |
|
||||
|---|---|---|
|
||||
| 46 | CI/Build (`.github/`, `.gitlab-ci.yml`, `dockerbuild/`) | gering — eigene Strecke, Upstreams Workflows brauchen wir nicht |
|
||||
| 22 | Config, Lockfiles, Upstream-Varianten | mittel — `pnpm-lock.yaml` konfliktet immer, wird aber regeneriert |
|
||||
| 13 | Web-Assets (`apps/web/res/`) | gering — meist eigene Dateien |
|
||||
| 4 + 3 | eigene Icons und `apps/desktop/axion1337/` | **keins** — kein Upstream-Pendant |
|
||||
| **12** | **Upstream-Quellcode** | **hier entsteht die Arbeit** |
|
||||
|
||||
### Die 12 Dateien, und warum sie angefasst wurden
|
||||
|
||||
**Branding (5)** — flach, gut isolierbar:
|
||||
|
||||
- `apps/web/src/SdkConfig.ts` — Defaults für `brand`, `welcome_background_url`, `desktopBuilds`
|
||||
- `apps/web/src/vector/index.html` — `<title>`, Favicon-Link, PWA-Namen
|
||||
- `apps/web/src/async-components/structures/ErrorView.tsx` — Logo der Fehlerseite
|
||||
- `apps/web/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx` — Attribution + Danksagung
|
||||
- `apps/web/src/i18n/strings/en_EN.json` — einzelne Strings
|
||||
|
||||
**ClamAV-Client-Scanning (7)** — tief in der Medien-Pipeline:
|
||||
|
||||
- `apps/web/src/ContentMessages.ts`, `utils/ContentScanner.ts`, `utils/DecryptFile.ts`
|
||||
- `apps/web/src/components/views/messages/MImageBody.tsx`, `MAudioBody.tsx`
|
||||
- `apps/web/src/viewmodels/message-body/FileBodyViewModel.ts`, `VideoBodyViewModel.ts`
|
||||
|
||||
### Nicht der Umfang entscheidet, sondern die Art des Eingriffs
|
||||
|
||||
Gemessen in geänderten Zeilen nehmen sich beide Gruppen wenig: **ClamAV ~130 Zeilen,
|
||||
Branding ~104**. Der größte Einzelpatch ist sogar Branding
|
||||
(`HelpUserSettingsTab.tsx`, 71 Zeilen). Wer nur zählt, hält beide für gleich teuer.
|
||||
|
||||
Sie sind es nicht, und der Grund ist die Art des Eingriffs:
|
||||
|
||||
- **Branding-Patches stehen am Rand.** Ein zusätzlicher Default in `SdkConfig.ts`,
|
||||
ein `<link>` im `<head>`, ein `<li>` in einer Settings-Liste. Wird die Datei
|
||||
umgebaut, sieht man sofort, wo das eigene Stück wieder hin muss.
|
||||
- **ClamAV-Patches stehen mittendrin** — in Entschlüsselungs- und Fehlerpfaden der
|
||||
Medien-Pipeline, verschränkt mit Upstream-Logik. Ein geänderter Kontrollfluss
|
||||
bedeutet nicht „Konflikt lösen", sondern „neu verstehen".
|
||||
|
||||
⚠️ **Und der eigentliche Haken: `viewmodels/`.** Element baut die Medien-Anzeige
|
||||
gerade auf MVVM um (`docs/MVVM.md`; v1 ist dort bereits als deprecated markiert —
|
||||
der Umbau läuft also schon in zweiter Runde). `FileBodyViewModel.ts` und
|
||||
`VideoBodyViewModel.ts` gab es in älteren Ständen gar nicht. Unsere Änderung darin
|
||||
ist mit je 6 Zeilen winzig — aber wenn Upstream diese Dateien verschiebt, umbenennt
|
||||
oder auflöst, entsteht **kein Konflikt**: die Zeilen sind einfach weg, und Git meldet
|
||||
nichts. Das ist gefährlicher als ein Konflikt, weil es stillschweigend passiert.
|
||||
|
||||
Praktische Folge: Nach einem Upstream-Update ist an ClamAV nicht die Merge-Ausgabe
|
||||
maßgeblich, sondern ein **Funktionstest** — eine verschlüsselte Datei senden und eine
|
||||
abgelehnte empfangen. Steht so auch in Abschnitt 2.
|
||||
|
||||
### Was daraus für künftige Änderungen folgt
|
||||
|
||||
1. **Erst prüfen, ob es die Konfiguration schon kann.** Auth-Logo, `logo_link_url`
|
||||
und `brand` liefen ohne Rebuild über die ConfigMap; das Call-Widget wurde
|
||||
vollständig über `VITE_PRODUCT_NAME` umbenannt, ohne eine einzige Quelldatei.
|
||||
Jede so vermiedene Datei ist eine, die beim Update nicht kollidiert.
|
||||
2. **Eigene Datei schlagen geänderte Datei.** `apps/desktop/axion1337/` und eigene
|
||||
Assets kosten beim Merge nichts.
|
||||
3. **Wenn Upstream-Code sein muss: einen Kommentar mit `ThreadNet-Fork:` und der
|
||||
Begründung dazu.** Beim Neuauftragen auf einen neuen Stand ist die Frage nie
|
||||
„was steht hier", sondern „warum stand das da" — und die beantwortet sonst
|
||||
niemand mehr.
|
||||
|
||||
## Repo-Topologie (seit 2026-07-31)
|
||||
|
||||
**Kanonisch ist `git.lab/axion1337.chat/ThreadNet-Web`** (Homelab-GitLab, nur im Lab
|
||||
@@ -60,3 +166,51 @@ auflösbar) — dort laufen Entwicklung und CI (`.gitlab-ci.yml`). Die Kopie auf
|
||||
`rohana.axion1337.de/sorb/ThreadNet-Web` ist ein **Push-Mirror** (automatisch, GitLab →
|
||||
Gitea) und dient als Lesekopie plus Standort für Issues, Container-Registry und Releases.
|
||||
**Niemals direkt nach rohana pushen** — der Mirror überschreibt divergente Stände.
|
||||
|
||||
## Element Call anheben (`@sorb/threadnet-call-embedded`)
|
||||
|
||||
Das Call-Widget kommt als npm-Paket aus der **Gitea-Registry auf rohana**, nicht von
|
||||
npmjs. `.npmrc` im Wurzelverzeichnis bindet den Scope fest:
|
||||
|
||||
```
|
||||
@sorb:registry=https://rohana.axion1337.de/api/packages/sorb/npm/
|
||||
```
|
||||
|
||||
Zum Anheben genügt damit der normale Weg — **kein Zusatzschritt, keine Umgebungsvariable**:
|
||||
|
||||
```sh
|
||||
# Version in apps/web/package.json setzen, dann:
|
||||
pnpm install --lockfile-only # Lockfile zieht die neue Tarball-URL von rohana
|
||||
pnpm --dir apps/web build # NICHT --filter web: das endet mit exit 0, ohne zu bauen
|
||||
```
|
||||
|
||||
Danach muss die Tarball-URL im `pnpm-lock.yaml` auf `rohana.axion1337.de` zeigen. Tut sie
|
||||
das nicht, ist die `.npmrc` verlorengegangen: **ohne sie löst pnpm gegen npmjs auf**, und
|
||||
das geht heute nur deshalb laut aus (404), weil der Name `@sorb` dort noch frei ist —
|
||||
verlässt man sich darauf, ist es ein *dependency-confusion*-Weg. Siehe management#0055.
|
||||
|
||||
Vor dem Anheben liegt das Paket erst dann in der Registry, wenn in `threadnet-call` der
|
||||
manuelle Job `publish_npm` gelaufen ist — der ist bewusst manuell und wird von sorb
|
||||
ausgelöst.
|
||||
|
||||
## Upstream als zweiter Remote (seit 2026-08-19)
|
||||
|
||||
Der Remote ist **lokale Konfiguration**, er wird nicht mitcommittet. Wer den Vergleich
|
||||
braucht, richtet ihn einmal ein:
|
||||
|
||||
```sh
|
||||
git remote add upstream https://github.com/element-hq/element-web.git
|
||||
git fetch --depth=1 upstream tag v1.12.26 # aktueller Stand
|
||||
git fetch --depth=1 upstream tag v1.12.17 # zum Vergleich
|
||||
```
|
||||
|
||||
Damit lässt sich ein Update **als Diff betrachten**, statt Dateien blind zu kopieren —
|
||||
zum Beispiel für die zwölf Dateien, die wir angefasst haben:
|
||||
|
||||
```sh
|
||||
git diff v1.12.26 main -- apps/web/src/... # unser Delta gegen Upstream
|
||||
git diff v1.12.17 v1.12.26 -- <datei> # was Upstream seither geaendert hat
|
||||
```
|
||||
|
||||
⚠️ Ein flacher Fetch liefert **keine Historie**: `git merge-base`, `git log` über
|
||||
Upstream und ein Graft-Versuch brauchen `git fetch upstream` ohne `--depth`.
|
||||
|
||||
@@ -617,8 +617,8 @@ importers:
|
||||
specifier: ^5.0.0
|
||||
version: 5.2.1(encoding@0.1.13)(webpack@5.106.2)
|
||||
'@sorb/threadnet-call-embedded':
|
||||
specifier: 0.19.2-threadnet.5
|
||||
version: 0.19.2-threadnet.5
|
||||
specifier: 0.19.2-threadnet.12
|
||||
version: 0.19.2-threadnet.12
|
||||
'@stylistic/eslint-plugin':
|
||||
specifier: ^5.0.0
|
||||
version: 5.10.0(eslint@8.57.1)
|
||||
@@ -5003,8 +5003,8 @@ packages:
|
||||
'@sinonjs/fake-timers@15.1.1':
|
||||
resolution: {integrity: sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==}
|
||||
|
||||
'@sorb/threadnet-call-embedded@0.19.2-threadnet.5':
|
||||
resolution: {integrity: sha512-u2TG7i82ibkpHSH/s6xA4Q6BTJqITdYWyrVieTiRwnm2Z+SCn/GmPK8JZIp/uSnpMrl9619yp/6vDVtpDJsKZg==, tarball: https://rohana.axion1337.de/api/packages/sorb/npm/%40sorb%2Fthreadnet-call-embedded/-/0.19.2-threadnet.5/threadnet-call-embedded-0.19.2-threadnet.5.tgz}
|
||||
'@sorb/threadnet-call-embedded@0.19.2-threadnet.12':
|
||||
resolution: {integrity: sha512-0x9nzkzGXFFVsXXI3LvLdWNXmjzJFsijh29yVXwrtFv/FQXgzwY8BttyMCCFHnEkp4VXtu7KeQfRCEzJB7rdIQ==, tarball: https://rohana.axion1337.de/api/packages/sorb/npm/%40sorb%2Fthreadnet-call-embedded/-/0.19.2-threadnet.12/threadnet-call-embedded-0.19.2-threadnet.12.tgz}
|
||||
|
||||
'@standard-schema/spec@1.1.0':
|
||||
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
|
||||
@@ -17632,7 +17632,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@sinonjs/commons': 3.0.1
|
||||
|
||||
'@sorb/threadnet-call-embedded@0.19.2-threadnet.5': {}
|
||||
'@sorb/threadnet-call-embedded@0.19.2-threadnet.12': {}
|
||||
|
||||
'@standard-schema/spec@1.1.0': {}
|
||||
|
||||
|
||||