feat: add initial project structure with configuration files and components
50
cmd/core-gui/apps/mining.itw3.json
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"code": "mining",
|
||||||
|
"type": "app",
|
||||||
|
"name": "Mining Module",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"namespace": "mining",
|
||||||
|
"description": "Cryptocurrency mining management",
|
||||||
|
"author": "Lethean",
|
||||||
|
"contexts": ["miner", "default"],
|
||||||
|
"menu": [
|
||||||
|
{
|
||||||
|
"id": "mining",
|
||||||
|
"label": "Mining",
|
||||||
|
"order": 200,
|
||||||
|
"contexts": ["miner"],
|
||||||
|
"children": [
|
||||||
|
{"id": "mining-dashboard", "label": "Dashboard", "route": "/mining/dashboard", "order": 1},
|
||||||
|
{"id": "mining-pools", "label": "Pools", "route": "/mining/pools", "order": 2},
|
||||||
|
{"id": "mining-sep1", "separator": true, "order": 3},
|
||||||
|
{"id": "mining-start", "label": "Start Mining", "action": "mining:start", "order": 4},
|
||||||
|
{"id": "mining-stop", "label": "Stop Mining", "action": "mining:stop", "order": 5}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"routes": [
|
||||||
|
{"path": "/mining/dashboard", "component": "mining-dashboard", "title": "Mining Dashboard", "contexts": ["miner"]},
|
||||||
|
{"path": "/mining/pools", "component": "mining-pools", "title": "Mining Pools", "contexts": ["miner"]}
|
||||||
|
],
|
||||||
|
"api": [
|
||||||
|
{"method": "GET", "path": "/status", "description": "Get mining status"},
|
||||||
|
{"method": "POST", "path": "/start", "description": "Start mining"},
|
||||||
|
{"method": "POST", "path": "/stop", "description": "Stop mining"},
|
||||||
|
{"method": "GET", "path": "/pools", "description": "List configured pools"}
|
||||||
|
],
|
||||||
|
"downloads": {
|
||||||
|
"x86_64": {
|
||||||
|
"darwin": {"url": "https://releases.example.com/mining/darwin-x86_64.tar.gz"},
|
||||||
|
"linux": {"url": "https://releases.example.com/mining/linux-x86_64.tar.gz"},
|
||||||
|
"windows": {"url": "https://releases.example.com/mining/windows-x86_64.zip"}
|
||||||
|
},
|
||||||
|
"aarch64": {
|
||||||
|
"darwin": {"url": "https://releases.example.com/mining/darwin-aarch64.tar.gz"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"defaultPool": "",
|
||||||
|
"threads": 0,
|
||||||
|
"intensity": 50
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ tasks:
|
||||||
|
|
||||||
install:public:deps:
|
install:public:deps:
|
||||||
summary: Install public dependencies
|
summary: Install public dependencies
|
||||||
dir: public
|
dir: frontend
|
||||||
sources:
|
sources:
|
||||||
- package.json
|
- package.json
|
||||||
- package-lock.json
|
- package-lock.json
|
||||||
|
|
@ -24,7 +24,7 @@ tasks:
|
||||||
build:public:
|
build:public:
|
||||||
label: build:public (PRODUCTION={{.PRODUCTION}})
|
label: build:public (PRODUCTION={{.PRODUCTION}})
|
||||||
summary: Build the public folder
|
summary: Build the public folder
|
||||||
dir: public
|
dir: frontend
|
||||||
sources:
|
sources:
|
||||||
- "**/*"
|
- "**/*"
|
||||||
generates:
|
generates:
|
||||||
|
|
@ -49,15 +49,15 @@ tasks:
|
||||||
- task: go:mod:tidy
|
- task: go:mod:tidy
|
||||||
sources:
|
sources:
|
||||||
- "**/*.[jt]s"
|
- "**/*.[jt]s"
|
||||||
- exclude: public/**/*
|
- exclude: frontend/**/*
|
||||||
- public/bindings/**/*
|
- frontend/bindings/**/*
|
||||||
- "**/*.go"
|
- "**/*.go"
|
||||||
- go.mod
|
- go.mod
|
||||||
- go.sum
|
- go.sum
|
||||||
generates:
|
generates:
|
||||||
- public/bindings/**/*
|
- frontend/bindings/**/*
|
||||||
cmds:
|
cmds:
|
||||||
- wails3 generate bindings -d public/bindings -f '{{.BUILD_FLAGS}}' -clean=true -ts
|
- wails3 generate bindings -d frontend/bindings -f '{{.BUILD_FLAGS}}' -clean=true -ts
|
||||||
|
|
||||||
generate:icons:
|
generate:icons:
|
||||||
summary: Generates Windows `.ico` and Mac `.icns` files from an image
|
summary: Generates Windows `.ico` and Mac `.icns` files from an image
|
||||||
|
|
@ -72,7 +72,7 @@ tasks:
|
||||||
|
|
||||||
dev:public:
|
dev:public:
|
||||||
summary: Runs the frontend dev server for live development
|
summary: Runs the frontend dev server for live development
|
||||||
dir: public
|
dir: frontend
|
||||||
deps:
|
deps:
|
||||||
- task: install:public:deps
|
- task: install:public:deps
|
||||||
cmds:
|
cmds:
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@ tasks:
|
||||||
GOOS: darwin
|
GOOS: darwin
|
||||||
CGO_ENABLED: 1
|
CGO_ENABLED: 1
|
||||||
GOARCH: '{{.ARCH | default ARCH}}'
|
GOARCH: '{{.ARCH | default ARCH}}'
|
||||||
CGO_CFLAGS: "-mmacosx-version-min=10.15"
|
CGO_CFLAGS: "-mmacosx-version-min=26.0"
|
||||||
CGO_LDFLAGS: "-mmacosx-version-min=10.15"
|
CGO_LDFLAGS: "-mmacosx-version-min=26.0"
|
||||||
MACOSX_DEPLOYMENT_TARGET: "10.15"
|
MACOSX_DEPLOYMENT_TARGET: "26.0"
|
||||||
PRODUCTION: '{{.PRODUCTION | default "false"}}'
|
PRODUCTION: '{{.PRODUCTION | default "false"}}'
|
||||||
|
|
||||||
build:universal:
|
build:universal:
|
||||||
|
|
|
||||||
157
cmd/core-gui/claude_bridge.go
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
var wsUpgrader = websocket.Upgrader{
|
||||||
|
ReadBufferSize: 1024,
|
||||||
|
WriteBufferSize: 1024,
|
||||||
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClaudeBridge forwards messages between GUI clients and the MCP core WebSocket.
|
||||||
|
type ClaudeBridge struct {
|
||||||
|
mcpConn *websocket.Conn
|
||||||
|
mcpURL string
|
||||||
|
clients map[*websocket.Conn]bool
|
||||||
|
clientsMu sync.RWMutex
|
||||||
|
broadcast chan []byte
|
||||||
|
reconnectMu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClaudeBridge creates a new bridge to the MCP core WebSocket.
|
||||||
|
func NewClaudeBridge(mcpURL string) *ClaudeBridge {
|
||||||
|
return &ClaudeBridge{
|
||||||
|
mcpURL: mcpURL,
|
||||||
|
clients: make(map[*websocket.Conn]bool),
|
||||||
|
broadcast: make(chan []byte, 256),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start connects to the MCP WebSocket and starts the bridge.
|
||||||
|
func (cb *ClaudeBridge) Start() {
|
||||||
|
go cb.connectToMCP()
|
||||||
|
go cb.broadcastLoop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// connectToMCP establishes connection to the MCP core WebSocket.
|
||||||
|
func (cb *ClaudeBridge) connectToMCP() {
|
||||||
|
for {
|
||||||
|
cb.reconnectMu.Lock()
|
||||||
|
if cb.mcpConn != nil {
|
||||||
|
cb.mcpConn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Claude bridge connecting to MCP at %s", cb.mcpURL)
|
||||||
|
conn, _, err := websocket.DefaultDialer.Dial(cb.mcpURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Claude bridge failed to connect to MCP: %v", err)
|
||||||
|
cb.reconnectMu.Unlock()
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cb.mcpConn = conn
|
||||||
|
cb.reconnectMu.Unlock()
|
||||||
|
log.Printf("Claude bridge connected to MCP")
|
||||||
|
|
||||||
|
// Read messages from MCP and broadcast to clients
|
||||||
|
for {
|
||||||
|
_, message, err := conn.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Claude bridge MCP read error: %v", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
cb.broadcast <- message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connection lost, retry
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// broadcastLoop sends messages from MCP to all connected clients.
|
||||||
|
func (cb *ClaudeBridge) broadcastLoop() {
|
||||||
|
for message := range cb.broadcast {
|
||||||
|
cb.clientsMu.RLock()
|
||||||
|
for client := range cb.clients {
|
||||||
|
err := client.WriteMessage(websocket.TextMessage, message)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Claude bridge client write error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb.clientsMu.RUnlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleWebSocket handles WebSocket connections from GUI clients.
|
||||||
|
func (cb *ClaudeBridge) HandleWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||||
|
conn, err := wsUpgrader.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Claude bridge upgrade error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cb.clientsMu.Lock()
|
||||||
|
cb.clients[conn] = true
|
||||||
|
cb.clientsMu.Unlock()
|
||||||
|
|
||||||
|
// Send connected message
|
||||||
|
connMsg, _ := json.Marshal(map[string]any{
|
||||||
|
"type": "system",
|
||||||
|
"data": "Connected to Claude bridge",
|
||||||
|
"timestamp": time.Now(),
|
||||||
|
})
|
||||||
|
conn.WriteMessage(websocket.TextMessage, connMsg)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
cb.clientsMu.Lock()
|
||||||
|
delete(cb.clients, conn)
|
||||||
|
cb.clientsMu.Unlock()
|
||||||
|
conn.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Read messages from client and forward to MCP
|
||||||
|
for {
|
||||||
|
_, message, err := conn.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the message to check type
|
||||||
|
var msg map[string]any
|
||||||
|
if err := json.Unmarshal(message, &msg); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward claude_message to MCP
|
||||||
|
if msgType, ok := msg["type"].(string); ok && msgType == "claude_message" {
|
||||||
|
cb.sendToMCP(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendToMCP sends a message to the MCP WebSocket.
|
||||||
|
func (cb *ClaudeBridge) sendToMCP(message []byte) {
|
||||||
|
cb.reconnectMu.Lock()
|
||||||
|
defer cb.reconnectMu.Unlock()
|
||||||
|
|
||||||
|
if cb.mcpConn == nil {
|
||||||
|
log.Printf("Claude bridge: MCP not connected")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := cb.mcpConn.WriteMessage(websocket.TextMessage, message)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Claude bridge MCP write error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
7
cmd/core-gui/frontend.old/.dockerignore
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
|
.env
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
17
cmd/core-gui/frontend.old/.editorconfig
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.ts]
|
||||||
|
quote_type = single
|
||||||
|
ij_typescript_use_double_quotes = false
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
42
cmd/core-gui/frontend.old/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||||
|
.npmrc
|
||||||
|
# Compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# Node
|
||||||
|
/node_modules
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea/
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
/.angular/cache
|
||||||
|
.sass-cache/
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
69
cmd/core-gui/frontend.old/README.md
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
### Installation
|
||||||
|
- `npm install` (install dependencies)
|
||||||
|
- `npm outdated` (verify dependency status)
|
||||||
|
|
||||||
|
### Development
|
||||||
|
- `npm run start`
|
||||||
|
- Visit http://localhost:4200
|
||||||
|
|
||||||
|
## Lint
|
||||||
|
- `npm run lint`
|
||||||
|
|
||||||
|
## Tests (headless-ready, no Chrome required)
|
||||||
|
- Unit/integration: `npm run test` (opens browser), or:
|
||||||
|
- Headless (uses Puppeteer Chromium): `npm run test:headless`
|
||||||
|
- Coverage report (HTML + text-summary): `npm run coverage`
|
||||||
|
- Coverage thresholds are enforced in Karma (≈80% statements/lines/functions, 70% branches for global). Adjust in `karma.conf.js` if needed.
|
||||||
|
|
||||||
|
### TDD workflow and test naming (Good/Bad/Ugly)
|
||||||
|
- Follow strict TDD:
|
||||||
|
1) Write failing tests from user stories + acceptance criteria
|
||||||
|
2) Implement minimal code to pass
|
||||||
|
3) Refactor
|
||||||
|
- Test case naming convention: each logical test should have three variants to clarify intent and data quality.
|
||||||
|
- Example helpers in `src/testing/gbu.ts`:
|
||||||
|
```ts
|
||||||
|
import { itGood, itBad, itUgly, trio } from 'src/testing/gbu';
|
||||||
|
|
||||||
|
itGood('saves profile', () => {/* valid data */});
|
||||||
|
itBad('saves profile', () => {/* incorrect data (edge) */});
|
||||||
|
itUgly('saves profile', () => {/* invalid data/conditions */});
|
||||||
|
|
||||||
|
// Or use trio
|
||||||
|
trio('process order', {
|
||||||
|
good: () => {/* ... */},
|
||||||
|
bad: () => {/* ... */},
|
||||||
|
ugly: () => {/* ... */},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
- Do not modify router-outlet containers in tests/components.
|
||||||
|
|
||||||
|
### Standalone Angular 20+ patterns (migration notes)
|
||||||
|
- This app is moving to Angular standalone APIs. Prefer:
|
||||||
|
- Standalone components (`standalone: true`, add `imports: []` per component)
|
||||||
|
- `provideRouter(...)`, `provideHttpClient(...)`, `provideServiceWorker(...)` in `app.config.ts`
|
||||||
|
- Translation is configured via `app.config.ts` using `TranslateModule.forRoot(...)` and an HTTP loader.
|
||||||
|
- Legacy NgModules should be converted progressively. If an `NgModule` remains but is unrouted/unreferenced, keep it harmlessly until deletion is approved. Do not alter the main router-outlet page context panel.
|
||||||
|
|
||||||
|
### Web Awesome + Font Awesome (Pro)
|
||||||
|
- Both Font Awesome and Web Awesome are integrated. Do not remove. Web Awesome assets are copied via `angular.json` assets, and its base path is set at runtime in `app.ts`:
|
||||||
|
```ts
|
||||||
|
import('@awesome.me/webawesome').then(m => m.setBasePath('/assets/web-awesome'));
|
||||||
|
```
|
||||||
|
- CSS includes are defined in `angular.json` and `src/styles.css`.
|
||||||
|
|
||||||
|
### SSR and production
|
||||||
|
- Build (browser + server): `npm run build`
|
||||||
|
- Serve SSR bundle: `npm run serve` → http://localhost:4000
|
||||||
|
|
||||||
|
### Notes for other LLMs / contributors
|
||||||
|
- Respect the constraints:
|
||||||
|
- Do NOT edit the router-outlet main panel; pages/services are the focus
|
||||||
|
- Preserve existing functionality; do not remove Web Awesome/Font Awesome
|
||||||
|
- Use strict TDD and Good/Bad/Ugly naming for tests
|
||||||
|
- Keep or improve code coverage ≥ configured thresholds for changed files
|
||||||
|
- Use Angular 20+ standalone patterns; update `app.config.ts` for global providers.
|
||||||
|
- For tests, prefer headless runs via Puppeteer (no local Chrome needed).
|
||||||
|
|
||||||
|
### Author
|
||||||
|
- Author: danny
|
||||||
132
cmd/core-gui/frontend.old/angular.json
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"lthn.io": {
|
||||||
|
"projectType": "application",
|
||||||
|
"schematics": {},
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular/build:application",
|
||||||
|
"options": {
|
||||||
|
"browser": "src/main.ts",
|
||||||
|
"polyfills": [
|
||||||
|
"zone.js"
|
||||||
|
],
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "public"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "@awesome.me/webawesome/**/*.*",
|
||||||
|
"input": "node_modules/",
|
||||||
|
"output": "/"
|
||||||
|
},
|
||||||
|
"src/sitemap.xml",
|
||||||
|
"src/robots.txt"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"node_modules/@fortawesome/fontawesome-free/css/all.min.css",
|
||||||
|
"src/styles.css"
|
||||||
|
],
|
||||||
|
"scripts": [],
|
||||||
|
"define": {
|
||||||
|
"import.meta.vitest": "undefined"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "1MB",
|
||||||
|
"maximumError": "1MB"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "4kB",
|
||||||
|
"maximumError": "8kB"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputHashing": "all",
|
||||||
|
"serviceWorker": "ngsw-config.json",
|
||||||
|
"server": "src/main.server.ts",
|
||||||
|
"outputMode": "server",
|
||||||
|
"ssr": {
|
||||||
|
"entry": "src/server.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"optimization": false,
|
||||||
|
"extractLicenses": false,
|
||||||
|
"sourceMap": true,
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.development.ts"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development"
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular/build:dev-server",
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"buildTarget": "lthn.io:build:production"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"buildTarget": "lthn.io:build:development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development"
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular/build:extract-i18n"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular/build:karma",
|
||||||
|
"options": {
|
||||||
|
"polyfills": [
|
||||||
|
"zone.js",
|
||||||
|
"zone.js/testing",
|
||||||
|
"src/test.ts"
|
||||||
|
],
|
||||||
|
"tsConfig": "tsconfig.spec.json",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "public"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"src/styles.css"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-eslint/builder:lint",
|
||||||
|
"options": {
|
||||||
|
"lintFilePatterns": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.html"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cli": {
|
||||||
|
"schematicCollections": [
|
||||||
|
"angular-eslint"
|
||||||
|
],
|
||||||
|
"analytics": false
|
||||||
|
}
|
||||||
|
}
|
||||||
63
cmd/core-gui/frontend.old/eslint.config.js
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
// @ts-check
|
||||||
|
const eslint = require("@eslint/js");
|
||||||
|
const tseslint = require("typescript-eslint");
|
||||||
|
const angular = require("angular-eslint");
|
||||||
|
|
||||||
|
module.exports = tseslint.config(
|
||||||
|
{
|
||||||
|
files: ["**/*.ts"],
|
||||||
|
extends: [
|
||||||
|
eslint.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
...tseslint.configs.stylistic,
|
||||||
|
...angular.configs.tsRecommended,
|
||||||
|
],
|
||||||
|
processor: angular.processInlineTemplates,
|
||||||
|
rules: {
|
||||||
|
"@angular-eslint/directive-selector": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
type: "attribute",
|
||||||
|
prefix: "app",
|
||||||
|
style: "camelCase",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@angular-eslint/component-selector": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
type: "element",
|
||||||
|
prefix: "app",
|
||||||
|
style: "kebab-case",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"@angular-eslint/component-class-suffix": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
suffixes: ["", "Component"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@angular-eslint/prefer-inject": "off",
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": [
|
||||||
|
"error",
|
||||||
|
{ "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }
|
||||||
|
],
|
||||||
|
"no-undefined": "off",
|
||||||
|
"no-var": "error",
|
||||||
|
"prefer-const": "error",
|
||||||
|
"func-names": "error",
|
||||||
|
"id-length": "error",
|
||||||
|
"newline-before-return": "error",
|
||||||
|
"space-before-blocks": "error",
|
||||||
|
"no-alert": "error"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ["**/*.html"],
|
||||||
|
extends: [
|
||||||
|
...angular.configs.templateRecommended,
|
||||||
|
...angular.configs.templateAccessibility,
|
||||||
|
],
|
||||||
|
rules: {},
|
||||||
|
}
|
||||||
|
);
|
||||||
61
cmd/core-gui/frontend.old/karma.conf.js
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
process.env.CHROME_BIN = process.env.CHROME_BIN || (function() {
|
||||||
|
try { return require('puppeteer').executablePath(); } catch { return undefined; }
|
||||||
|
})();
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client: {
|
||||||
|
jasmine: {
|
||||||
|
// you can add configuration options for Jasmine here
|
||||||
|
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||||
|
// for example, you can disable the random execution order
|
||||||
|
random: true
|
||||||
|
},
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
jasmineHtmlReporter: {
|
||||||
|
suppressAll: true // removes the duplicated traces
|
||||||
|
},
|
||||||
|
coverageReporter: {
|
||||||
|
dir: require('path').join(__dirname, './coverage/angular-starter'),
|
||||||
|
subdir: '.',
|
||||||
|
reporters: [
|
||||||
|
{ type: 'html' },
|
||||||
|
{ type: 'text-summary' }
|
||||||
|
],
|
||||||
|
check: {
|
||||||
|
global: {
|
||||||
|
statements: 80,
|
||||||
|
branches: 70,
|
||||||
|
functions: 80,
|
||||||
|
lines: 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
customLaunchers: {
|
||||||
|
ChromeHeadless: {
|
||||||
|
base: 'Chrome',
|
||||||
|
flags: [
|
||||||
|
'--headless',
|
||||||
|
'--disable-gpu',
|
||||||
|
'--no-sandbox',
|
||||||
|
'--disable-dev-shm-usage',
|
||||||
|
'--disable-web-security',
|
||||||
|
'--remote-debugging-port=9222'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
restartOnFileChange: true
|
||||||
|
});
|
||||||
|
};
|
||||||
30
cmd/core-gui/frontend.old/ngsw-config.json
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
|
||||||
|
"index": "/index.html",
|
||||||
|
"assetGroups": [
|
||||||
|
{
|
||||||
|
"name": "app",
|
||||||
|
"installMode": "prefetch",
|
||||||
|
"resources": {
|
||||||
|
"files": [
|
||||||
|
"/favicon.ico",
|
||||||
|
"/index.csr.html",
|
||||||
|
"/index.html",
|
||||||
|
"/manifest.webmanifest",
|
||||||
|
"/*.css",
|
||||||
|
"/*.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "assets",
|
||||||
|
"installMode": "lazy",
|
||||||
|
"updateMode": "prefetch",
|
||||||
|
"resources": {
|
||||||
|
"files": [
|
||||||
|
"/**/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
12685
cmd/core-gui/frontend.old/package-lock.json
generated
Normal file
60
cmd/core-gui/frontend.old/package.json
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
{
|
||||||
|
"name": "lthn.io",
|
||||||
|
"version": "20.3.2",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"dev": "ng serve --port 4200",
|
||||||
|
"start": "ng serve --port 4200",
|
||||||
|
"build": "ng build",
|
||||||
|
"watch": "ng build --watch --configuration development",
|
||||||
|
"preview": "http-server ./dist/lthn-dns-web/browser -o",
|
||||||
|
"puppeteer:install": "npx puppeteer browsers install chrome || true",
|
||||||
|
"test": "ng test",
|
||||||
|
"test:headless": "(export CHROME_BIN=\"$(node -e \"console.log(require('puppeteer').executablePath())\")\"; ng test --no-watch --code-coverage=false --browsers=ChromeHeadless) || (npm run puppeteer:install && export CHROME_BIN=\"$(node -e \"console.log(require('puppeteer').executablePath())\")\" && ng test --no-watch --code-coverage=false --browsers=ChromeHeadless)",
|
||||||
|
"coverage": "(export CHROME_BIN=\"$(node -e \"console.log(require('puppeteer').executablePath())\")\"; ng test --no-watch --code-coverage --browsers=ChromeHeadless) || (npm run puppeteer:install && export CHROME_BIN=\"$(node -e \"console.log(require('puppeteer').executablePath())\")\" && ng test --no-watch --code-coverage --browsers=ChromeHeadless)",
|
||||||
|
"lint": "ng lint",
|
||||||
|
"serve": "node dist/angular-starter/server/server.mjs"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/common": "^20.3.2",
|
||||||
|
"@angular/compiler": "^20.3.2",
|
||||||
|
"@angular/core": "^20.3.2",
|
||||||
|
"@angular/forms": "^20.3.2",
|
||||||
|
"@angular/platform-browser": "^20.3.2",
|
||||||
|
"@angular/platform-server": "^20.3.2",
|
||||||
|
"@angular/router": "^20.3.2",
|
||||||
|
"@angular/service-worker": "^20.3.2",
|
||||||
|
"@angular/ssr": "^20.3.3",
|
||||||
|
"@awesome.me/kit-2e7e02d1b1": "^1.0.6",
|
||||||
|
"@awesome.me/webawesome": "file:~/Code/lib/webawesome",
|
||||||
|
"@fortawesome/fontawesome-free": "^7.0.1",
|
||||||
|
"@ngx-translate/core": "^17.0.0",
|
||||||
|
"@ngx-translate/http-loader": "^17.0.0",
|
||||||
|
"bootstrap": "^5.3.8",
|
||||||
|
"express": "^5.1.0",
|
||||||
|
"rxjs": "^7.8.2",
|
||||||
|
"tslib": "^2.8.1",
|
||||||
|
"uuid": "^13.0.0",
|
||||||
|
"zone.js": "^0.15.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular/build": "^20.3.3",
|
||||||
|
"@angular/cli": "^20.3.3",
|
||||||
|
"@angular/compiler-cli": "^20.3.2",
|
||||||
|
"@types/express": "^5.0.3",
|
||||||
|
"@types/jasmine": "^5.1.9",
|
||||||
|
"@types/node": "^24.6.0",
|
||||||
|
"angular-eslint": "^20.3.0",
|
||||||
|
"eslint": "^9.36.0",
|
||||||
|
"jasmine-core": "^5.11.0",
|
||||||
|
"karma": "^6.4.4",
|
||||||
|
"karma-chrome-launcher": "^3.2.0",
|
||||||
|
"karma-coverage": "^2.2.1",
|
||||||
|
"karma-jasmine": "^5.1.0",
|
||||||
|
"karma-jasmine-html-reporter": "^2.1.0",
|
||||||
|
"puppeteer": "^23.7.0",
|
||||||
|
"typescript": "~5.8.3",
|
||||||
|
"typescript-eslint": "^8.45.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
cmd/core-gui/frontend.old/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
331
cmd/core-gui/frontend.old/public/i18n/en.json
Normal file
|
|
@ -0,0 +1,331 @@
|
||||||
|
{ "app": {
|
||||||
|
"title": "Bob Wallet"
|
||||||
|
},
|
||||||
|
"sidebar": {
|
||||||
|
"wallet": "Wallet",
|
||||||
|
"topLevelDomains": "Top Level Domains",
|
||||||
|
"miscellaneous": "Miscellaneous",
|
||||||
|
"portfolio": "Portfolio",
|
||||||
|
"send": "Send",
|
||||||
|
"receive": "Receive",
|
||||||
|
"domainManager": "Domain Manager",
|
||||||
|
"browseDomains": "Browse Domains",
|
||||||
|
"yourBids": "Your Bids",
|
||||||
|
"watching": "Watching",
|
||||||
|
"exchange": "Exchange",
|
||||||
|
"claimAirdrop": "Claim Airdrop",
|
||||||
|
"signMessage": "Sign Message",
|
||||||
|
"verifyMessage": "Verify Message",
|
||||||
|
"currentHeight": "Current Height",
|
||||||
|
"currentHash": "Current Hash"
|
||||||
|
},
|
||||||
|
"topbar": {
|
||||||
|
"searchPlaceholder": "Search TLD",
|
||||||
|
"synced": "Synced",
|
||||||
|
"walletID": "Wallet ID",
|
||||||
|
"spendableBalance": "Spendable Balance",
|
||||||
|
"network": "Network",
|
||||||
|
"settings": "Settings",
|
||||||
|
"logout": "Logout"
|
||||||
|
},
|
||||||
|
"home": {
|
||||||
|
"spendable": "Spendable",
|
||||||
|
"locked": "Locked",
|
||||||
|
"revealable": "Revealable",
|
||||||
|
"redeemable": "Redeemable",
|
||||||
|
"registerable": "Registerable",
|
||||||
|
"renewable": "Renewable",
|
||||||
|
"transferring": "Transferring",
|
||||||
|
"finalizable": "Finalizable",
|
||||||
|
"inBids": "In bids",
|
||||||
|
"bid": "bid",
|
||||||
|
"bids": "bids",
|
||||||
|
"revealAll": "Reveal All",
|
||||||
|
"redeemAll": "Redeem All",
|
||||||
|
"registerAll": "Register All",
|
||||||
|
"renewAll": "Renew All",
|
||||||
|
"finalizeAll": "Finalize All",
|
||||||
|
"bidsReadyToReveal": "{{count}} bids ready to reveal",
|
||||||
|
"bidsReadyToRedeem": "{{count}} bids ready to redeem",
|
||||||
|
"namesReadyToRegister": "{{count}} names ready to register",
|
||||||
|
"domainsExpiringSoon": "{{count}} domains expiring soon",
|
||||||
|
"domainsInTransfer": "{{count}} domains in transfer",
|
||||||
|
"transfersReadyToFinalize": "{{count}} transfers ready to finalize",
|
||||||
|
"transactionHistory": "Transaction History",
|
||||||
|
"noTransactions": "No transactions yet. Transaction history will appear here once you start using the wallet."
|
||||||
|
},
|
||||||
|
"domainManager": {
|
||||||
|
"searchPlaceholder": "Search domains...",
|
||||||
|
"export": "Export",
|
||||||
|
"bulkTransfer": "Bulk Transfer",
|
||||||
|
"claimNamePayment": "Claim Name for Payment",
|
||||||
|
"emptyState": "You do not own any names yet.",
|
||||||
|
"browseDomainsLink": "Browse domains",
|
||||||
|
"toGetStarted": "to get started.",
|
||||||
|
"name": "Name",
|
||||||
|
"expires": "Expires",
|
||||||
|
"highestBid": "Highest Bid",
|
||||||
|
"showingDomains": "Showing {{count}} domains"
|
||||||
|
},
|
||||||
|
"exchange": {
|
||||||
|
"listings": "Listings",
|
||||||
|
"fills": "Fills",
|
||||||
|
"auctions": "Auctions",
|
||||||
|
"yourListings": "Your Listings",
|
||||||
|
"yourFills": "Your Fills",
|
||||||
|
"marketplaceAuctions": "Marketplace Auctions",
|
||||||
|
"createListing": "Create Listing",
|
||||||
|
"refresh": "Refresh",
|
||||||
|
"noActiveListings": "You have no active listings.",
|
||||||
|
"noFilledOrders": "You have no filled orders.",
|
||||||
|
"noActiveAuctions": "No active auctions found.",
|
||||||
|
"listDomainsInfo": "List your domains for sale to other Handshake users via the Shakedex protocol.",
|
||||||
|
"completedPurchasesInfo": "Completed purchases will appear here.",
|
||||||
|
"browseAuctionsInfo": "Browse available domain auctions from other users."
|
||||||
|
},
|
||||||
|
"searchTld": {
|
||||||
|
"searchPlaceholder": "Search for a name...",
|
||||||
|
"search": "Search",
|
||||||
|
"searching": "Searching...",
|
||||||
|
"enterNamePrompt": "Enter a name to search for availability and auction status.",
|
||||||
|
"available": "Available",
|
||||||
|
"inAuction": "In Auction",
|
||||||
|
"status": "Status",
|
||||||
|
"currentBid": "Current Bid",
|
||||||
|
"blocksUntilReveal": "Blocks until reveal",
|
||||||
|
"availableForBidding": "Available for bidding",
|
||||||
|
"auctionInProgress": "Auction in progress",
|
||||||
|
"placeBid": "Place Bid",
|
||||||
|
"watch": "Watch"
|
||||||
|
},
|
||||||
|
"onboarding": {
|
||||||
|
"welcome": "Welcome to Bob Wallet",
|
||||||
|
"setupPrompt": "Set up your wallet to start managing Handshake names",
|
||||||
|
"createNewWallet": "Create New Wallet",
|
||||||
|
"importSeed": "Import Seed",
|
||||||
|
"connectLedger": "Connect Ledger",
|
||||||
|
"important": "Important:",
|
||||||
|
"seedPhraseWarning": "Write down your seed phrase and store it in a secure location. You will need it to recover your wallet.",
|
||||||
|
"copySeedPhrase": "Copy Seed Phrase",
|
||||||
|
"savedSeed": "I've Saved My Seed",
|
||||||
|
"importSeedPrompt": "Enter your 12 or 24 word seed phrase to restore an existing wallet.",
|
||||||
|
"seedPhrase": "Seed Phrase",
|
||||||
|
"seedPhrasePlaceholder": "Enter your seed phrase",
|
||||||
|
"importWallet": "Import Wallet",
|
||||||
|
"ledgerPrompt": "Connect your Ledger hardware wallet to manage your Handshake names securely.",
|
||||||
|
"instructions": "Instructions:",
|
||||||
|
"ledgerStep1": "Connect your Ledger device via USB",
|
||||||
|
"ledgerStep2": "Enter your PIN on the device",
|
||||||
|
"ledgerStep3": "Open the Handshake app on your Ledger",
|
||||||
|
"ledgerStep4": "Click \"Connect\" below",
|
||||||
|
"connectLedgerButton": "Connect Ledger"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"general": "General",
|
||||||
|
"wallet": "Wallet",
|
||||||
|
"connection": "Connection",
|
||||||
|
"advanced": "Advanced",
|
||||||
|
"language": "Language",
|
||||||
|
"blockExplorer": "Block Explorer",
|
||||||
|
"theme": "Theme",
|
||||||
|
"light": "Light",
|
||||||
|
"dark": "Dark",
|
||||||
|
"system": "System",
|
||||||
|
"walletDirectory": "Wallet Directory",
|
||||||
|
"walletDirectoryInfo": "Location where wallet data is stored",
|
||||||
|
"changeDirectory": "Change Directory",
|
||||||
|
"backup": "Backup",
|
||||||
|
"backupInfo": "Export wallet seed phrase and settings",
|
||||||
|
"exportBackup": "Export Backup",
|
||||||
|
"rescanBlockchain": "Rescan Blockchain",
|
||||||
|
"rescanInfo": "Re-scan the blockchain for transactions",
|
||||||
|
"rescan": "Rescan",
|
||||||
|
"connectionType": "Connection Type",
|
||||||
|
"fullNode": "Full Node",
|
||||||
|
"spv": "SPV (Light)",
|
||||||
|
"customRPC": "Custom RPC",
|
||||||
|
"network": "Network",
|
||||||
|
"mainnet": "Mainnet",
|
||||||
|
"testnet": "Testnet",
|
||||||
|
"regtest": "Regtest",
|
||||||
|
"simnet": "Simnet",
|
||||||
|
"apiKey": "API Key",
|
||||||
|
"apiKeyInfo": "Node API authentication key",
|
||||||
|
"analytics": "Analytics",
|
||||||
|
"analyticsInfo": "Share anonymous usage data to improve Bob",
|
||||||
|
"developerOptions": "Developer Options",
|
||||||
|
"openDebugConsole": "Open Debug Console"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"hns": "HNS",
|
||||||
|
"usd": "USD",
|
||||||
|
"loading": "Loading...",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"close": "Close",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"continue": "Continue",
|
||||||
|
"back": "Back",
|
||||||
|
"next": "Next",
|
||||||
|
"done": "Done",
|
||||||
|
"error": "Error",
|
||||||
|
"success": "Success",
|
||||||
|
"warning": "Warning",
|
||||||
|
"info": "Info"
|
||||||
|
},
|
||||||
|
"app.boot.download-check": "Checking for Updates",
|
||||||
|
"app.boot.folder-check": "Setup Check",
|
||||||
|
"app.boot.loaded-runtime": "Application Loaded",
|
||||||
|
"app.boot.server-check": "Checking Server",
|
||||||
|
"app.boot.start-runtime": "Starting Desktop",
|
||||||
|
"app.core.ui.search": "Search",
|
||||||
|
"app.lthn.chain.daemons.lethean-blockchain-export": "Blockchain Export",
|
||||||
|
"app.lthn.chain.daemons.lethean-blockchain-import": "Blockchain Import",
|
||||||
|
"app.lthn.chain.daemons.lethean-wallet-cli": "Wallet CLI",
|
||||||
|
"app.lthn.chain.daemons.lethean-wallet-rpc": "Wallet RPC",
|
||||||
|
"app.lthn.chain.daemons.lethean-wallet-vpn-rpc": "Exit Node Wallet",
|
||||||
|
"app.lthn.chain.daemons.letheand": "Blockchain Service",
|
||||||
|
"app.lthn.chain.desc.no_transactions": "There were no transactions included in this block",
|
||||||
|
"app.lthn.chain.description": "Lethean (LTHN) Blockchain Stats",
|
||||||
|
"app.lthn.chain.heading": "Lethean Blockchain Stats",
|
||||||
|
"app.lthn.chain.menu.blocks": "Blocks",
|
||||||
|
"app.lthn.chain.menu.configuration": "Configuration",
|
||||||
|
"app.lthn.chain.menu.raw_data": "Raw Block Data",
|
||||||
|
"app.lthn.chain.menu.stats": "Stats",
|
||||||
|
"app.lthn.chain.table.age": "Age",
|
||||||
|
"app.lthn.chain.table.depth": "Depth",
|
||||||
|
"app.lthn.chain.table.difficulty": "Difficulty",
|
||||||
|
"app.lthn.chain.table.height": "Height",
|
||||||
|
"app.lthn.chain.table.reward": "Reward",
|
||||||
|
"app.lthn.chain.table.time": "Time",
|
||||||
|
"app.lthn.chain.table.title.chain-status": "Blockchain Status",
|
||||||
|
"app.lthn.chain.table.title.recent-blocks": "Recently Created Blocks",
|
||||||
|
"app.lthn.chain.title": "Blockchain Explorer",
|
||||||
|
"app.lthn.chain.words.alt_blocks_count": "Alt Blocks",
|
||||||
|
"app.lthn.chain.words.block_size": "Block Size",
|
||||||
|
"app.lthn.chain.words.block_size_limit": "Block Size Limit",
|
||||||
|
"app.lthn.chain.words.chain_stat": "Chain Stats",
|
||||||
|
"app.lthn.chain.words.chain_stat_value": "Node Reported Value",
|
||||||
|
"app.lthn.chain.words.cumulative_difficulty": "Cumulative Difficulty",
|
||||||
|
"app.lthn.chain.words.depth": "Depth from Top Block",
|
||||||
|
"app.lthn.chain.words.difficulty": "Difficulty",
|
||||||
|
"app.lthn.chain.words.grey_peerlist_size": "P2P Grey Peers",
|
||||||
|
"app.lthn.chain.words.hash": "Hash",
|
||||||
|
"app.lthn.chain.words.height": "Height",
|
||||||
|
"app.lthn.chain.words.incoming_connections_count": "P2P Incoming",
|
||||||
|
"app.lthn.chain.words.install-blockchain": "Install Blockchain",
|
||||||
|
"app.lthn.chain.words.last_block_time": "Synchronised to Block:",
|
||||||
|
"app.lthn.chain.words.loading-data": "Loading Blockchain Data",
|
||||||
|
"app.lthn.chain.words.major_version": "Major Version",
|
||||||
|
"app.lthn.chain.words.miner_transaction": "Miner Transaction",
|
||||||
|
"app.lthn.chain.words.miner_tx": "POW Miner Transaction",
|
||||||
|
"app.lthn.chain.words.minor_version": "Minor Version",
|
||||||
|
"app.lthn.chain.words.nonce": "Block Solution",
|
||||||
|
"app.lthn.chain.words.orphan_status": "Valid Block",
|
||||||
|
"app.lthn.chain.words.outgoing_connections_count": "P2P Out",
|
||||||
|
"app.lthn.chain.words.reward": "Reward",
|
||||||
|
"app.lthn.chain.words.start_time": "Start Time",
|
||||||
|
"app.lthn.chain.words.status": "Status",
|
||||||
|
"app.lthn.chain.words.target": "Target",
|
||||||
|
"app.lthn.chain.words.target_height": "Target Height",
|
||||||
|
"app.lthn.chain.words.testnet": "Testnet",
|
||||||
|
"app.lthn.chain.words.timestamp": "Timestamp",
|
||||||
|
"app.lthn.chain.words.top_height": "Newest Block",
|
||||||
|
"app.lthn.chain.words.tx_count": "Total Transactions",
|
||||||
|
"app.lthn.chain.words.tx_pool_size": "Pending Transactions",
|
||||||
|
"app.lthn.chain.words.unlock_time": "Unlock Block",
|
||||||
|
"app.lthn.chain.words.valid": "Valid Block",
|
||||||
|
"app.lthn.chain.words.version": "Block Structure Version",
|
||||||
|
"app.lthn.chain.words.white_peerlist_size": "P2P Whitelist",
|
||||||
|
"app.lthn.console.title": "Console",
|
||||||
|
"app.lthn.wallet.button.create-wallet": "Create Wallet",
|
||||||
|
"app.lthn.wallet.button.restore-wallet": "Restore Wallet",
|
||||||
|
"app.lthn.wallet.button.unlock-wallet": "Unlock",
|
||||||
|
"app.lthn.wallet.label.address": "Address",
|
||||||
|
"app.lthn.wallet.label.autosave": "Save Open Wallet",
|
||||||
|
"app.lthn.wallet.label.filename": "Filename",
|
||||||
|
"app.lthn.wallet.label.restore-height": "Restore Height",
|
||||||
|
"app.lthn.wallet.label.spend-key": "Spend Key",
|
||||||
|
"app.lthn.wallet.label.view-key": "View Key",
|
||||||
|
"app.lthn.wallet.label.wallet-password": "Wallet Password",
|
||||||
|
"app.lthn.wallet.label.wallet-password-confirm": "Confirm Password",
|
||||||
|
"app.lthn.wallet.titles.new-wallet": "Make New Wallet",
|
||||||
|
"app.lthn.wallet.titles.restore-keys": "Restore From Keys",
|
||||||
|
"app.lthn.wallet.titles.restore-seed": "Restore From Seed",
|
||||||
|
"app.lthn.wallet.titles.unlock-wallet": "Unlock Wallet",
|
||||||
|
"app.lthn.wallet.titles.wallet-transactions": "Wallet Transactions",
|
||||||
|
"app.market.apps": "App Marketplace",
|
||||||
|
"app.market.dashboard": "Dashboard",
|
||||||
|
"app.market.installed": "Installed Apps",
|
||||||
|
"app.market.no-apps-installed": "You have no apps installed.",
|
||||||
|
"app.market.view-installable-apps": "View Installable Apps",
|
||||||
|
"app.title": "Lethean Desktop",
|
||||||
|
"charts.network-hashrate.subtitle": "Data Provided by",
|
||||||
|
"charts.network-hashrate.title": "Network Hash Rate",
|
||||||
|
"lang.de": "German",
|
||||||
|
"lang.en": "English",
|
||||||
|
"lang.es": "Spanish",
|
||||||
|
"lang.fr": "French",
|
||||||
|
"lang.ru": "Russian",
|
||||||
|
"lang.uk": "Ukrainian (Ukraine)",
|
||||||
|
"lang.zh": "Chinese",
|
||||||
|
"menu.about": "About",
|
||||||
|
"menu.activity": "Activity",
|
||||||
|
"menu.api": "api",
|
||||||
|
"menu.blockchain": "Blockchain",
|
||||||
|
"menu.build": "Build",
|
||||||
|
"menu.dashboard": "Dashboard",
|
||||||
|
"menu.docs": "Documentation",
|
||||||
|
"menu.documentation": "Documentation",
|
||||||
|
"menu.explorer": "Explorer",
|
||||||
|
"menu.help": "Help",
|
||||||
|
"menu.hub-admin": "Admin Hub",
|
||||||
|
"menu.hub-client": "Client Hub",
|
||||||
|
"menu.hub-developer": "Developer",
|
||||||
|
"menu.hub-gateway": "Gateway",
|
||||||
|
"menu.hub-server": "Server Hub",
|
||||||
|
"menu.info": "info",
|
||||||
|
"menu.logout": "Sign Out",
|
||||||
|
"menu.mining": "Mining",
|
||||||
|
"menu.settings": "Settings",
|
||||||
|
"menu.vpn": "VPN",
|
||||||
|
"menu.wallet": "Wallet",
|
||||||
|
"menu.your-profile": "Your Profile",
|
||||||
|
"view.dashboard.description": "Lethean (LTHN) Web app",
|
||||||
|
"view.dashboard.heading": "Lethean Dashboard",
|
||||||
|
"view.dashboard.title": "Lethean (LTHN)",
|
||||||
|
"view.wallets.description": "Crypto Wallet Manager",
|
||||||
|
"view.wallets.heading": "Wallet Manager",
|
||||||
|
"view.wallets.title": "Wallets",
|
||||||
|
"words.actions.add": "Add",
|
||||||
|
"words.actions.clone": "Clone",
|
||||||
|
"words.actions.edit": "Edit",
|
||||||
|
"words.actions.install": "Install",
|
||||||
|
"words.actions.new": "New",
|
||||||
|
"words.actions.remove": "Remove",
|
||||||
|
"words.actions.report": "Report",
|
||||||
|
"words.actions.save": "Save",
|
||||||
|
"words.states.installing": "Installing",
|
||||||
|
"words.states.installing_desc": "We are downloading the blockchain executables from GitHub to your Lethean user directory.",
|
||||||
|
"words.states.loading": "Loading",
|
||||||
|
"words.states.not_installed": "Not Installed",
|
||||||
|
"words.states.not_installed_desc": "Click Install Blockchain to download the latest Lethean Blockchain CLI",
|
||||||
|
"words.things.button": "Button",
|
||||||
|
"words.things.documentation": "Documentation",
|
||||||
|
"words.things.menu": "Menu",
|
||||||
|
"words.things.mining-pool": "Mining Pool",
|
||||||
|
"words.things.page": "Page",
|
||||||
|
"words.things.problem": "Problem",
|
||||||
|
"words.things.type": "Type",
|
||||||
|
"words.time.past.day": "a day ago",
|
||||||
|
"words.time.past.days": "days ago",
|
||||||
|
"words.time.past.hour": "an hour ago",
|
||||||
|
"words.time.past.hours": "hours ago",
|
||||||
|
"words.time.past.minute": "a minute ago",
|
||||||
|
"words.time.past.minutes": "minutes ago",
|
||||||
|
"words.time.past.month": "a month ago",
|
||||||
|
"words.time.past.months": " months ago",
|
||||||
|
"words.time.past.seconds": "a few seconds ago",
|
||||||
|
"words.time.past.year": "a year ago",
|
||||||
|
"words.time.past.years": "years ago"
|
||||||
|
}
|
||||||
BIN
cmd/core-gui/frontend.old/public/icons/icon-128x128.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
cmd/core-gui/frontend.old/public/icons/icon-144x144.png
Normal file
|
After Width: | Height: | Size: 3 KiB |
BIN
cmd/core-gui/frontend.old/public/icons/icon-152x152.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
cmd/core-gui/frontend.old/public/icons/icon-192x192.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
cmd/core-gui/frontend.old/public/icons/icon-384x384.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
cmd/core-gui/frontend.old/public/icons/icon-512x512.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
cmd/core-gui/frontend.old/public/icons/icon-72x72.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
cmd/core-gui/frontend.old/public/icons/icon-96x96.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
57
cmd/core-gui/frontend.old/public/manifest.webmanifest
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
{
|
||||||
|
"name": "Core Framework",
|
||||||
|
"short_name": "Core",
|
||||||
|
"display": "standalone",
|
||||||
|
"scope": "./",
|
||||||
|
"start_url": "./",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icons/icon-72x72.png",
|
||||||
|
"sizes": "72x72",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/icon-96x96.png",
|
||||||
|
"sizes": "96x96",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/icon-128x128.png",
|
||||||
|
"sizes": "128x128",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/icon-144x144.png",
|
||||||
|
"sizes": "144x144",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/icon-152x152.png",
|
||||||
|
"sizes": "152x152",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/icon-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/icon-384x384.png",
|
||||||
|
"sizes": "384x384",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/icon-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable any"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
3
cmd/core-gui/frontend.old/public/robots.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
User-agent: *
|
||||||
|
Disallow:
|
||||||
|
Sitemap: /sitemap.xml
|
||||||
76
cmd/core-gui/frontend.old/public/sitemap.xml
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset
|
||||||
|
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
|
||||||
|
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
||||||
|
<!-- created with Free Online Sitemap Generator www.xml-sitemaps.com -->
|
||||||
|
|
||||||
|
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>1.00</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/about</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/contact</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/bootstrap</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/services</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/components</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/httpclient</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/forms</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/about/experience</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.64</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/about/skill</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.64</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/contact/mailing</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.64</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/contact/mapping</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.64</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://angular.ganatan.com/contact/website</loc>
|
||||||
|
<lastmod>2023-12-08T12:51:22+00:00</lastmod>
|
||||||
|
<priority>0.64</priority>
|
||||||
|
</url>
|
||||||
|
|
||||||
|
</urlset>
|
||||||
15
cmd/core-gui/frontend.old/src/app/app.config.server.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
|
||||||
|
import { provideServerRendering, withRoutes } from '@angular/ssr';
|
||||||
|
import { appConfig } from './app.config';
|
||||||
|
import { serverRoutes } from './app.routes.server';
|
||||||
|
import { TranslateLoader } from '@ngx-translate/core';
|
||||||
|
import { TranslateServerLoader } from './translate-server.loader';
|
||||||
|
|
||||||
|
const serverConfig: ApplicationConfig = {
|
||||||
|
providers: [
|
||||||
|
provideServerRendering(withRoutes(serverRoutes)),
|
||||||
|
{ provide: TranslateLoader, useClass: TranslateServerLoader }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const config = mergeApplicationConfig(appConfig, serverConfig);
|
||||||
42
cmd/core-gui/frontend.old/src/app/app.config.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChangeDetection, isDevMode, importProvidersFrom } from '@angular/core';
|
||||||
|
import { provideRouter } from '@angular/router';
|
||||||
|
import { HttpClient, provideHttpClient, withFetch } from '@angular/common/http';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { provideTranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||||
|
|
||||||
|
import { routes } from './app.routes';
|
||||||
|
import { withInMemoryScrolling } from '@angular/router';
|
||||||
|
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
|
||||||
|
import { provideServiceWorker } from '@angular/service-worker';
|
||||||
|
|
||||||
|
export const appConfig: ApplicationConfig = {
|
||||||
|
providers: [
|
||||||
|
provideHttpClient(
|
||||||
|
withFetch(),
|
||||||
|
),
|
||||||
|
provideBrowserGlobalErrorListeners(),
|
||||||
|
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||||
|
provideRouter(routes,
|
||||||
|
withInMemoryScrolling({
|
||||||
|
scrollPositionRestoration: 'enabled',
|
||||||
|
anchorScrolling: 'enabled',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
provideClientHydration(withEventReplay()),
|
||||||
|
provideServiceWorker('ngsw-worker.js', {
|
||||||
|
enabled: !isDevMode(),
|
||||||
|
registrationStrategy: 'registerWhenStable:30000'
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Add ngx-translate providers
|
||||||
|
importProvidersFrom(
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
fallbackLang: 'en'
|
||||||
|
})
|
||||||
|
),
|
||||||
|
provideTranslateHttpLoader({
|
||||||
|
prefix: './i18n/',
|
||||||
|
suffix: '.json'
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
0
cmd/core-gui/frontend.old/src/app/app.css
Normal file
140
cmd/core-gui/frontend.old/src/app/app.html
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
<wa-page mobile-breakpoint="960">
|
||||||
|
|
||||||
|
<!-- Shell: left nav + content -->
|
||||||
|
<div class="app-shell"
|
||||||
|
style="display: grid; grid-template-columns: 280px 1fr; min-height: calc(100vh - 56px - 56px);">
|
||||||
|
<!-- Left navigation drawer (collapsible) -->
|
||||||
|
<wa-drawer>
|
||||||
|
<nav slot="navigation">
|
||||||
|
<a routerLink="/" class="sidebar-link">Home</a>
|
||||||
|
<a routerLink="/domain-manager" class="sidebar-link">Send</a>
|
||||||
|
<a routerLink="/settings" class="sidebar-link">Settings</a>
|
||||||
|
<a routerLink="/" class="icon-item active" aria-label="Dashboard">
|
||||||
|
<i class="fas fa-home"></i>
|
||||||
|
</a>
|
||||||
|
<a routerLink="/team" class="icon-item" aria-label="Team">
|
||||||
|
<i class="fas fa-users"></i>
|
||||||
|
</a>
|
||||||
|
<a routerLink="/projects" class="icon-item" aria-label="Projects">
|
||||||
|
<i class="fas fa-briefcase"></i>
|
||||||
|
</a>
|
||||||
|
<a routerLink="/calendar" class="icon-item" aria-label="Calendar">
|
||||||
|
<i class="fas fa-calendar-alt"></i>
|
||||||
|
</a>
|
||||||
|
<a routerLink="/documents" class="icon-item" aria-label="Documents">
|
||||||
|
<i class="fas fa-file-alt"></i>
|
||||||
|
</a>
|
||||||
|
<a routerLink="/reports" class="icon-item" aria-label="Reports">
|
||||||
|
<i class="fas fa-chart-pie"></i>
|
||||||
|
</a>
|
||||||
|
<!-- Add more nav items as needed -->
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
|
</wa-drawer>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<app-footer slot="footer"></app-footer>
|
||||||
|
</wa-page>
|
||||||
|
|
||||||
|
|
||||||
|
<!--<!– Top-level wrapper using Web Awesome (no Tailwind) –>-->
|
||||||
|
<!--<div class="app-frame">-->
|
||||||
|
<!-- <!– Mobile sidebar via Drawer –>-->
|
||||||
|
<!-- <wa-drawer #mobileSidebar class="mobile-sidebar" placement="start" style="--size: 20rem;">-->
|
||||||
|
<!-- <div class="sidebar-inner">-->
|
||||||
|
<!-- <div class="brand-row">-->
|
||||||
|
<!-- <img src="https://tailwindcss.com/plus-assets/img/logos/mark.svg?color=indigo&shade=500" alt="Your Company" class="brand-logo" />-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <nav class="nav-list">-->
|
||||||
|
<!-- <a routerLink="/" class="nav-item active">-->
|
||||||
|
<!-- <i class="fas fa-home"></i>-->
|
||||||
|
<!-- <span>Dashboard</span>-->
|
||||||
|
<!-- </a>-->
|
||||||
|
<!-- <a routerLink="/team" class="nav-item">-->
|
||||||
|
<!-- <i class="fas fa-users"></i>-->
|
||||||
|
<!-- <span>Team</span>-->
|
||||||
|
<!-- </a>-->
|
||||||
|
<!-- <a routerLink="/projects" class="nav-item">-->
|
||||||
|
<!-- <i class="fas fa-briefcase"></i>-->
|
||||||
|
<!-- <span>Projects</span>-->
|
||||||
|
<!-- </a>-->
|
||||||
|
<!-- <a routerLink="/calendar" class="nav-item">-->
|
||||||
|
<!-- <i class="fas fa-calendar-alt"></i>-->
|
||||||
|
<!-- <span>Calendar</span>-->
|
||||||
|
<!-- </a>-->
|
||||||
|
<!-- <a routerLink="/documents" class="nav-item">-->
|
||||||
|
<!-- <i class="fas fa-file-alt"></i>-->
|
||||||
|
<!-- <span>Documents</span>-->
|
||||||
|
<!-- </a>-->
|
||||||
|
<!-- <a routerLink="/reports" class="nav-item">-->
|
||||||
|
<!-- <i class="fas fa-chart-pie"></i>-->
|
||||||
|
<!-- <span>Reports</span>-->
|
||||||
|
<!-- </a>-->
|
||||||
|
<!-- </nav>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </wa-drawer>-->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <!– Main column (left padding on lg for the fixed sidebar) –>-->
|
||||||
|
<!-- <div class="main-col">-->
|
||||||
|
<!-- <!– Topbar –>-->
|
||||||
|
<!-- <header class="topbar">-->
|
||||||
|
<!-- <wa-button variant="text" size="small" class="lg-hidden" (click)="onToggleSidebar()" aria-label="Open sidebar">-->
|
||||||
|
<!-- <i class="fas fa-bars"></i>-->
|
||||||
|
<!-- </wa-button>-->
|
||||||
|
|
||||||
|
<!-- <div class="topbar-sep lg-hidden" aria-hidden="true"></div>-->
|
||||||
|
|
||||||
|
<!-- <div class="topbar-flex">-->
|
||||||
|
<!-- <form class="search-form" role="search">-->
|
||||||
|
<!-- <wa-input placeholder="Search" size="small" pill>-->
|
||||||
|
<!-- <i slot="prefix" class="fas fa-search"></i>-->
|
||||||
|
<!-- </wa-input>-->
|
||||||
|
<!-- </form>-->
|
||||||
|
|
||||||
|
<!-- <div class="topbar-actions">-->
|
||||||
|
<!-- <wa-button variant="text" size="small" aria-label="View notifications">-->
|
||||||
|
<!-- <i class="fas fa-bell"></i>-->
|
||||||
|
<!-- </wa-button>-->
|
||||||
|
|
||||||
|
<!-- <div class="lg-sep" aria-hidden="true"></div>-->
|
||||||
|
|
||||||
|
<!-- <!– Profile dropdown –>-->
|
||||||
|
<!-- <wa-dropdown>-->
|
||||||
|
<!-- <wa-button slot="trigger" size="small" pill>-->
|
||||||
|
<!-- <img src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?auto=format&fit=facearea&facepad=2&w=48&h=48&q=80"-->
|
||||||
|
<!-- alt="" class="avatar" />-->
|
||||||
|
<!-- <span class="user-name lg-only">Tom Cook</span>-->
|
||||||
|
<!-- <i class="fas fa-chevron-down lg-only"></i>-->
|
||||||
|
<!-- </wa-button>-->
|
||||||
|
<!-- <wa-menu>-->
|
||||||
|
<!-- <wa-menu-item>Your profile</wa-menu-item>-->
|
||||||
|
<!-- <wa-menu-item>Sign out</wa-menu-item>-->
|
||||||
|
<!-- </wa-menu>-->
|
||||||
|
<!-- </wa-dropdown>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </header>-->
|
||||||
|
|
||||||
|
<!-- <!– Primary content area (single Angular outlet) –>-->
|
||||||
|
<!-- <main class="content">-->
|
||||||
|
<!-- <router-outlet></router-outlet>-->
|
||||||
|
<!-- </main>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
|
||||||
|
<!-- <!– Optional secondary aside on xl+ screens –>-->
|
||||||
|
<!-- <aside class="secondary-aside">-->
|
||||||
|
<!-- <!– Secondary column content (hidden on smaller screens) –>-->
|
||||||
|
<!-- </aside>-->
|
||||||
|
|
||||||
|
<!-- <!– Footer (existing component) –>-->
|
||||||
|
<!-- <app-footer></app-footer>-->
|
||||||
|
<!--</div>-->
|
||||||
|
|
||||||
|
|
||||||
8
cmd/core-gui/frontend.old/src/app/app.routes.server.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { RenderMode, ServerRoute } from '@angular/ssr';
|
||||||
|
|
||||||
|
export const serverRoutes: ServerRoute[] = [
|
||||||
|
{
|
||||||
|
path: '**',
|
||||||
|
renderMode: RenderMode.Prerender
|
||||||
|
}
|
||||||
|
];
|
||||||
25
cmd/core-gui/frontend.old/src/app/app.routes.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { Routes } from '@angular/router';
|
||||||
|
import { HomePage } from './pages/home/home.page';
|
||||||
|
import { SearchTldPage } from './pages/search-tld/search-tld.page';
|
||||||
|
import { OnboardingPage } from './pages/onboarding/onboarding.page';
|
||||||
|
import { SettingsPage } from './pages/settings/settings.page';
|
||||||
|
import { DomainManagerPage } from './pages/domain-manager/domain-manager.page';
|
||||||
|
import { ExchangePage } from './pages/exchange/exchange.page';
|
||||||
|
|
||||||
|
export const routes: Routes = [
|
||||||
|
{ path: '', redirectTo: '/account', pathMatch: 'full' },
|
||||||
|
{ path: 'account', component: HomePage, title: 'Portfolio • Bob Wallet' },
|
||||||
|
{ path: 'send', component: HomePage, title: 'Send • Bob Wallet' },
|
||||||
|
{ path: 'receive', component: HomePage, title: 'Receive • Bob Wallet' },
|
||||||
|
{ path: 'domain-manager', component: DomainManagerPage, title: 'Domain Manager • Bob Wallet' },
|
||||||
|
{ path: 'domains', component: SearchTldPage, title: 'Browse Domains • Bob Wallet' },
|
||||||
|
{ path: 'bids', component: HomePage, title: 'Your Bids • Bob Wallet' },
|
||||||
|
{ path: 'watching', component: HomePage, title: 'Watching • Bob Wallet' },
|
||||||
|
{ path: 'exchange', component: ExchangePage, title: 'Exchange • Bob Wallet' },
|
||||||
|
{ path: 'get-coins', component: HomePage, title: 'Claim Airdrop • Bob Wallet' },
|
||||||
|
{ path: 'sign-message', component: HomePage, title: 'Sign Message • Bob Wallet' },
|
||||||
|
{ path: 'verify-message', component: HomePage, title: 'Verify Message • Bob Wallet' },
|
||||||
|
{ path: 'settings', component: SettingsPage, title: 'Settings • Bob Wallet' },
|
||||||
|
{ path: 'onboarding', component: OnboardingPage, title: 'Onboarding • Bob Wallet' },
|
||||||
|
{ path: '**', redirectTo: '/account' }
|
||||||
|
];
|
||||||
24
cmd/core-gui/frontend.old/src/app/app.spec.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { App } from './app';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
|
||||||
|
describe('App', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [App],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ActivatedRoute,
|
||||||
|
useValue: {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(App);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
40
cmd/core-gui/frontend.old/src/app/app.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { Component, OnInit, Inject, PLATFORM_ID, CUSTOM_ELEMENTS_SCHEMA, ViewChild, ElementRef } from '@angular/core';
|
||||||
|
import { CommonModule, DOCUMENT, isPlatformBrowser } from '@angular/common';
|
||||||
|
import {RouterLink, RouterOutlet} from '@angular/router';
|
||||||
|
import { FooterComponent } from './shared/components/footer/footer.component';
|
||||||
|
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||||
|
import {Subscription} from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
RouterOutlet,
|
||||||
|
FooterComponent,
|
||||||
|
TranslateModule,
|
||||||
|
RouterLink
|
||||||
|
],
|
||||||
|
templateUrl: './app.html',
|
||||||
|
styleUrl: './app.css',
|
||||||
|
standalone: true,
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
})
|
||||||
|
export class App {
|
||||||
|
@ViewChild('sidebar', { read: ElementRef, static: false }) sidebar?: ElementRef<HTMLElement>;
|
||||||
|
|
||||||
|
sidebarOpen = false;
|
||||||
|
userMenuOpen = false;
|
||||||
|
currentRole = 'Developer';
|
||||||
|
|
||||||
|
time: string = '';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(DOCUMENT) private document: Document,
|
||||||
|
@Inject(PLATFORM_ID) private platformId: object,
|
||||||
|
private translateService: TranslateService
|
||||||
|
) {
|
||||||
|
// Set default language
|
||||||
|
this.translateService.use('en');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { } from "@awesome.me/webawesome/dist/webawesome.loader.js"
|
||||||
|
// This module enables Angular to accept unknown custom elements (Web Awesome components)
|
||||||
|
// without throwing template parse errors.
|
||||||
|
@NgModule({
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
})
|
||||||
|
export class CustomElementsModule {}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class ClipboardService {
|
||||||
|
async copyText(text: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// fall back
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback using a hidden textarea
|
||||||
|
const ta = document.createElement('textarea');
|
||||||
|
ta.value = text;
|
||||||
|
ta.style.position = 'fixed';
|
||||||
|
ta.style.left = '-9999px';
|
||||||
|
document.body.appendChild(ta);
|
||||||
|
ta.select();
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
document.body.removeChild(ta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
// WAILS3 INTEGRATION:
|
||||||
|
// This service currently uses web-standard File System Access API.
|
||||||
|
// For Wails3, replace with Go service methods calling:
|
||||||
|
// - application.OpenFileDialog().PromptForSingleSelection()
|
||||||
|
// - application.SaveFileDialog().SetFilename().PromptForSelection()
|
||||||
|
// See WAILS3_INTEGRATION.md for complete examples.
|
||||||
|
|
||||||
|
export interface OpenFileOptions {
|
||||||
|
multiple?: boolean;
|
||||||
|
accept?: string[]; // e.g., ["application/json", "text/plain"]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaveFileOptions {
|
||||||
|
suggestedName?: string;
|
||||||
|
types?: { description?: string; accept?: Record<string, string[]> }[];
|
||||||
|
blob: Blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class FileDialogService {
|
||||||
|
// Directory picker using File System Access API when available
|
||||||
|
async pickDirectory(): Promise<any | null> {
|
||||||
|
const nav: any = window.navigator;
|
||||||
|
if ((window as any).showDirectoryPicker) {
|
||||||
|
try {
|
||||||
|
// @ts-ignore
|
||||||
|
const handle: any = await (window as any).showDirectoryPicker({ mode: 'readwrite' });
|
||||||
|
return handle;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback: not supported in all browsers; inform the user
|
||||||
|
alert('Directory picker is not supported in this browser.');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open file(s) with <input type="file"> fallback if FS Access API not used
|
||||||
|
async openFile(opts: OpenFileOptions = {}): Promise<File[] | null> {
|
||||||
|
// Always supported fallback
|
||||||
|
return new Promise<File[] | null>((resolve) => {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.multiple = !!opts.multiple;
|
||||||
|
if (opts.accept && opts.accept.length) {
|
||||||
|
input.accept = opts.accept.join(',');
|
||||||
|
}
|
||||||
|
input.onchange = () => {
|
||||||
|
const files = input.files ? Array.from(input.files) : null;
|
||||||
|
resolve(files);
|
||||||
|
};
|
||||||
|
input.click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save file using File System Access API if available, otherwise trigger a download
|
||||||
|
async saveFile(opts: SaveFileOptions): Promise<File | null> {
|
||||||
|
if ((window as any).showSaveFilePicker) {
|
||||||
|
try {
|
||||||
|
// @ts-ignore
|
||||||
|
const handle = await (window as any).showSaveFilePicker({
|
||||||
|
suggestedName: opts.suggestedName,
|
||||||
|
types: opts.types
|
||||||
|
});
|
||||||
|
const writable = await handle.createWritable();
|
||||||
|
await writable.write(opts.blob);
|
||||||
|
await writable.close();
|
||||||
|
return { name: handle.name } as any;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: download
|
||||||
|
const url = URL.createObjectURL(opts.blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = opts.suggestedName || 'download';
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
return { name: opts.suggestedName || 'download' } as any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class HardwareWalletService {
|
||||||
|
// Placeholder for WebHID/WebUSB detection
|
||||||
|
get isWebHIDAvailable() {
|
||||||
|
return 'hid' in navigator;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isWebUSBAvailable() {
|
||||||
|
return 'usb' in navigator;
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectLedger(): Promise<void> {
|
||||||
|
// In a real implementation, prompt for a specific HID/USB device
|
||||||
|
// and establish transport (e.g., via @ledgerhq/hw-transport-webhid).
|
||||||
|
// This is a stub to document the integration point.
|
||||||
|
throw new Error('HardwareWalletService.connectLedger is not implemented in the web build.');
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAppVersion(): Promise<string> {
|
||||||
|
// Should query the connected device/app for version information
|
||||||
|
throw new Error('HardwareWalletService.getAppVersion is not implemented in the web build.');
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect(): Promise<void> {
|
||||||
|
// Close transport/session to the device
|
||||||
|
throw new Error('HardwareWalletService.disconnect is not implemented in the web build.');
|
||||||
|
}
|
||||||
|
}
|
||||||
233
cmd/core-gui/frontend.old/src/app/services/ipc/stubs.ts
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
// IPC Stub classes mapping old Electron IPC services and methods.
|
||||||
|
// These stubs let the web build compile and run without native IPC.
|
||||||
|
// Each method throws a NotImplementedError to highlight what needs
|
||||||
|
// to be replaced in a native wrapper or future web-compatible API.
|
||||||
|
//
|
||||||
|
// WAILS3 INTEGRATION:
|
||||||
|
// These stubs will be replaced by Wails3 auto-generated bindings.
|
||||||
|
// See WAILS3_INTEGRATION.md for complete migration guide.
|
||||||
|
//
|
||||||
|
// Pattern:
|
||||||
|
// 1. Create Go service structs with exported methods (e.g., NodeService, WalletService)
|
||||||
|
// 2. Register services in Wails3 main.go: application.NewService(&NodeService{})
|
||||||
|
// 3. Run `wails3 generate bindings` to create TypeScript bindings
|
||||||
|
// 4. Import generated bindings: import { GetInfo } from '../bindings/.../nodeservice'
|
||||||
|
// 5. Replace stub calls with binding calls: await GetInfo() instead of IPC.Node.getInfo()
|
||||||
|
//
|
||||||
|
// Each service below maps 1:1 to a Go service struct that will be created.
|
||||||
|
|
||||||
|
export class NotImplementedError extends Error {
|
||||||
|
constructor(message: string) {
|
||||||
|
super(message);
|
||||||
|
this.name = 'NotImplementedError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function notImplemented(service: string, method: string): never {
|
||||||
|
throw new NotImplementedError(`IPC ${service}.${method} is not implemented in the web build.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeIpcStub<T extends Record<string, any>>(service: string, methods: string[]): T {
|
||||||
|
const obj: Record<string, any> = {};
|
||||||
|
for (const m of methods) {
|
||||||
|
obj[m] = (..._args: any[]) => notImplemented(service, m);
|
||||||
|
}
|
||||||
|
return obj as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Services and their methods as defined in old/app/background/**/client.js
|
||||||
|
export const Node = makeIpcStub('Node', [
|
||||||
|
'start',
|
||||||
|
'stop',
|
||||||
|
'reset',
|
||||||
|
'generateToAddress',
|
||||||
|
'getAPIKey',
|
||||||
|
'getNoDns',
|
||||||
|
'getSpvMode',
|
||||||
|
'getInfo',
|
||||||
|
'getNameInfo',
|
||||||
|
'getTXByAddresses',
|
||||||
|
'getNameByHash',
|
||||||
|
'getBlockByHeight',
|
||||||
|
'getTx',
|
||||||
|
'broadcastRawTx',
|
||||||
|
'sendRawAirdrop',
|
||||||
|
'getFees',
|
||||||
|
'getAverageBlockTime',
|
||||||
|
'getMTP',
|
||||||
|
'getCoin',
|
||||||
|
'verifyMessageWithName',
|
||||||
|
'setNodeDir',
|
||||||
|
'setAPIKey',
|
||||||
|
'setNoDns',
|
||||||
|
'setSpvMode',
|
||||||
|
'getDir',
|
||||||
|
'getHNSPrice',
|
||||||
|
'testCustomRPCClient',
|
||||||
|
'getDNSSECProof',
|
||||||
|
'sendRawClaim',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const Wallet = makeIpcStub('Wallet', [
|
||||||
|
'start',
|
||||||
|
'getAPIKey',
|
||||||
|
'setAPIKey',
|
||||||
|
'getWalletInfo',
|
||||||
|
'getAccountInfo',
|
||||||
|
'getCoin',
|
||||||
|
'getTX',
|
||||||
|
'getNames',
|
||||||
|
'createNewWallet',
|
||||||
|
'importSeed',
|
||||||
|
'generateReceivingAddress',
|
||||||
|
'getAuctionInfo',
|
||||||
|
'getTransactionHistory',
|
||||||
|
'getPendingTransactions',
|
||||||
|
'getBids',
|
||||||
|
'getBlind',
|
||||||
|
'getMasterHDKey',
|
||||||
|
'hasAddress',
|
||||||
|
'setPassphrase',
|
||||||
|
'revealSeed',
|
||||||
|
'estimateTxFee',
|
||||||
|
'estimateMaxSend',
|
||||||
|
'removeWalletById',
|
||||||
|
'updateAccountDepth',
|
||||||
|
'findNonce',
|
||||||
|
'findNonceCancel',
|
||||||
|
'encryptWallet',
|
||||||
|
'backup',
|
||||||
|
'rescan',
|
||||||
|
'deepClean',
|
||||||
|
'reset',
|
||||||
|
'sendOpen',
|
||||||
|
'sendBid',
|
||||||
|
'sendRegister',
|
||||||
|
'sendUpdate',
|
||||||
|
'sendReveal',
|
||||||
|
'sendRedeem',
|
||||||
|
'sendRenewal',
|
||||||
|
'sendRevealAll',
|
||||||
|
'sendRedeemAll',
|
||||||
|
'sendRegisterAll',
|
||||||
|
'signMessageWithName',
|
||||||
|
'transferMany',
|
||||||
|
'finalizeAll',
|
||||||
|
'finalizeMany',
|
||||||
|
'renewAll',
|
||||||
|
'renewMany',
|
||||||
|
'sendTransfer',
|
||||||
|
'cancelTransfer',
|
||||||
|
'finalizeTransfer',
|
||||||
|
'finalizeWithPayment',
|
||||||
|
'claimPaidTransfer',
|
||||||
|
'revokeName',
|
||||||
|
'send',
|
||||||
|
'lock',
|
||||||
|
'unlock',
|
||||||
|
'isLocked',
|
||||||
|
'addSharedKey',
|
||||||
|
'removeSharedKey',
|
||||||
|
'getNonce',
|
||||||
|
'importNonce',
|
||||||
|
'zap',
|
||||||
|
'importName',
|
||||||
|
'rpcGetWalletInfo',
|
||||||
|
'loadTransaction',
|
||||||
|
'listWallets',
|
||||||
|
'getStats',
|
||||||
|
'isReady',
|
||||||
|
'createClaim',
|
||||||
|
'sendClaim',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const Setting = makeIpcStub('Setting', [
|
||||||
|
'getExplorer',
|
||||||
|
'setExplorer',
|
||||||
|
'getLocale',
|
||||||
|
'setLocale',
|
||||||
|
'getCustomLocale',
|
||||||
|
'setCustomLocale',
|
||||||
|
'getLatestRelease',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const Ledger = makeIpcStub('Ledger', [
|
||||||
|
'getXPub',
|
||||||
|
'getAppVersion',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const DB = makeIpcStub('DB', [
|
||||||
|
'open',
|
||||||
|
'close',
|
||||||
|
'put',
|
||||||
|
'get',
|
||||||
|
'del',
|
||||||
|
'getUserDir',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const Analytics = makeIpcStub('Analytics', [
|
||||||
|
'setOptIn',
|
||||||
|
'getOptIn',
|
||||||
|
'track',
|
||||||
|
'screenView',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const Connections = makeIpcStub('Connections', [
|
||||||
|
'getConnection',
|
||||||
|
'setConnection',
|
||||||
|
'setConnectionType',
|
||||||
|
'getCustomRPC',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const Shakedex = makeIpcStub('Shakedex', [
|
||||||
|
'fulfillSwap',
|
||||||
|
'getFulfillments',
|
||||||
|
'finalizeSwap',
|
||||||
|
'transferLock',
|
||||||
|
'transferCancel',
|
||||||
|
'getListings',
|
||||||
|
'finalizeLock',
|
||||||
|
'finalizeCancel',
|
||||||
|
'launchAuction',
|
||||||
|
'downloadProofs',
|
||||||
|
'restoreOneListing',
|
||||||
|
'restoreOneFill',
|
||||||
|
'getExchangeAuctions',
|
||||||
|
'listAuction',
|
||||||
|
'getFeeInfo',
|
||||||
|
'getBestBid',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const Claim = makeIpcStub('Claim', [
|
||||||
|
'airdropGenerateProofs',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const Logger = makeIpcStub('Logger', [
|
||||||
|
'info',
|
||||||
|
'warn',
|
||||||
|
'error',
|
||||||
|
'log',
|
||||||
|
'download',
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const Hip2 = makeIpcStub('Hip2', [
|
||||||
|
'getPort',
|
||||||
|
'setPort',
|
||||||
|
'fetchAddress',
|
||||||
|
'setServers',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Aggregate facade to import from components/services if needed
|
||||||
|
export const IPC = {
|
||||||
|
Node,
|
||||||
|
Wallet,
|
||||||
|
Setting,
|
||||||
|
Ledger,
|
||||||
|
DB,
|
||||||
|
Analytics,
|
||||||
|
Connections,
|
||||||
|
Shakedex,
|
||||||
|
Claim,
|
||||||
|
Logger,
|
||||||
|
Hip2,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class NotificationsService {
|
||||||
|
async requestPermission(): Promise<NotificationPermission> {
|
||||||
|
if (!('Notification' in window)) return 'denied';
|
||||||
|
if (Notification.permission === 'default') {
|
||||||
|
try {
|
||||||
|
return await Notification.requestPermission();
|
||||||
|
} catch {
|
||||||
|
return Notification.permission;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Notification.permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
async show(title: string, options?: NotificationOptions): Promise<void> {
|
||||||
|
if (!('Notification' in window)) return;
|
||||||
|
const perm = await this.requestPermission();
|
||||||
|
if (perm === 'granted') {
|
||||||
|
new Notification(title, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { InjectionToken } from '@angular/core';
|
||||||
|
|
||||||
|
export const BROWSER_STORAGE = new InjectionToken<Storage>('Browser Storage', {
|
||||||
|
providedIn: 'root',
|
||||||
|
factory: () => localStorage
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class StorageService {
|
||||||
|
private prefix = 'lthnDNS:';
|
||||||
|
|
||||||
|
setItem<T = unknown>(key: string, value: T): void {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(this.prefix + key, JSON.stringify(value));
|
||||||
|
} catch (e) {
|
||||||
|
// ignore quota or unsupported errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getItem<T = unknown>(key: string, fallback: T | null = null): T | null {
|
||||||
|
const raw = localStorage.getItem(this.prefix + key);
|
||||||
|
if (!raw) return fallback;
|
||||||
|
try {
|
||||||
|
return JSON.parse(raw) as T;
|
||||||
|
} catch {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItem(key: string): void {
|
||||||
|
localStorage.removeItem(this.prefix + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearAll(): void {
|
||||||
|
Object.keys(localStorage)
|
||||||
|
.filter(k => k.startsWith(this.prefix))
|
||||||
|
.forEach(k => localStorage.removeItem(k));
|
||||||
|
}
|
||||||
|
}
|
||||||
14
cmd/core-gui/frontend.old/src/app/translate-server.loader.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { join } from 'path';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
import { TranslateLoader } from '@ngx-translate/core';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
export class TranslateServerLoader implements TranslateLoader {
|
||||||
|
constructor(private prefix: string = 'i18n', private suffix: string = '.json') {}
|
||||||
|
|
||||||
|
public getTranslation(lang: string): Observable<any> {
|
||||||
|
const path = join(process.cwd(), 'i18n', this.prefix, `${lang}${this.suffix}`);
|
||||||
|
const data = JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||||
|
return of(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
export const appVersion = '250905-1502';
|
||||||
|
|
||||||
|
export const appInfo = {
|
||||||
|
name: 'Core',
|
||||||
|
logo: 'ganatan',
|
||||||
|
network: 'ganatan',
|
||||||
|
xnetwork: 'dannyganatan',
|
||||||
|
linkedinnetwork: 'dannyganatan',
|
||||||
|
website: 'www.ganatan.com',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const applicationBase = {
|
||||||
|
name: 'angular-starter',
|
||||||
|
angular: 'Angular 20.3.2',
|
||||||
|
bootstrap: 'Bootstrap 5.3.8',
|
||||||
|
fontawesome: 'Font Awesome 7.0.1',
|
||||||
|
};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { appInfo, applicationBase } from './environment.common';
|
||||||
|
|
||||||
|
export const environment = {
|
||||||
|
appInfo,
|
||||||
|
application: {
|
||||||
|
...applicationBase,
|
||||||
|
angular: `${applicationBase.angular} DEV`,
|
||||||
|
},
|
||||||
|
urlNews: './assets/params/json/mock/trailers.json',
|
||||||
|
urlMovies: './assets/params/json/mock/movies.json',
|
||||||
|
useMock: true,
|
||||||
|
backend: 'http://localhost:3000',
|
||||||
|
};
|
||||||
13
cmd/core-gui/frontend.old/src/environments/environment.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { appInfo, applicationBase } from './environment.common';
|
||||||
|
|
||||||
|
export const environment = {
|
||||||
|
appInfo,
|
||||||
|
application: {
|
||||||
|
...applicationBase,
|
||||||
|
angular: `${applicationBase.angular} PROD`,
|
||||||
|
},
|
||||||
|
urlNews: './assets/params/json/mock/trailers.json',
|
||||||
|
urlMovies: './assets/params/json/mock/movies.json',
|
||||||
|
useMock: true,
|
||||||
|
backend: 'http://localhost:3000',
|
||||||
|
};
|
||||||
21
cmd/core-gui/frontend.old/src/index.html
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en" class="wa-theme-premium wa-palette-vogue wa-brand-indigo">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>LTHN - Layered Transmission Host Network</title>
|
||||||
|
<base href="/">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
<!-- <link rel="stylesheet" href="/assets/web-awesome/styles/webawesome.css" />-->
|
||||||
|
<!-- <link rel="stylesheet" href="/assets/web-awesome/styles/themes/premium.css" />-->
|
||||||
|
<!-- <link rel="stylesheet" href="/assets/web-awesome/styles/native.css" />-->
|
||||||
|
<!-- <link rel="stylesheet" href="/assets/web-awesome/styles/utilities.css" />-->
|
||||||
|
<!-- <link rel="stylesheet" href="/assets/web-awesome/styles/color/vairants.css" />-->
|
||||||
|
<link rel="manifest" href="manifest.webmanifest">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
<noscript>Please enable JavaScript to continue using this application.</noscript>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
8
cmd/core-gui/frontend.old/src/main.server.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { BootstrapContext, bootstrapApplication } from '@angular/platform-browser';
|
||||||
|
import { App } from './app/app';
|
||||||
|
import { config } from './app/app.config.server';
|
||||||
|
|
||||||
|
const bootstrap = (context: BootstrapContext) =>
|
||||||
|
bootstrapApplication(App, config, context);
|
||||||
|
|
||||||
|
export default bootstrap;
|
||||||
5
cmd/core-gui/frontend.old/src/main.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { bootstrapApplication } from '@angular/platform-browser';
|
||||||
|
import { appConfig } from './app/app.config';
|
||||||
|
import { App } from './app/app';
|
||||||
|
bootstrapApplication(App, appConfig)
|
||||||
|
.catch((err) => console.error(err));
|
||||||
68
cmd/core-gui/frontend.old/src/server.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
import {
|
||||||
|
AngularNodeAppEngine,
|
||||||
|
createNodeRequestHandler,
|
||||||
|
isMainModule,
|
||||||
|
writeResponseToNodeResponse,
|
||||||
|
} from '@angular/ssr/node';
|
||||||
|
import express from 'express';
|
||||||
|
import { join } from 'node:path';
|
||||||
|
|
||||||
|
const browserDistFolder = join(import.meta.dirname, '../browser');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const angularApp = new AngularNodeAppEngine();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example Express Rest API endpoints can be defined here.
|
||||||
|
* Uncomment and define endpoints as necessary.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* ```ts
|
||||||
|
* app.get('/api/{*splat}', (req, res) => {
|
||||||
|
* // Handle API request
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve static files from /browser
|
||||||
|
*/
|
||||||
|
app.use(
|
||||||
|
express.static(browserDistFolder, {
|
||||||
|
maxAge: '1y',
|
||||||
|
index: false,
|
||||||
|
redirect: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle all other requests by rendering the Angular application.
|
||||||
|
*/
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
angularApp
|
||||||
|
.handle(req)
|
||||||
|
.then((response) =>
|
||||||
|
response ? writeResponseToNodeResponse(response, res) : next(),
|
||||||
|
)
|
||||||
|
.catch(next);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the server if this module is the main entry point.
|
||||||
|
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
|
||||||
|
*/
|
||||||
|
if (isMainModule(import.meta.url)) {
|
||||||
|
const port = process.env['PORT'] || 4000;
|
||||||
|
app.listen(port, (error) => {
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Node Express server listening on http://localhost:${port}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request handler used by the Angular CLI (for dev-server and during build) or Firebase Cloud Functions.
|
||||||
|
*/
|
||||||
|
export const reqHandler = createNodeRequestHandler(app);
|
||||||
13
cmd/core-gui/frontend.old/src/styles.css
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
@import "@awesome.me/webawesome/dist/styles/webawesome.css";
|
||||||
|
@import "@awesome.me/webawesome/dist/styles/themes/premium.css";
|
||||||
|
@import "@awesome.me/webawesome/dist/styles/native.css";
|
||||||
|
@import "@awesome.me/webawesome/dist/styles/utilities.css";
|
||||||
|
@import "@awesome.me/webawesome/dist/styles/color/palettes/vogue.css";
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
min-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
38
cmd/core-gui/frontend.old/src/test.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import 'zone.js/testing';
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { TranslateService, TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { Observable, of } from 'rxjs';
|
||||||
|
|
||||||
|
// Provide TranslateService mock globally for tests to avoid NG0201 in standalone components
|
||||||
|
(() => {
|
||||||
|
class FakeTranslateLoader implements TranslateLoader {
|
||||||
|
getTranslation(lang: string): Observable<any> { return of({}); }
|
||||||
|
}
|
||||||
|
|
||||||
|
const translateServiceMock: Partial<TranslateService> = {
|
||||||
|
use: (() => ({ toPromise: async () => undefined })) as any,
|
||||||
|
instant: ((key: string) => key) as any,
|
||||||
|
get: (((key: any) => ({ subscribe: (fn: any) => fn(key) })) as any),
|
||||||
|
onLangChange: { subscribe: () => ({ unsubscribe() {} }) } as any,
|
||||||
|
} as Partial<TranslateService>;
|
||||||
|
|
||||||
|
// Patch TestBed.configureTestingModule to always include Translate support
|
||||||
|
const originalConfigure = TestBed.configureTestingModule.bind(TestBed);
|
||||||
|
(TestBed as any).configureTestingModule = (meta: any = {}) => {
|
||||||
|
// Ensure providers include TranslateService mock if not already provided
|
||||||
|
const providers = meta.providers ?? [];
|
||||||
|
const hasTranslateProvider = providers.some((p: any) => p && (p.provide === TranslateService));
|
||||||
|
meta.providers = hasTranslateProvider ? providers : [...providers, { provide: TranslateService, useValue: translateServiceMock }];
|
||||||
|
|
||||||
|
// Ensure imports include TranslateModule.forRoot with a fake loader (brings internal _TranslateService)
|
||||||
|
const imports = meta.imports ?? [];
|
||||||
|
const hasTranslateModule = imports.some((imp: any) => imp && (imp === TranslateModule || (imp.ngModule && imp.ngModule === TranslateModule)));
|
||||||
|
if (!hasTranslateModule) {
|
||||||
|
imports.push(TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: FakeTranslateLoader } }));
|
||||||
|
}
|
||||||
|
meta.imports = imports;
|
||||||
|
|
||||||
|
return originalConfigure(meta);
|
||||||
|
};
|
||||||
|
})();
|
||||||
31
cmd/core-gui/frontend.old/src/testing/gbu.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Good/Bad/Ugly test helpers for Jasmine
|
||||||
|
// Usage:
|
||||||
|
// import { itGood, itBad, itUgly, trio } from 'src/testing/gbu';
|
||||||
|
// itGood('does X', () => { /* ... */ });
|
||||||
|
// trio('feature does Y', {
|
||||||
|
// good: () => { /* ... */ },
|
||||||
|
// bad: () => { /* ... */ },
|
||||||
|
// ugly: () => { /* ... */ },
|
||||||
|
// });
|
||||||
|
|
||||||
|
export function suffix(base: string, tag: 'Good' | 'Bad' | 'Ugly'): string {
|
||||||
|
return `${base}_${tag}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function itGood(name: string, fn: jasmine.ImplementationCallback, timeout?: number): void {
|
||||||
|
it(suffix(name, 'Good'), fn, timeout as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function itBad(name: string, fn: jasmine.ImplementationCallback, timeout?: number): void {
|
||||||
|
it(suffix(name, 'Bad'), fn, timeout as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function itUgly(name: string, fn: jasmine.ImplementationCallback, timeout?: number): void {
|
||||||
|
it(suffix(name, 'Ugly'), fn, timeout as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trio(name: string, impls: { good: () => void; bad: () => void; ugly: () => void; }): void {
|
||||||
|
itGood(name, impls.good);
|
||||||
|
itBad(name, impls.bad);
|
||||||
|
itUgly(name, impls.ugly);
|
||||||
|
}
|
||||||
20
cmd/core-gui/frontend.old/tsconfig.app.json
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||||
|
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/app",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
"./node_modules/@awesome.me/webawesome/dist/custom-elements-jsx.d.ts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/testing/**/*.ts",
|
||||||
|
"src/test.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
35
cmd/core-gui/frontend.old/tsconfig.json
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||||
|
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"lib": [ "ES2022", "DOM"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"importHelpers": true,
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "preserve",
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"enableI18nLegacyMessageIdFormat": false,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"strictInputAccessModifiers": true,
|
||||||
|
"typeCheckHostBindings": true,
|
||||||
|
"strictTemplates": true
|
||||||
|
},
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
18
cmd/core-gui/frontend.old/tsconfig.spec.json
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
|
||||||
|
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine"
|
||||||
|
],
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"src/*": ["src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
5
cmd/core-gui/frontend/.postcssrc.json
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"plugins": {
|
||||||
|
"@tailwindcss/postcss": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,69 +1,59 @@
|
||||||
### Installation
|
# Frontend
|
||||||
- `npm install` (install dependencies)
|
|
||||||
- `npm outdated` (verify dependency status)
|
|
||||||
|
|
||||||
### Development
|
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.3.6.
|
||||||
- `npm run start`
|
|
||||||
- Visit http://localhost:4200
|
|
||||||
|
|
||||||
## Lint
|
## Development server
|
||||||
- `npm run lint`
|
|
||||||
|
|
||||||
## Tests (headless-ready, no Chrome required)
|
To start a local development server, run:
|
||||||
- Unit/integration: `npm run test` (opens browser), or:
|
|
||||||
- Headless (uses Puppeteer Chromium): `npm run test:headless`
|
|
||||||
- Coverage report (HTML + text-summary): `npm run coverage`
|
|
||||||
- Coverage thresholds are enforced in Karma (≈80% statements/lines/functions, 70% branches for global). Adjust in `karma.conf.js` if needed.
|
|
||||||
|
|
||||||
### TDD workflow and test naming (Good/Bad/Ugly)
|
```bash
|
||||||
- Follow strict TDD:
|
ng serve
|
||||||
1) Write failing tests from user stories + acceptance criteria
|
```
|
||||||
2) Implement minimal code to pass
|
|
||||||
3) Refactor
|
|
||||||
- Test case naming convention: each logical test should have three variants to clarify intent and data quality.
|
|
||||||
- Example helpers in `src/testing/gbu.ts`:
|
|
||||||
```ts
|
|
||||||
import { itGood, itBad, itUgly, trio } from 'src/testing/gbu';
|
|
||||||
|
|
||||||
itGood('saves profile', () => {/* valid data */});
|
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
|
||||||
itBad('saves profile', () => {/* incorrect data (edge) */});
|
|
||||||
itUgly('saves profile', () => {/* invalid data/conditions */});
|
|
||||||
|
|
||||||
// Or use trio
|
## Code scaffolding
|
||||||
trio('process order', {
|
|
||||||
good: () => {/* ... */},
|
|
||||||
bad: () => {/* ... */},
|
|
||||||
ugly: () => {/* ... */},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
- Do not modify router-outlet containers in tests/components.
|
|
||||||
|
|
||||||
### Standalone Angular 20+ patterns (migration notes)
|
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||||
- This app is moving to Angular standalone APIs. Prefer:
|
|
||||||
- Standalone components (`standalone: true`, add `imports: []` per component)
|
|
||||||
- `provideRouter(...)`, `provideHttpClient(...)`, `provideServiceWorker(...)` in `app.config.ts`
|
|
||||||
- Translation is configured via `app.config.ts` using `TranslateModule.forRoot(...)` and an HTTP loader.
|
|
||||||
- Legacy NgModules should be converted progressively. If an `NgModule` remains but is unrouted/unreferenced, keep it harmlessly until deletion is approved. Do not alter the main router-outlet page context panel.
|
|
||||||
|
|
||||||
### Web Awesome + Font Awesome (Pro)
|
```bash
|
||||||
- Both Font Awesome and Web Awesome are integrated. Do not remove. Web Awesome assets are copied via `angular.json` assets, and its base path is set at runtime in `app.ts`:
|
ng generate component component-name
|
||||||
```ts
|
```
|
||||||
import('@awesome.me/webawesome').then(m => m.setBasePath('/assets/web-awesome'));
|
|
||||||
```
|
|
||||||
- CSS includes are defined in `angular.json` and `src/styles.css`.
|
|
||||||
|
|
||||||
### SSR and production
|
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||||
- Build (browser + server): `npm run build`
|
|
||||||
- Serve SSR bundle: `npm run serve` → http://localhost:4000
|
|
||||||
|
|
||||||
### Notes for other LLMs / contributors
|
```bash
|
||||||
- Respect the constraints:
|
ng generate --help
|
||||||
- Do NOT edit the router-outlet main panel; pages/services are the focus
|
```
|
||||||
- Preserve existing functionality; do not remove Web Awesome/Font Awesome
|
|
||||||
- Use strict TDD and Good/Bad/Ugly naming for tests
|
|
||||||
- Keep or improve code coverage ≥ configured thresholds for changed files
|
|
||||||
- Use Angular 20+ standalone patterns; update `app.config.ts` for global providers.
|
|
||||||
- For tests, prefer headless runs via Puppeteer (no local Chrome needed).
|
|
||||||
|
|
||||||
### Author
|
## Building
|
||||||
- Author: danny
|
|
||||||
|
To build the project run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng build
|
||||||
|
```
|
||||||
|
|
||||||
|
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
For end-to-end (e2e) testing, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ng e2e
|
||||||
|
```
|
||||||
|
|
||||||
|
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,13 @@
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"newProjectRoot": "projects",
|
"newProjectRoot": "projects",
|
||||||
"projects": {
|
"projects": {
|
||||||
"lthn.io": {
|
"frontend": {
|
||||||
"projectType": "application",
|
"projectType": "application",
|
||||||
"schematics": {},
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"style": "scss"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": "",
|
"root": "",
|
||||||
"sourceRoot": "src",
|
"sourceRoot": "src",
|
||||||
"prefix": "app",
|
"prefix": "app",
|
||||||
|
|
@ -14,38 +18,56 @@
|
||||||
"builder": "@angular/build:application",
|
"builder": "@angular/build:application",
|
||||||
"options": {
|
"options": {
|
||||||
"browser": "src/main.ts",
|
"browser": "src/main.ts",
|
||||||
"polyfills": [
|
|
||||||
"zone.js"
|
|
||||||
],
|
|
||||||
"tsConfig": "tsconfig.app.json",
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"polyfills": ["src/polyfills.ts"],
|
||||||
|
"inlineStyleLanguage": "scss",
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
"input": "public"
|
"input": "public"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"glob": "@awesome.me/webawesome/**/*.*",
|
"glob": "fa-{brands,jelly,thin,light,regular,solid}*.woff2",
|
||||||
"input": "node_modules/",
|
"input": "node_modules/@fortawesome/fontawesome-free/webfonts",
|
||||||
|
"output": "webfonts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*.*",
|
||||||
|
"input": "node_modules/@awesome.me/webawesome/dist",
|
||||||
|
"output": "@awesome.me/webawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*.*",
|
||||||
|
"input": "bindings",
|
||||||
"output": "/"
|
"output": "/"
|
||||||
},
|
},
|
||||||
"src/sitemap.xml",
|
{ "glob": "**/*", "input": "node_modules/monaco-editor", "output": "/assets/monaco/" },
|
||||||
"src/robots.txt"
|
{ "glob": "**/*", "input": "../services/docs/static", "output": "docs" },
|
||||||
|
{
|
||||||
|
"glob": "**/*.json",
|
||||||
|
"input": "../services/core/i18n/locales",
|
||||||
|
"output": "assets/i18n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scripts": [
|
||||||
|
"node_modules/@tailwindplus/elements/dist/index.js"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"node_modules/@fortawesome/fontawesome-free/css/all.min.css",
|
"src/styles.scss"
|
||||||
"src/styles.css"
|
]
|
||||||
],
|
|
||||||
"scripts": [],
|
|
||||||
"define": {
|
|
||||||
"import.meta.vitest": "undefined"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
"budgets": [
|
"budgets": [
|
||||||
{
|
{
|
||||||
"type": "initial",
|
"type": "initial",
|
||||||
"maximumWarning": "1MB",
|
"maximumWarning": "500kB",
|
||||||
"maximumError": "1MB"
|
"maximumError": "1MB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -54,36 +76,24 @@
|
||||||
"maximumError": "8kB"
|
"maximumError": "8kB"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"outputHashing": "all",
|
"outputHashing": "all"
|
||||||
"serviceWorker": "ngsw-config.json",
|
|
||||||
"server": "src/main.server.ts",
|
|
||||||
"outputMode": "server",
|
|
||||||
"ssr": {
|
|
||||||
"entry": "src/server.ts"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"development": {
|
"development": {
|
||||||
"optimization": false,
|
"optimization": false,
|
||||||
"extractLicenses": false,
|
"extractLicenses": false,
|
||||||
"sourceMap": true,
|
"sourceMap": true
|
||||||
"fileReplacements": [
|
|
||||||
{
|
|
||||||
"replace": "src/environments/environment.ts",
|
|
||||||
"with": "src/environments/environment.development.ts"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultConfiguration": "development"
|
"defaultConfiguration": "production"
|
||||||
},
|
},
|
||||||
"serve": {
|
"serve": {
|
||||||
"builder": "@angular/build:dev-server",
|
"builder": "@angular/build:dev-server",
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
"buildTarget": "lthn.io:build:production"
|
"buildTarget": "frontend:build:production"
|
||||||
},
|
},
|
||||||
"development": {
|
"development": {
|
||||||
"buildTarget": "lthn.io:build:development"
|
"buildTarget": "frontend:build:development"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultConfiguration": "development"
|
"defaultConfiguration": "development"
|
||||||
|
|
@ -94,12 +104,8 @@
|
||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular/build:karma",
|
"builder": "@angular/build:karma",
|
||||||
"options": {
|
"options": {
|
||||||
"polyfills": [
|
|
||||||
"zone.js",
|
|
||||||
"zone.js/testing",
|
|
||||||
"src/test.ts"
|
|
||||||
],
|
|
||||||
"tsConfig": "tsconfig.spec.json",
|
"tsConfig": "tsconfig.spec.json",
|
||||||
|
"inlineStyleLanguage": "scss",
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
|
|
@ -107,16 +113,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"src/styles.css"
|
"src/styles.scss"
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"builder": "@angular-eslint/builder:lint",
|
|
||||||
"options": {
|
|
||||||
"lintFilePatterns": [
|
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.html"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -124,9 +121,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cli": {
|
"cli": {
|
||||||
"schematicCollections": [
|
|
||||||
"angular-eslint"
|
|
||||||
],
|
|
||||||
"analytics": false
|
"analytics": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5278
cmd/core-gui/frontend/package-lock.json
generated
|
|
@ -1,60 +1,66 @@
|
||||||
{
|
{
|
||||||
"name": "lthn.io",
|
"name": "frontend",
|
||||||
"version": "20.3.2",
|
"version": "0.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"dev": "ng serve --port 4200",
|
"start": "ng serve",
|
||||||
"start": "ng serve --port 4200",
|
"dev": "ng serve --configuration development",
|
||||||
"build": "ng build",
|
"build": "ng build",
|
||||||
|
"build:dev": "ng build --configuration development",
|
||||||
"watch": "ng build --watch --configuration development",
|
"watch": "ng build --watch --configuration development",
|
||||||
"preview": "http-server ./dist/lthn-dns-web/browser -o",
|
|
||||||
"puppeteer:install": "npx puppeteer browsers install chrome || true",
|
|
||||||
"test": "ng test",
|
"test": "ng test",
|
||||||
"test:headless": "(export CHROME_BIN=\"$(node -e \"console.log(require('puppeteer').executablePath())\")\"; ng test --no-watch --code-coverage=false --browsers=ChromeHeadless) || (npm run puppeteer:install && export CHROME_BIN=\"$(node -e \"console.log(require('puppeteer').executablePath())\")\" && ng test --no-watch --code-coverage=false --browsers=ChromeHeadless)",
|
"wa-link": "cd ~/Code/lib/webawesome && npm link && cd - && npm link @awesome.me/webawesome",
|
||||||
"coverage": "(export CHROME_BIN=\"$(node -e \"console.log(require('puppeteer').executablePath())\")\"; ng test --no-watch --code-coverage --browsers=ChromeHeadless) || (npm run puppeteer:install && export CHROME_BIN=\"$(node -e \"console.log(require('puppeteer').executablePath())\")\" && ng test --no-watch --code-coverage --browsers=ChromeHeadless)",
|
"fa-link": "cd ~/Code/lib/fontawesome/npm && npm link && cd - && npm link @fortawesome/fontawesome-free"
|
||||||
"lint": "ng lint",
|
},
|
||||||
"serve": "node dist/angular-starter/server/server.mjs"
|
"prettier": {
|
||||||
|
"printWidth": 100,
|
||||||
|
"singleQuote": true,
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.html",
|
||||||
|
"options": {
|
||||||
|
"parser": "angular"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/common": "^20.3.2",
|
"@angular/common": "^20.3.16",
|
||||||
"@angular/compiler": "^20.3.2",
|
"@angular/compiler": "^20.3.16",
|
||||||
"@angular/core": "^20.3.2",
|
"@angular/core": "^20.3.16",
|
||||||
"@angular/forms": "^20.3.2",
|
"@angular/forms": "^20.3.16",
|
||||||
"@angular/platform-browser": "^20.3.2",
|
"@angular/platform-browser": "^20.3.16",
|
||||||
"@angular/platform-server": "^20.3.2",
|
"@angular/router": "^20.3.16",
|
||||||
"@angular/router": "^20.3.2",
|
"@awesome.me/webawesome": "^3.0.0",
|
||||||
"@angular/service-worker": "^20.3.2",
|
|
||||||
"@angular/ssr": "^20.3.3",
|
|
||||||
"@awesome.me/kit-2e7e02d1b1": "^1.0.6",
|
|
||||||
"@awesome.me/webawesome": "file:~/Code/lib/webawesome",
|
|
||||||
"@fortawesome/fontawesome-free": "^7.0.1",
|
"@fortawesome/fontawesome-free": "^7.0.1",
|
||||||
"@ngx-translate/core": "^17.0.0",
|
"@ngx-translate/core": "^17.0.0",
|
||||||
"@ngx-translate/http-loader": "^17.0.0",
|
"@ngx-translate/http-loader": "^17.0.0",
|
||||||
"bootstrap": "^5.3.8",
|
"@tailwindplus/elements": "^1.0.18",
|
||||||
"express": "^5.1.0",
|
"@wailsio/runtime": "^3.0.0-alpha.72",
|
||||||
"rxjs": "^7.8.2",
|
"highcharts": "^12.4.0",
|
||||||
"tslib": "^2.8.1",
|
"highcharts-angular": "^5.1.0",
|
||||||
"uuid": "^13.0.0",
|
"monaco-editor": "^0.52.2",
|
||||||
|
"ngx-monaco-editor-v2": "^20.3.0",
|
||||||
|
"rxjs": "~7.8.0",
|
||||||
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "^0.15.1"
|
"zone.js": "^0.15.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/build": "^20.3.3",
|
"@angular/build": "^20.3.14",
|
||||||
"@angular/cli": "^20.3.3",
|
"@angular/cli": "^20.3.6",
|
||||||
"@angular/compiler-cli": "^20.3.2",
|
"@angular/compiler-cli": "^20.3.16",
|
||||||
"@types/express": "^5.0.3",
|
"@tailwindcss/postcss": "^4.1.14",
|
||||||
"@types/jasmine": "^5.1.9",
|
"@types/jasmine": "~5.1.0",
|
||||||
"@types/node": "^24.6.0",
|
"autoprefixer": "^10.4.21",
|
||||||
"angular-eslint": "^20.3.0",
|
"jasmine-core": "~5.9.0",
|
||||||
"eslint": "^9.36.0",
|
"karma": "~6.4.0",
|
||||||
"jasmine-core": "^5.11.0",
|
"karma-chrome-launcher": "~3.2.0",
|
||||||
"karma": "^6.4.4",
|
"karma-coverage": "~2.2.0",
|
||||||
"karma-chrome-launcher": "^3.2.0",
|
"karma-jasmine": "~5.1.0",
|
||||||
"karma-coverage": "^2.2.1",
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
"karma-jasmine": "^5.1.0",
|
"postcss": "^8.5.6",
|
||||||
"karma-jasmine-html-reporter": "^2.1.0",
|
"tailwindcss": "^4.1.14",
|
||||||
"puppeteer": "^23.7.0",
|
"typescript": "~5.9.2"
|
||||||
"typescript": "~5.8.3",
|
|
||||||
"typescript-eslint": "^8.45.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
15
cmd/core-gui/frontend/public/assets/i18n/en.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"menu.dashboard": "Dashboard",
|
||||||
|
"menu.mining": "Mining",
|
||||||
|
"menu.blockchain": "Blockchain",
|
||||||
|
"Developer": "Developer",
|
||||||
|
"Networking": "Networking",
|
||||||
|
"Settings": "Settings",
|
||||||
|
"menu.hub-client": "Client Hub",
|
||||||
|
"menu.hub-server": "Server Hub",
|
||||||
|
"menu.hub-developer": "Developer Hub",
|
||||||
|
"menu.hub-gateway": "Gateway Hub",
|
||||||
|
"menu.hub-admin": "Admin Hub",
|
||||||
|
"menu.your-profile": "Your Profile",
|
||||||
|
"menu.logout": "Logout"
|
||||||
|
}
|
||||||
BIN
cmd/core-gui/frontend/public/avatar.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
cmd/core-gui/frontend/public/logo/lthn/bg-logo-black.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
cmd/core-gui/frontend/public/logo/lthn/bg-logo-gradient.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
cmd/core-gui/frontend/public/logo/lthn/bg-logo-white.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
cmd/core-gui/frontend/public/logo/lthn/hoplite-icon-128.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
cmd/core-gui/frontend/public/logo/lthn/hoplite-icon-256.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
cmd/core-gui/frontend/public/logo/lthn/hoplite-icon-512.png
Normal file
|
After Width: | Height: | Size: 77 KiB |