init projectmycelium
This commit is contained in:
345
src/views/dashboard/app_provider.html
Normal file
345
src/views/dashboard/app_provider.html
Normal file
@@ -0,0 +1,345 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - App Provider{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<h1>App Provider Dashboard</h1>
|
||||
<p class="lead">Develop, deploy, and manage applications for the ThreeFold ecosystem</p>
|
||||
|
||||
<!-- Status Summary -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card info">
|
||||
<h5 class="card-title">Published Apps</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{% if app_provider_data is defined and app_provider_data.published_apps is defined %}{{ app_provider_data.published_apps }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">Active</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card primary">
|
||||
<h5 class="card-title">Active Deployments</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{% if app_provider_data is defined and app_provider_data.active_deployments is defined %}{{ app_provider_data.active_deployments }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">Instances</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card warning">
|
||||
<h5 class="card-title">Customer Base</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{% if app_provider_data is defined and app_provider_data.total_deployments is defined %}{{ app_provider_data.total_deployments }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">Total Deployments</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card success">
|
||||
<h5 class="card-title">Monthly Earnings</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{% if app_provider_data is defined and app_provider_data.monthly_revenue_usd is defined %}{{ app_provider_data.monthly_revenue_usd }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">$/month</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Register New App Button -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-end">
|
||||
<a href="#" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#registerAppModal">
|
||||
<i class="bi bi-plus-circle me-2"></i> Register New Application
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Published Applications Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>My Published Applications</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Application</th>
|
||||
<th>Type</th>
|
||||
<th>Status</th>
|
||||
<th>Version</th>
|
||||
<th>Active Deployments</th>
|
||||
<th>Average Rating</th>
|
||||
<th>Monthly Revenue</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="apps-list-tbody">
|
||||
<!-- Apps will be populated by JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Application Deployments Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Active Deployments</h3>
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
Each application can have multiple deployments across different users and environments.
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Deployment ID</th>
|
||||
<th>Application</th>
|
||||
<th>Customer</th>
|
||||
<th>Region</th>
|
||||
<th>Instances</th>
|
||||
<th>Deployed On</th>
|
||||
<th>Status</th>
|
||||
<th>Health</th>
|
||||
<th>Resource Usage</th>
|
||||
<th>Revenue</th>
|
||||
<th>Monitoring</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="active-deployments-tbody">
|
||||
<!-- Active deployments will be populated by JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center mt-3">
|
||||
<nav aria-label="Deployments pagination">
|
||||
<ul class="pagination">
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">Previous</a>
|
||||
</li>
|
||||
<li class="page-item active"><a class="page-link" href="#">1</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">2</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">3</a></li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#">Next</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Development Resources Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Developer Resources</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-book me-2 text-primary"></i> Documentation</h5>
|
||||
<p>Access guides, tutorials, and API references for developing ThreeFold applications</p>
|
||||
<a href="https://manual.threefold.io" target="_blank" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-box-arrow-up-right me-1"></i>Browse Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-people me-2 text-info"></i> Developer Community</h5>
|
||||
<p>Connect with other ThreeFold application developers, share insights, and get help</p>
|
||||
<a href="https://t.me/threefoldtesting" target="_blank" class="btn btn-sm btn-outline-info">
|
||||
<i class="bi bi-box-arrow-up-right me-1"></i>Join Community
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Revenue Monitoring Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Revenue Monitoring</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Monthly Revenue Trend</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="revenueChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Revenue by Application</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="revenueDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Additional Charts Row -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Deployment Trend</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="deploymentTrendChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>App Performance</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="appPerformanceChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<!-- Hydration JSON for initial app provider dashboard data (safe, non-executable) -->
|
||||
<script id="ap-dashboard-hydration" type="application/json">
|
||||
{% if app_provider_data is defined %}
|
||||
{{ app_provider_data | json_encode() }}
|
||||
{% else %}
|
||||
null
|
||||
{% endif %}
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||
<script src="/static/js/dashboard-app-provider.js"></script>
|
||||
<style>
|
||||
/* Ensure charts have consistent sizes */
|
||||
.card-body {
|
||||
min-height: 340px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
<!-- Register Application Modal -->
|
||||
<div class="modal fade" id="registerAppModal" tabindex="-1" aria-labelledby="registerAppModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="registerAppModalLabel">Register New Application</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="appName" class="form-label">Application Name</label>
|
||||
<input type="text" class="form-control" id="appName" placeholder="Enter application name">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="appDesc" class="form-label">Description</label>
|
||||
<textarea class="form-control" id="appDesc" rows="3" placeholder="Describe your application"></textarea>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="appCategory" class="form-label">Category</label>
|
||||
<select class="form-select" id="appCategory">
|
||||
<option selected>Select category</option>
|
||||
<option value="productivity">Productivity</option>
|
||||
<option value="communication">Communication</option>
|
||||
<option value="business">Business</option>
|
||||
<option value="storage">Storage & Backup</option>
|
||||
<option value="development">Development Tools</option>
|
||||
<option value="analytics">Analytics & BI</option>
|
||||
<option value="other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="appType" class="form-label">Deployment Type</label>
|
||||
<select class="form-select" id="appType">
|
||||
<option selected>Select type</option>
|
||||
<option value="container">Container-based</option>
|
||||
<option value="vm">Virtual Machine</option>
|
||||
<option value="kubernetes">Kubernetes Workload</option>
|
||||
<option value="custom">Custom Deployment</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="appRepo" class="form-label">Source Repository URL</label>
|
||||
<input type="url" class="form-control" id="appRepo" placeholder="https://github.com/yourusername/yourrepo">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="resourceRequirements" class="form-label">Minimum Resource Requirements</label>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-2">
|
||||
<input type="number" class="form-control" id="minCPU" placeholder="vCPU Cores">
|
||||
</div>
|
||||
<div class="col-md-4 mb-2">
|
||||
<input type="number" class="form-control" id="minRAM" placeholder="RAM (GB)">
|
||||
</div>
|
||||
<div class="col-md-4 mb-2">
|
||||
<input type="number" class="form-control" id="minStorage" placeholder="Storage (GB)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="appPrice" class="form-label">Pricing Model</label>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-2">
|
||||
<select class="form-select" id="pricingType">
|
||||
<option selected>Select pricing model</option>
|
||||
<option value="subscription">Subscription (per user/month)</option>
|
||||
<option value="usage">Usage-based</option>
|
||||
<option value="fixed">Fixed price (per instance)</option>
|
||||
<option value="free">Free</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="priceAmount" placeholder="Amount">
|
||||
<span class="input-group-text">$</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="selfHealing">
|
||||
<label class="form-check-label" for="selfHealing">Enable self-healing capabilities</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-info" id="registerAppBtn">Register Application</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
208
src/views/dashboard/cart.html
Normal file
208
src/views/dashboard/cart.html
Normal file
@@ -0,0 +1,208 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}Shopping Cart - ThreeFold Dashboard{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<!-- Header with marketplace navigation -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="mb-1">
|
||||
<i class="bi bi-cart3 me-2"></i>Shopping Cart
|
||||
</h1>
|
||||
<p class="lead mb-0">Review and manage your selected services</p>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="/" class="btn btn-outline-primary">
|
||||
<i class="bi bi-shop me-1"></i> Browse Marketplace
|
||||
</a>
|
||||
<a href="/orders" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-receipt me-1"></i> Order History
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Content -->
|
||||
<div class="row">
|
||||
<!-- Cart Items -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-list-ul me-2"></i>Cart Items
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body" id="cartItemsContainer">
|
||||
<!-- Cart items will be loaded here -->
|
||||
<div class="text-center py-5" id="emptyCartMessage">
|
||||
<i class="bi bi-cart-x display-1 text-muted mb-3"></i>
|
||||
<h4 class="text-muted">Your cart is empty</h4>
|
||||
<p class="text-muted mb-4">Browse our marketplace to find services for your projects</p>
|
||||
<a href="/marketplace" class="btn btn-primary">
|
||||
<i class="bi bi-shop me-1"></i> Browse Marketplace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Summary -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-calculator me-2"></i>Order Summary
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="summary-section" id="cartSummary">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal:</span>
|
||||
<span id="cartSubtotal">{{ currency_symbol | default(value="$") }}0.00</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Estimated Deploy Time:</span>
|
||||
<span id="cartDeployTime">0 minutes</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<strong>Total:</strong>
|
||||
<strong id="cartTotal">{{ currency_symbol | default(value="$") }}0.00</strong>
|
||||
</div>
|
||||
|
||||
<!-- Wallet Balance Check -->
|
||||
<div class="wallet-status mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span>Your {{ display_currency | default(value="USD") }} Credits:</span>
|
||||
<span class="fw-bold" id="userBalance">{{ currency_symbol | default(value="$") }}0.00</span>
|
||||
</div>
|
||||
<div class="balance-indicator mt-2" id="balanceIndicator">
|
||||
<!-- Balance status will be shown here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary btn-lg" id="checkoutBtn" data-action="proceed-checkout" disabled>
|
||||
<i class="bi bi-credit-card me-1"></i>
|
||||
Proceed to Checkout
|
||||
</button>
|
||||
<button class="btn btn-outline-danger" id="clearCartBtn" disabled data-bs-toggle="modal" data-bs-target="#clearCartModal">
|
||||
<i class="bi bi-trash me-1"></i>
|
||||
Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="card shadow-sm mt-3">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-lightning me-2"></i>Quick Actions
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/dashboard/wallet" class="btn btn-outline-success btn-sm">
|
||||
<i class="bi bi-wallet2 me-1"></i>
|
||||
Top Up Wallet
|
||||
</a>
|
||||
<button class="btn btn-outline-info btn-sm" data-action="save-for-later">
|
||||
<i class="bi bi-bookmark me-1"></i>
|
||||
Save for Later
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary btn-sm" data-action="share-cart">
|
||||
<i class="bi bi-share me-1"></i>
|
||||
Share Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Item Template -->
|
||||
<template id="cartItemTemplate">
|
||||
<div class="cart-item border-bottom py-3" data-item-id="">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="service-icon me-3">
|
||||
<i class="bi bi-server display-6 text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-1 service-name"></h6>
|
||||
<p class="text-muted mb-0 service-specs"></p>
|
||||
<small class="text-muted added-time"></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-center">
|
||||
<div class="price-display">
|
||||
<span class="h5 mb-0 service-price"></span>
|
||||
<small class="text-muted d-block">per month</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-end">
|
||||
<div class="item-actions d-flex align-items-center">
|
||||
<!-- Quantity Controls -->
|
||||
<div class="quantity-controls d-flex align-items-center me-3">
|
||||
<button class="btn btn-sm btn-outline-secondary" data-action="decrease-qty" title="Decrease quantity">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
<span class="quantity-display mx-2 fw-bold" style="min-width: 30px; text-align: center;">1</span>
|
||||
<button class="btn btn-sm btn-outline-secondary" data-action="increase-qty" title="Increase quantity">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Remove Button -->
|
||||
<button class="btn btn-sm btn-outline-danger" data-action="remove-item" title="Remove item">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Clear Cart Confirmation Modal (Dashboard) -->
|
||||
<div class="modal fade" id="clearCartModal" tabindex="-1" aria-labelledby="clearCartModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="clearCartModalLabel"><i class="bi bi-trash me-2"></i>Clear Cart</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
Are you sure you want to clear your cart? This action cannot be undone.
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" id="confirmClearCartBtn" data-action="confirm-clear-cart">
|
||||
<i class="bi bi-trash me-1"></i> Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block hydration %}
|
||||
{{ super() }}
|
||||
<script id="hydration-dashboard-cart" type="application/json">
|
||||
{
|
||||
"currency_symbol": {{ currency_symbol | default(value="$") | json_encode() }},
|
||||
"display_currency": {{ display_currency | default(value="USD") | json_encode() }}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="/static/js/dashboard_cart.js"></script>
|
||||
{% endblock %}
|
1153
src/views/dashboard/farmer.html
Normal file
1153
src/views/dashboard/farmer.html
Normal file
File diff suppressed because it is too large
Load Diff
305
src/views/dashboard/index.html
Normal file
305
src/views/dashboard/index.html
Normal file
@@ -0,0 +1,305 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - Overview{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="mb-1">Dashboard Overview</h1>
|
||||
<p class="lead mb-0">Welcome, {% if user.name %}{{ user.name }}{% else %}{{ user.email }}{% endif %}</p>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<a href="/dashboard/wallet" class="btn btn-primary">
|
||||
<i class="bi bi-currency-exchange me-1"></i> Get Credits
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status Summary -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card primary">
|
||||
<h5 class="card-title">Active Deployments</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{% if user_metrics is defined and user_metrics.active_deployments_count is defined %}{{ user_metrics.active_deployments_count }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">Applications</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card success">
|
||||
<h5 class="card-title">Resources</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ active_compute_resources_count | default(value=0) }}</h2>
|
||||
<small class="text-muted">Active Slices</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card warning">
|
||||
<h5 class="card-title">Current Cost</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ total_monthly_cost | default(value=0) | format_decimal(precision=2) }}</h2>
|
||||
<small class="text-muted">{{ currency_symbol | default(value="$") }}/month</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card info">
|
||||
<h5 class="card-title">Wallet Balance</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0" id="dashboardWalletBalance">{{ currency_symbol | default(value="$") }}{% if user_metrics is defined and user_metrics.wallet_balance is defined %}{{ user_metrics.wallet_balance | format_decimal(precision=2) }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">Credits (<span id="dashboardCurrencyCode">{{ display_currency | default(value="USD") }}</span>)</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Quick Actions</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<a href="/marketplace/applications" class="btn btn-outline-primary w-100 mb-2">
|
||||
<i class="bi bi-box-seam me-2"></i> Deploy Applications
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="/marketplace/compute" class="btn btn-outline-success w-100 mb-2">
|
||||
<i class="bi bi-cpu me-2"></i> Reserve Resources
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="/dashboard/wallet" class="btn btn-outline-info w-100 mb-2">
|
||||
<i class="bi bi-wallet2 me-2"></i> Manage Wallet
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="/dashboard/farmer" class="btn btn-outline-info w-100 mb-2">
|
||||
<i class="bi bi-hdd-rack me-2"></i> Add a 3Node
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<a href="/dashboard/settings" class="btn btn-outline-secondary w-100 mb-2">
|
||||
<i class="bi bi-gear me-2"></i> Account Settings
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="/marketplace" class="btn btn-outline-dark w-100 mb-2">
|
||||
<i class="bi bi-shop me-2"></i> Browse Marketplace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Roles Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<h3>Your Roles</h3>
|
||||
<p>Manage your ThreeFold experience through different perspectives:</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 mb-4">
|
||||
<div class="dashboard-card">
|
||||
<span class="badge bg-primary badge-role">USER</span>
|
||||
<h4>User Dashboard</h4>
|
||||
<p>Deploy apps, manage resources, monitor costs, and track usage.</p>
|
||||
<div class="d-grid">
|
||||
<a href="/dashboard/user" class="btn btn-sm btn-outline-primary">Access User Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 mb-4">
|
||||
<div class="dashboard-card">
|
||||
<span class="badge bg-success badge-role">FARMER</span>
|
||||
<h4>Farmer Dashboard</h4>
|
||||
<p>Manage your nodes, create slices, set pricing, and track earnings.</p>
|
||||
<div class="d-grid">
|
||||
<a href="/dashboard/farmer" class="btn btn-sm btn-outline-success">Access Farmer Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 mb-4">
|
||||
<div class="dashboard-card">
|
||||
<span class="badge bg-info badge-role">APP PROVIDER</span>
|
||||
<h4>App Provider Dashboard</h4>
|
||||
<p>Develop, deploy, and manage applications for the TF ecosystem.</p>
|
||||
<div class="d-grid">
|
||||
<a href="/dashboard/app-provider" class="btn btn-sm btn-outline-info">Access App Provider Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 mb-4">
|
||||
<div class="dashboard-card">
|
||||
<span class="badge bg-warning badge-role">SERVICE PROVIDER</span>
|
||||
<h4>Service Provider Dashboard</h4>
|
||||
<p>Offer professional services and manage maintenance requests.</p>
|
||||
<div class="d-grid">
|
||||
<a href="/dashboard/service-provider" class="btn btn-sm btn-outline-warning">Access Service Provider Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistics Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Statistics</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Resource Utilization</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="resourceUtilizationOverviewChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Credits Usage Trend</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="creditsUsageOverviewChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>User Activity</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="userActivityChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Deployment Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="deploymentDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activity -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Recent Activity</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Action</th>
|
||||
<th>Status</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if recent_activities is defined and recent_activities and recent_activities | length > 0 %}
|
||||
{% for activity in recent_activities %}
|
||||
<tr>
|
||||
<td>{{ activity.date }}</td>
|
||||
<td>{{ activity.action }}</td>
|
||||
<td>
|
||||
{% if activity.status == "Completed" %}
|
||||
<span class="badge bg-success">{{ activity.status }}</span>
|
||||
{% elif activity.status == "Active" %}
|
||||
<span class="badge bg-success">{{ activity.status }}</span>
|
||||
{% elif activity.status == "Pending" %}
|
||||
<span class="badge bg-info">{{ activity.status }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ activity.status }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ activity.details }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-center text-muted">No recent activity</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||
<style>
|
||||
/* Ensure charts have consistent sizes */
|
||||
.card.h-100 {
|
||||
height: 400px !important;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
height: 340px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- JSON hydration for dashboard charts -->
|
||||
<script type="application/json" id="dashboard-chart-data">
|
||||
{
|
||||
"displayCurrency": "{% if display_currency is defined and display_currency %}{{ display_currency }}{% else %}USD{% endif %}",
|
||||
"resourceUtilization": {
|
||||
{% if user_metrics is defined and user_metrics.resource_utilization is defined %}
|
||||
"cpu": {{ user_metrics.resource_utilization.cpu }},
|
||||
"memory": {{ user_metrics.resource_utilization.memory }},
|
||||
"storage": {{ user_metrics.resource_utilization.storage }},
|
||||
"network": {{ user_metrics.resource_utilization.network }}
|
||||
{% else %}
|
||||
"cpu": 0, "memory": 0, "storage": 0, "network": 0
|
||||
{% endif %}
|
||||
},
|
||||
"creditsUsageTrend": [
|
||||
{% if user_metrics is defined and user_metrics.cost_trend is defined %}
|
||||
{% for value in user_metrics.cost_trend %}{{ value }}{% if not loop.last %}, {% endif %}{% endfor %}
|
||||
{% else %}0, 0, 0, 0, 0, 0{% endif %}
|
||||
],
|
||||
"userActivity": {
|
||||
"deployments": [
|
||||
0, 0, 0, 0, 0, 0
|
||||
],
|
||||
"resourceReservations": [
|
||||
0, 0, 0, 0, 0, 0
|
||||
]
|
||||
},
|
||||
"deploymentDistribution": {
|
||||
"regions": [],
|
||||
"nodes": [],
|
||||
"slices": [],
|
||||
"apps": [],
|
||||
"gateways": []
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Externalized dashboard logic (charts + wallet updater) -->
|
||||
<script src="/static/js/dashboard.js"></script>
|
||||
{% endblock %}
|
238
src/views/dashboard/layout.html
Normal file
238
src/views/dashboard/layout.html
Normal file
@@ -0,0 +1,238 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar Toggle Button (mobile only) -->
|
||||
<button class="btn sidebar-toggle d-md-none" id="sidebarToggleBtn" aria-label="Toggle sidebar navigation" aria-expanded="false" aria-controls="sidebar">
|
||||
<i class="bi bi-list"></i> Menu
|
||||
</button>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse" id="sidebar">
|
||||
<div class="position-sticky pt-3">
|
||||
<h5 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mb-1 text-muted">
|
||||
<span>Dashboard</span>
|
||||
</h5>
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'home' %}active{% endif %}" href="/dashboard">
|
||||
<i class="bi bi-speedometer2 me-1"></i>
|
||||
Overview
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'user' %}active{% endif %}" href="/dashboard/user">
|
||||
<i class="bi bi-person me-1"></i>
|
||||
User
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'farmer' %}active{% endif %}" href="/dashboard/farmer">
|
||||
<i class="bi bi-hdd-rack me-1"></i>
|
||||
Farmer
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'app_provider' %}active{% endif %}" href="/dashboard/app-provider">
|
||||
<i class="bi bi-app me-1"></i>
|
||||
App Provider
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'service_provider' %}active{% endif %}" href="/dashboard/service-provider">
|
||||
<i class="bi bi-person-workspace me-1"></i>
|
||||
Service Provider
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'wallet' %}active{% endif %}" href="/dashboard/wallet">
|
||||
<i class="bi bi-wallet2 me-1"></i>
|
||||
Wallet
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Shopping & Orders Section -->
|
||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||
<span>Shopping</span>
|
||||
</h6>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'cart' %}active{% endif %}" href="/dashboard/cart" id="cartNavLink">
|
||||
<i class="bi bi-cart3 me-1"></i>
|
||||
Shopping Cart
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'orders' %}active{% endif %}" href="/dashboard/orders">
|
||||
<i class="bi bi-receipt me-1"></i>
|
||||
Order History
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- HIDE: Pools navigation - keeping for future use
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'pools' %}active{% endif %}" href="/dashboard/pools">
|
||||
<i class="bi bi-currency-exchange me-1"></i>
|
||||
Credits Pools
|
||||
</a>
|
||||
</li>
|
||||
-->
|
||||
|
||||
<!-- Communication Section -->
|
||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||
<span>Communication</span>
|
||||
</h6>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link position-relative {% if active_section == 'messages' %}active{% endif %}" href="/dashboard/messages">
|
||||
<i class="bi bi-chat-dots me-1"></i>
|
||||
Messages
|
||||
<span class="badge bg-danger rounded-pill ms-auto message-badge" style="display: none; font-size: 0.7rem;">0</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Settings Section -->
|
||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||
<span>Account</span>
|
||||
</h6>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'settings' %}active{% endif %}" href="/dashboard/settings">
|
||||
<i class="bi bi-gear me-1"></i>
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content-wrapper position-relative">
|
||||
<!-- Sidebar Backdrop (mobile only) - positioned here so it doesn't cover the sidebar -->
|
||||
<div class="sidebar-backdrop d-md-none" id="sidebarBackdrop"></div>
|
||||
{% block dashboard_content %}
|
||||
<!-- Content will be injected here by child templates -->
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<!-- Add Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css">
|
||||
|
||||
<style>
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 56px; /* Navbar height */
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
padding: 20px 0 0;
|
||||
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
|
||||
height: 100%; /* Full height */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Footer should only appear on the right side */
|
||||
@media (min-width: 768px) {
|
||||
.footer {
|
||||
margin-left: 25%; /* Matches the width of col-md-3 */
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.footer {
|
||||
margin-left: 16.666667%; /* Matches the width of col-lg-2 */
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-heading {
|
||||
font-size: .75rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.sidebar .nav-link {
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active {
|
||||
color: #2470dc;
|
||||
}
|
||||
|
||||
.dashboard-section {
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
background-color: #f8f9fa;
|
||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);
|
||||
}
|
||||
|
||||
.dashboard-card {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
background-color: white;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.dashboard-card:hover {
|
||||
box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
border-left: 4px solid;
|
||||
background-color: white;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);
|
||||
}
|
||||
|
||||
.stats-card.primary {
|
||||
border-left-color: #007bff;
|
||||
}
|
||||
|
||||
.stats-card.success {
|
||||
border-left-color: #28a745;
|
||||
}
|
||||
|
||||
.stats-card.info {
|
||||
border-left-color: #17a2b8;
|
||||
}
|
||||
|
||||
.stats-card.warning {
|
||||
border-left-color: #ffc107;
|
||||
}
|
||||
|
||||
.badge-role {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* Adjust for fixed navbar */
|
||||
main.py-4 {
|
||||
padding-top: 4.5rem !important;
|
||||
}
|
||||
|
||||
/* Removed conflicting media query */
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="/static/js/dashboard_layout.js"></script>
|
||||
<script src="/static/js/messaging-system.js"></script>
|
||||
<script>
|
||||
// Dynamic user detection for messaging system
|
||||
try {
|
||||
// Initialize messaging system with dynamic user detection
|
||||
if (window.MessagingSystem) {
|
||||
window.MessagingSystem.initializeWithDynamicUser();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize messaging system:', error);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
136
src/views/dashboard/messages.html
Normal file
136
src/views/dashboard/messages.html
Normal file
@@ -0,0 +1,136 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">
|
||||
<i class="bi bi-chat-dots me-2"></i>Messages
|
||||
</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<div class="btn-group me-2">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="refreshMessagesBtn">
|
||||
<i class="bi bi-arrow-clockwise"></i> Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Messages Interface -->
|
||||
<div class="row h-100">
|
||||
<!-- Conversations List -->
|
||||
<div class="col-md-4 col-lg-3">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-list-ul me-1"></i>Conversations
|
||||
</h6>
|
||||
<span class="badge bg-primary" id="totalConversationsCount">0</span>
|
||||
</div>
|
||||
<div class="card-body p-0" style="height: calc(100vh - 280px); min-height: 500px;">
|
||||
<div id="conversationsList" class="list-group list-group-flush h-100" style="overflow-y: auto;">
|
||||
<!-- Loading state -->
|
||||
<div class="d-flex justify-content-center align-items-center h-100" id="conversationsLoading">
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary mb-3" role="status">
|
||||
<span class="visually-hidden">Loading conversations...</span>
|
||||
</div>
|
||||
<p class="text-muted">Loading conversations...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Empty state -->
|
||||
<div class="d-flex justify-content-center align-items-center h-100 d-none" id="conversationsEmpty">
|
||||
<div class="text-center text-muted">
|
||||
<i class="bi bi-chat-square-text fs-1 mb-3"></i>
|
||||
<h6>No conversations yet</h6>
|
||||
<p class="small">Start a conversation from the marketplace or user profiles</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message View -->
|
||||
<div class="col-md-8 col-lg-9 d-flex flex-column" style="height: calc(100vh - 200px);">
|
||||
<div class="card h-100 d-flex flex-column">
|
||||
<!-- Message Header -->
|
||||
<div class="card-header d-none flex-shrink-0" id="messageHeader">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="mb-0" id="conversationTitle">Select a conversation</h6>
|
||||
<small class="text-muted" id="conversationParticipants"></small>
|
||||
</div>
|
||||
<div>
|
||||
<span class="badge bg-secondary" id="conversationContext">general</span>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary ms-2" id="markAsReadBtn">
|
||||
<i class="bi bi-check2-all"></i> Mark as Read
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Welcome/Empty State -->
|
||||
<div class="card-body d-flex justify-content-center align-items-center flex-grow-1" id="messagesWelcome" style="background: #f8f9fa;">
|
||||
<div class="text-center text-muted">
|
||||
<i class="bi bi-chat-square-dots fs-1 mb-3"></i>
|
||||
<h5>Welcome to Messages</h5>
|
||||
<p>Select a conversation from the left to view messages</p>
|
||||
<p class="small">You can start conversations from marketplace listings or user profiles</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Messages Area -->
|
||||
<div class="card-body flex-grow-1 p-3 d-none overflow-auto" id="messagesContainer" style="background: linear-gradient(to bottom, #fafafa 0%, #ffffff 100%);">
|
||||
<!-- Messages will be populated here -->
|
||||
</div>
|
||||
|
||||
<!-- Message Input -->
|
||||
<div class="card-footer border-top p-3 flex-shrink-0 d-none" id="messageInputContainer" style="background: white;">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="messageInput" placeholder="Type your message..." maxlength="1000" disabled>
|
||||
<button class="btn btn-primary" type="button" id="sendMessageBtn" disabled>
|
||||
<i class="bi bi-send"></i>
|
||||
</button>
|
||||
</div>
|
||||
<small class="text-muted mt-1 d-block">Press Enter to send • <span id="messageCharCount">0</span>/1000 characters</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Container -->
|
||||
<div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 1055;">
|
||||
<div id="successToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-success text-white">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>
|
||||
<strong class="me-auto">Success</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="successToastBody">
|
||||
Message sent successfully!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="errorToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-danger text-white">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<strong class="me-auto">Error</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="errorToastBody">
|
||||
An error occurred!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="application/json" id="messages-hydration">
|
||||
{
|
||||
"user_email": {{ user_email | default(value="") | json_encode() | safe }}
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/dashboard-messages.js"></script>
|
||||
{% endblock %}
|
201
src/views/dashboard/orders.html
Normal file
201
src/views/dashboard/orders.html
Normal file
@@ -0,0 +1,201 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}Order History - ThreeFold Dashboard{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<!-- Header with marketplace navigation -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="mb-1">
|
||||
<i class="bi bi-receipt me-2"></i>Order History
|
||||
</h1>
|
||||
<p class="lead mb-0">Track your purchases and deployments</p>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="/" class="btn btn-outline-primary">
|
||||
<i class="bi bi-shop me-1"></i> Browse Marketplace
|
||||
</a>
|
||||
<a href="/dashboard/cart" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-cart3 me-1"></i> Shopping Cart
|
||||
<span class="badge bg-primary ms-1" id="cartBadge" style="display: none;">0</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Orders Filter and Search -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-8">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-4">
|
||||
<label for="orderStatus" class="form-label">Filter by Status</label>
|
||||
<select class="form-select" id="orderStatus">
|
||||
<option value="">All Orders</option>
|
||||
<option value="pending">Pending</option>
|
||||
<option value="processing">Processing</option>
|
||||
<option value="deployed">Deployed</option>
|
||||
<option value="active">Active</option>
|
||||
<option value="failed">Failed</option>
|
||||
<option value="cancelled">Cancelled</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="orderPeriod" class="form-label">Time Period</label>
|
||||
<select class="form-select" id="orderPeriod">
|
||||
<option value="">All Time</option>
|
||||
<option value="7">Last 7 days</option>
|
||||
<option value="30">Last 30 days</option>
|
||||
<option value="90">Last 3 months</option>
|
||||
<option value="365">Last year</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="orderSearch" class="form-label">Search Orders</label>
|
||||
<input type="text" class="form-control" id="orderSearch" placeholder="Order ID or service name...">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="mb-1" id="totalOrders">0</h5>
|
||||
<small class="text-muted">Total Orders</small>
|
||||
<hr class="my-2">
|
||||
<h6 class="mb-1 text-success" id="totalSpent">0</h6>
|
||||
<small class="text-muted">Total Spent</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Orders List -->
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-list-ul me-2"></i>Your Orders
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body" id="ordersContainer">
|
||||
<!-- Orders will be loaded here -->
|
||||
<div class="text-center py-5" id="noOrdersMessage">
|
||||
<i class="bi bi-receipt display-1 text-muted mb-3"></i>
|
||||
<h4 class="text-muted">No orders found</h4>
|
||||
<p class="text-muted mb-4">Start shopping to see your order history here</p>
|
||||
<a href="/" class="btn btn-primary">
|
||||
<i class="bi bi-shop me-1"></i> Browse Marketplace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Item Template -->
|
||||
<template id="orderItemTemplate">
|
||||
<div class="order-item border-bottom py-3" data-order-id="">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="order-icon me-3">
|
||||
<i class="bi bi-box-seam display-6 text-primary"></i>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<div>
|
||||
<h6 class="mb-1">
|
||||
<span class="order-id"></span>
|
||||
<span class="badge order-status ms-2"></span>
|
||||
</h6>
|
||||
<p class="text-muted mb-1 order-services"></p>
|
||||
<small class="text-muted order-date"></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-center">
|
||||
<div class="price-display">
|
||||
<span class="h6 mb-0 order-total"></span>
|
||||
<small class="text-muted d-block">Total Cost</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-end">
|
||||
<div class="order-actions">
|
||||
<button class="btn btn-sm btn-outline-primary me-2" data-action="toggle-details">
|
||||
<i class="bi bi-eye"></i> Details
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#" data-action="view-invoice">
|
||||
<i class="bi bi-eye me-1"></i> View Invoice
|
||||
</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-action="contact-support">
|
||||
<i class="bi bi-headset me-1"></i> Contact Support
|
||||
</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Expandable Order Details -->
|
||||
<div class="order-details mt-3" style="display: none;">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h6>Services Ordered:</h6>
|
||||
<div class="order-services-list">
|
||||
<!-- Services will be populated here -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6>Deployment Status:</h6>
|
||||
<div class="deployment-status">
|
||||
<!-- Deployment info will be populated here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Order Details Modal -->
|
||||
<div class="modal fade" id="orderDetailsModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">
|
||||
<i class="bi bi-receipt me-2"></i>Order Details
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="orderDetailsContent">
|
||||
<!-- Order details will be loaded here -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" data-action="view-invoice-from-modal">
|
||||
<i class="bi bi-eye me-1"></i> View Invoice
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="application/json" id="orders-hydration">
|
||||
{
|
||||
"currency_symbol": {{ currency_symbol | default(value='$') | json_encode() }},
|
||||
"display_currency": {{ display_currency | default(value='USD') | json_encode() }}
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/dashboard_orders.js"></script>
|
||||
{% endblock %}
|
621
src/views/dashboard/pools.html
Normal file
621
src/views/dashboard/pools.html
Normal file
@@ -0,0 +1,621 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - Credits Pools{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<h1>Credits Pools</h1>
|
||||
<p class="lead">Exchange currencies and tokens through ThreeFold liquidity pools</p>
|
||||
|
||||
|
||||
<!-- Liquidity Pools Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Available Liquidity Pools</h3>
|
||||
<p>Exchange between different currencies and tokens through our liquidity pools</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card h-100" data-pool-id="credits-fiat">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">Credits - Fiat Pool</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">Purchase Credits with fiat currencies (USD, EUR, etc.) at the fixed rate of 1 USD per Credit.</p>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Exchange rate:</span>
|
||||
<span class="fw-bold exchange-rate">1 USD = 0.85 EUR</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Pool liquidity:</span>
|
||||
<span class="fw-bold liquidity">125,000 USD</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Min transaction:</span>
|
||||
<span class="fw-bold">$10</span>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#buyCreditsModal">Buy Credits</button>
|
||||
<button class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#sellCreditsModal">Sell Credits</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card h-100" data-pool-id="credits-tft">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0">Credits - TFT Pool</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">Exchange between USD Credits and ThreeFold Tokens (TFT).</p>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Current rate:</span>
|
||||
<span class="fw-bold exchange-rate">1 USD ≈ 5 TFT</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Pool liquidity:</span>
|
||||
<span class="fw-bold liquidity">25,000 USD / 125,000 TFT</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Min transaction:</span>
|
||||
<span class="fw-bold">$10 / 50 TFT</span>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#buyCreditsWithTFTModal">Buy Credits</button>
|
||||
<button class="btn btn-outline-success" data-bs-toggle="modal" data-bs-target="#sellCreditsForTFTModal">Sell Credits</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card h-100" data-pool-id="credits-peaq">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="mb-0">Credits - PEAQ Pool</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">Exchange between USD Credits and PEAQ tokens for the Peaq Network.</p>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Current rate:</span>
|
||||
<span class="fw-bold exchange-rate">1 USD ≈ 20 PEAQ</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Pool liquidity:</span>
|
||||
<span class="fw-bold liquidity">10,000 USD / 200,000 PEAQ</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Min transaction:</span>
|
||||
<span class="fw-bold">$10 / 200 PEAQ</span>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-info" data-bs-toggle="modal" data-bs-target="#buyCreditsWithPEAQModal">Buy Credits</button>
|
||||
<button class="btn btn-outline-info" data-bs-toggle="modal" data-bs-target="#sellCreditsForPEAQModal">Sell Credits</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Staking Section -->
|
||||
<div class="row mt-4" id="staking">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Credits Staking</h3>
|
||||
<p>Stake your Credits to earn discounts and increase your reputation in the ThreeFold ecosystem</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Your Staking Status</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6 class="text-muted">Currently Staked</h6>
|
||||
<h3 class="mb-0">$25</h3>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6 class="text-muted">Lock Period</h6>
|
||||
<h3 class="mb-0">3 months</h3>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6 class="text-muted">Discount Level</h6>
|
||||
<h3 class="mb-0">5%</h3>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6 class="text-muted">Reputation Bonus</h6>
|
||||
<h3 class="mb-0">+25 points</h3>
|
||||
</div>
|
||||
<div class="col-12 mt-2">
|
||||
<div class="d-grid">
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#stakeCreditsModal">
|
||||
<i class="bi bi-plus-circle me-2"></i> Stake Credits
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Staking Benefits</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Staked Amount</th>
|
||||
<th>Discount</th>
|
||||
<th>Reputation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>$10-50</td>
|
||||
<td>5%</td>
|
||||
<td>+25 points</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$51-100</td>
|
||||
<td>10%</td>
|
||||
<td>+50 points</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$101-500</td>
|
||||
<td>15%</td>
|
||||
<td>+100 points</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$501+</td>
|
||||
<td>20%</td>
|
||||
<td>+200 points</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Analytics Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Credits Analytics</h3>
|
||||
<p>Key metrics and historical data for Credits pools and exchanges</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Credits Exchange History</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="creditsPriceHistoryChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Liquidity Pool Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="liquidityPoolDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Exchange Volume (Last 30 Days)</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="exchangeVolumeChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Staking Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="stakingDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy TFC Credits Modal -->
|
||||
<div class="modal fade" id="buyCreditsModal" tabindex="-1" aria-labelledby="buyCreditsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="buyCreditsModalLabel">Buy USD Credits</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="creditsAmount" class="form-label">Amount of Credits to purchase</label>
|
||||
<input type="number" class="form-control" id="creditsAmount" min="10" value="100">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="paymentCurrency" class="form-label">Payment Currency</label>
|
||||
<select class="form-select" id="paymentCurrency">
|
||||
<option value="USD" selected>USD</option>
|
||||
<option value="EUR">EUR</option>
|
||||
<option value="GBP">GBP</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="paymentMethod" class="form-label">Payment Method</label>
|
||||
<select class="form-select" id="paymentMethod">
|
||||
<option value="card" selected>Credit/Debit Card</option>
|
||||
<option value="bank">Bank Transfer</option>
|
||||
<option value="crypto">Cryptocurrency</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 Credit = $1.00
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">$100</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Cost:</span>
|
||||
<span class="text-end">10.00 USD</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-action="confirm-buy-credits-fiat">Confirm Purchase</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sell TFC Credits Modal -->
|
||||
<div class="modal fade" id="sellCreditsModal" tabindex="-1" aria-labelledby="sellCreditsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="sellCreditsModalLabel">Sell USD Credits</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="sellCreditsAmount" class="form-label">Amount of Credits to sell</label>
|
||||
<input type="number" class="form-control" id="sellCreditsAmount" min="10" max="125" value="100">
|
||||
<div class="form-text">Maximum available: $125</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="receiveCurrency" class="form-label">Receive Currency</label>
|
||||
<select class="form-select" id="receiveCurrency">
|
||||
<option value="USD" selected>USD</option>
|
||||
<option value="EUR">EUR</option>
|
||||
<option value="GBP">GBP</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="payoutMethod" class="form-label">Payout Method</label>
|
||||
<select class="form-select" id="payoutMethod">
|
||||
<option value="bank" selected>Bank Transfer</option>
|
||||
<option value="card">Card Refund</option>
|
||||
<option value="crypto">Cryptocurrency</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 Credit = $1.00
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">$100</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>You receive:</span>
|
||||
<span class="text-end">10.00 USD</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-action="confirm-sell-credits-fiat">Confirm Sale</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stake TFC Credits Modal -->
|
||||
<div class="modal fade" id="stakeCreditsModal" tabindex="-1" aria-labelledby="stakeCreditsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-success text-white">
|
||||
<h5 class="modal-title" id="stakeCreditsModalLabel">Stake USD Credits</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="stakeAmount" class="form-label">Amount to stake</label>
|
||||
<input type="number" class="form-control" id="stakeAmount" min="100" max="1000" value="500">
|
||||
<div class="form-text">Available balance: $100</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="stakeDuration" class="form-label">Lock period</label>
|
||||
<select class="form-select" id="stakeDuration">
|
||||
<option value="1">1 Month</option>
|
||||
<option value="3" selected>3 Months</option>
|
||||
<option value="6">6 Months</option>
|
||||
<option value="12">12 Months</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="alert alert-success">
|
||||
<div class="d-flex">
|
||||
<i class="bi bi-check-circle me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Staking Benefits:</strong>
|
||||
<ul class="mb-0 ps-3">
|
||||
<li>10% discount on all marketplace purchases</li>
|
||||
<li>+50 reputation points</li>
|
||||
<li>Priority access to new resources</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" data-action="confirm-stake-credits">Confirm Staking</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy TFC Credits with TFT Modal -->
|
||||
<div class="modal fade" id="buyTFCWithTFTModal" tabindex="-1" aria-labelledby="buyTFCWithTFTModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-success text-white">
|
||||
<h5 class="modal-title" id="buyTFCWithTFTModalLabel">Buy ThreeFold Credits (TFC) with TFT</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="tfcAmountTFT" class="form-label">Amount of TFC Credits to purchase</label>
|
||||
<input type="number" class="form-control" id="tfpAmountTFT" min="10" value="100">
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 TFC = 0.5 TFT
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">100 TFC</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Cost:</span>
|
||||
<span class="text-end">50 TFT</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" data-action="confirm-buy-tfc-tft">Confirm Purchase</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sell TFC Credits for TFT Modal -->
|
||||
<div class="modal fade" id="sellTFCForTFTModal" tabindex="-1" aria-labelledby="sellTFCForTFTModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-success text-white">
|
||||
<h5 class="modal-title" id="sellTFCForTFTModalLabel">Sell ThreeFold Credits (TFC) for TFT</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="sellTfcAmountTFT" class="form-label">Amount of TFC Credits to sell</label>
|
||||
<input type="number" class="form-control" id="sellTfpAmountTFT" min="10" max="1250" value="100">
|
||||
<div class="form-text">Maximum available: 1,250 TFC</div>
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 TFC = 0.5 TFT
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">100 TFC</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>You receive:</span>
|
||||
<span class="text-end">50 TFT</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" data-action="confirm-sell-tfc-tft">Confirm Sale</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy TFC Credits with PEAQ Modal -->
|
||||
<div class="modal fade" id="buyTFCWithPEAQModal" tabindex="-1" aria-labelledby="buyTFCWithPEAQModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-info text-white">
|
||||
<h5 class="modal-title" id="buyTFCWithPEAQModalLabel">Buy ThreeFold Credits (TFC) with PEAQ</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="tfcAmountPEAQ" class="form-label">Amount of TFC Credits to purchase</label>
|
||||
<input type="number" class="form-control" id="tfpAmountPEAQ" min="10" value="100">
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 TFC = 2 PEAQ
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">100 TFC</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Cost:</span>
|
||||
<span class="text-end">200 PEAQ</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-info" data-action="confirm-buy-tfc-peaq">Confirm Purchase</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sell TFC Credits for PEAQ Modal -->
|
||||
<div class="modal fade" id="sellTFCForPEAQModal" tabindex="-1" aria-labelledby="sellTFCForPEAQModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-info text-white">
|
||||
<h5 class="modal-title" id="sellTFCForPEAQModalLabel">Sell ThreeFold Credits (TFC) for PEAQ</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="sellTfcAmountPEAQ" class="form-label">Amount of TFC Credits to sell</label>
|
||||
<input type="number" class="form-control" id="sellTfpAmountPEAQ" min="10" max="1250" value="100">
|
||||
<div class="form-text">Maximum available: 1,250 TFC</div>
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 TFC = 2 PEAQ
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">100 TFC</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>You receive:</span>
|
||||
<span class="text-end">200 PEAQ</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-info" data-action="confirm-sell-tfc-peaq">Confirm Sale</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Container for Success Messages -->
|
||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||
<div id="successToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-success text-white">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>
|
||||
<strong class="me-auto">Success</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="successToastBody">
|
||||
Operation completed successfully!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="errorToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-danger text-white">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<strong class="me-auto">Error</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="errorToastBody">
|
||||
An error occurred!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||
<style>
|
||||
/* Ensure charts have consistent sizes */
|
||||
.card.h-100 {
|
||||
height: 400px !important;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
height: 340px;
|
||||
}
|
||||
</style>
|
||||
<script type="application/json" id="pools-hydration">
|
||||
{
|
||||
"charts": true
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/dashboard_pools.js"></script>
|
||||
{% endblock %}
|
1089
src/views/dashboard/service_provider.html
Normal file
1089
src/views/dashboard/service_provider.html
Normal file
File diff suppressed because it is too large
Load Diff
333
src/views/dashboard/service_request_invoice.html
Normal file
333
src/views/dashboard/service_request_invoice.html
Normal file
@@ -0,0 +1,333 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Service Invoice - ThreeFold Dashboard</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.navbar-brand img {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.invoice-header {
|
||||
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
||||
border: 2px solid #2196f3;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.invoice-details {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.invoice-number {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: #2196f3;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #0b5ed7 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(135deg, #0b5ed7 0%, #0a58ca 100%);
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
content: "›";
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
color: #2196f3;
|
||||
}
|
||||
|
||||
.invoice-table th {
|
||||
background-color: #f8f9fa;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.no-print {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.card, .invoice-details {
|
||||
box-shadow: none !important;
|
||||
border: 1px solid #dee2e6 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark no-print">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" class="me-2">
|
||||
<span>ThreeFold Dashboard</span>
|
||||
</a>
|
||||
<div class="navbar-nav ms-auto">
|
||||
<a class="nav-link" href="/dashboard">
|
||||
<i class="bi bi-speedometer2 me-1"></i>Dashboard
|
||||
</a>
|
||||
<a class="nav-link active" href="/dashboard/service-provider">
|
||||
<i class="bi bi-person-workspace me-1"></i>Service Provider
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container py-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4 no-print">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/" class="text-decoration-none">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/dashboard" class="text-decoration-none">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="/dashboard/service-provider" class="text-decoration-none">Service Provider</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Service Invoice</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{% if request %}
|
||||
<!-- Invoice Header -->
|
||||
<div class="invoice-header p-4 mb-4">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h1 class="h2 mb-2">
|
||||
<i class="bi bi-receipt me-2"></i>THREEFOLD GRID SERVICE INVOICE
|
||||
</h1>
|
||||
<div class="invoice-number">INV-{{ request.id }}</div>
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end">
|
||||
<div class="mb-2">
|
||||
<strong>Invoice Date:</strong> {{ invoice_date }}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Due Date:</strong> {{ due_date }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Invoice Details -->
|
||||
<div class="col-lg-8">
|
||||
<div class="invoice-details p-4 mb-4">
|
||||
<!-- Service Provider and Bill To -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-2">SERVICE PROVIDER:</h6>
|
||||
<div class="fw-bold">{{ user.email }}</div>
|
||||
{% if user.name %}
|
||||
<div>{{ user.name }}</div>
|
||||
{% endif %}
|
||||
{% if user.country %}
|
||||
<div>{{ user.country }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-2">BILL TO:</h6>
|
||||
<div class="fw-bold">{{ request.client_name }}</div>
|
||||
{% if request.client_email %}
|
||||
<div>{{ request.client_email }}</div>
|
||||
{% endif %}
|
||||
{% if request.client_phone %}
|
||||
<div>{{ request.client_phone }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Details -->
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted mb-2">SERVICE DETAILS:</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-2">
|
||||
<strong>Request ID:</strong> {{ request.id }}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<strong>Service Type:</strong> {{ request.service_name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-2">
|
||||
<strong>Service Date:</strong> {{ request.requested_date }}
|
||||
</div>
|
||||
{% if request.completed_date %}
|
||||
<div class="mb-2">
|
||||
<strong>Completion Date:</strong> {{ request.completed_date }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Billing Breakdown -->
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted mb-3">BILLING BREAKDOWN:</h6>
|
||||
<table class="table invoice-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Description</th>
|
||||
<th class="text-center">Hours Worked</th>
|
||||
<th class="text-center">Rate</th>
|
||||
<th class="text-end">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ request.service_name }}</td>
|
||||
<td class="text-center">{{ request.estimated_hours }} hours</td>
|
||||
<td class="text-center">${{ rate }} per hour</td>
|
||||
<td class="text-end">${{ request.budget }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Total Amount -->
|
||||
<div class="border-top pt-4 mt-4">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-3">PAYMENT TERMS:</h6>
|
||||
<p class="mb-2">Payment is due within 30 days of invoice date.</p>
|
||||
<p class="mb-2">Please reference invoice number <strong>INV-{{ request.id }}</strong> with payment.</p>
|
||||
<p class="mb-0"><em>Thank you for choosing ThreeFold Grid services!</em></p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-md-end">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal:</span>
|
||||
<span>${{ request.budget }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Platform fee:</span>
|
||||
<span class="text-muted">Free</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="fw-bold fs-5">TOTAL AMOUNT:</span>
|
||||
<span class="total-amount">${{ request.budget }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Generated Date -->
|
||||
<div class="border-top pt-3 mt-4">
|
||||
<small class="text-muted">Generated on: {{ generated_date }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions Sidebar -->
|
||||
<div class="col-lg-4 no-print">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-gear me-2"></i>Invoice Actions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/dashboard/service-provider" class="btn btn-primary">
|
||||
<i class="bi bi-arrow-left me-2"></i>Back to Dashboard
|
||||
</a>
|
||||
<button class="btn btn-success js-print">
|
||||
<i class="bi bi-printer me-2"></i>Print Invoice
|
||||
</button>
|
||||
<a href="/api/dashboard/service-requests/{{ request.id }}/report" class="btn btn-outline-primary">
|
||||
<i class="bi bi-file-earmark-text me-2"></i>View Report
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h6 class="mb-3">Need Help?</h6>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/docs" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-book me-1"></i>Documentation
|
||||
</a>
|
||||
<a href="https://threefoldfaq.crisp.help/en/" class="btn btn-sm btn-outline-success" target="_blank">
|
||||
<i class="bi bi-chat-dots me-1"></i>Live Chat
|
||||
</a>
|
||||
<a href="mailto:support@threefold.io" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-envelope me-1"></i>Email Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Invoice Summary -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-info-circle me-2"></i>Invoice Summary
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Service Hours:</span>
|
||||
<span>{{ request.estimated_hours }}h</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Hourly Rate:</span>
|
||||
<span>${{ rate }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Priority:</span>
|
||||
<span class="badge bg-{% if request.priority == 'High' %}danger{% elif request.priority == 'Medium' %}warning{% else %}secondary{% endif %}">{{ request.priority }}</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="fw-bold">Total:</span>
|
||||
<span class="fw-bold text-primary">${{ request.budget }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-exclamation-triangle fs-1 text-warning mb-3"></i>
|
||||
<h3>Service Request Not Found</h3>
|
||||
<p class="text-muted">The requested service request could not be found.</p>
|
||||
<a href="/dashboard/service-provider" class="btn btn-primary">Back to Dashboard</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script type="application/json" id="service-invoice-data">{}</script>
|
||||
<script src="/static/js/print-utils.js"></script>
|
||||
</body>
|
||||
</html>
|
388
src/views/dashboard/service_request_report.html
Normal file
388
src/views/dashboard/service_request_report.html
Normal file
@@ -0,0 +1,388 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Service Request Report - ThreeFold Dashboard</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.navbar-brand img {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.report-header {
|
||||
background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%);
|
||||
border: 2px solid #4caf50;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.report-details {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.status-in-progress {
|
||||
background: #d1ecf1;
|
||||
color: #0c5460;
|
||||
border: 1px solid #bee5eb;
|
||||
}
|
||||
|
||||
.status-open {
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
border: 1px solid #ffeaa7;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #0b5ed7 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(135deg, #0b5ed7 0%, #0a58ca 100%);
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
content: "›";
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.progress-circle {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.progress-0-25 { background: #dc3545; }
|
||||
.progress-26-50 { background: #fd7e14; }
|
||||
.progress-51-75 { background: #ffc107; color: #000; }
|
||||
.progress-76-100 { background: #198754; }
|
||||
|
||||
@media print {
|
||||
.no-print {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.card, .report-details {
|
||||
box-shadow: none !important;
|
||||
border: 1px solid #dee2e6 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark no-print">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" class="me-2">
|
||||
<span>ThreeFold Dashboard</span>
|
||||
</a>
|
||||
<div class="navbar-nav ms-auto">
|
||||
<a class="nav-link" href="/dashboard">
|
||||
<i class="bi bi-speedometer2 me-1"></i>Dashboard
|
||||
</a>
|
||||
<a class="nav-link active" href="/dashboard/service-provider">
|
||||
<i class="bi bi-person-workspace me-1"></i>Service Provider
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container py-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4 no-print">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/" class="text-decoration-none">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/dashboard" class="text-decoration-none">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="/dashboard/service-provider" class="text-decoration-none">Service Provider</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Service Report</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{% if request %}
|
||||
<!-- Report Header -->
|
||||
<div class="report-header p-4 mb-4">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h1 class="h2 mb-2">
|
||||
<i class="bi bi-file-earmark-text me-2"></i>Service Request Report
|
||||
</h1>
|
||||
<p class="mb-0 text-muted">
|
||||
<i class="bi bi-hash me-1"></i>Request ID: {{ request.id }}
|
||||
</p>
|
||||
{% if request.completed_date %}
|
||||
<p class="mb-0 text-muted">
|
||||
<i class="bi bi-calendar me-1"></i>Completed on {{ request.completed_date }}
|
||||
</p>
|
||||
{% else %}
|
||||
<p class="mb-0 text-muted">
|
||||
<i class="bi bi-calendar me-1"></i>Completed recently
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end">
|
||||
<span class="status-badge status-{{ status_class }}">
|
||||
<i class="bi bi-check-circle me-1"></i>{{ request.status }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Report Details -->
|
||||
<div class="col-lg-8">
|
||||
<div class="report-details p-4 mb-4">
|
||||
<h3 class="mb-4">
|
||||
<i class="bi bi-info-circle me-2"></i>Service Details
|
||||
</h3>
|
||||
|
||||
<!-- Client Information -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-2">CLIENT INFORMATION</h6>
|
||||
<div class="mb-2">
|
||||
<strong>Name:</strong> {{ request.client_name }}
|
||||
</div>
|
||||
{% if request.client_email %}
|
||||
<div class="mb-2">
|
||||
<strong>Email:</strong> {{ request.client_email }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="mb-2">
|
||||
<strong>Email:</strong> <span class="text-muted">Not provided</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if request.client_phone %}
|
||||
<div class="mb-2">
|
||||
<strong>Phone:</strong> {{ request.client_phone }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-2">SERVICE INFORMATION</h6>
|
||||
<div class="mb-2">
|
||||
<strong>Service:</strong> {{ request.service_name }}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<strong>Requested Date:</strong> {{ request.requested_date }}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<strong>Estimated Hours:</strong> {{ request.estimated_hours }} hours
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Description -->
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted mb-2">SERVICE DESCRIPTION</h6>
|
||||
<div class="p-3 bg-light rounded">
|
||||
{% if request.description %}
|
||||
{{ request.description }}
|
||||
{% else %}
|
||||
<span class="text-muted">{{ request.service_name }} service for {{ request.client_name }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Progress Information -->
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted mb-2">COMPLETION STATUS</h6>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="progress-circle
|
||||
{% if request.progress <= 25 %}progress-0-25
|
||||
{% elif request.progress <= 50 %}progress-26-50
|
||||
{% elif request.progress <= 75 %}progress-51-75
|
||||
{% else %}progress-76-100{% endif %} me-3">
|
||||
{{ request.progress }}%
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">{{ request.progress }}% Complete</div>
|
||||
<small class="text-muted">Service completion progress</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Financial Summary -->
|
||||
<div class="border-top pt-4 mt-4">
|
||||
<h6 class="text-muted mb-3">FINANCIAL SUMMARY</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<strong class="text-muted">Service Rate:</strong>
|
||||
<div>${{ rate }} per hour</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong class="text-muted">Hours Worked:</strong>
|
||||
<div>{{ request.estimated_hours }} hours</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-md-end">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal:</span>
|
||||
<span>${{ request.budget }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Platform fee:</span>
|
||||
<span class="text-muted">Free</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="fw-bold fs-5">Total Amount:</span>
|
||||
<span class="fw-bold text-success fs-4">${{ request.budget }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions Sidebar -->
|
||||
<div class="col-lg-4 no-print">
|
||||
<div class="card">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-gear me-2"></i>Report Actions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/dashboard/service-provider" class="btn btn-primary">
|
||||
<i class="bi bi-arrow-left me-2"></i>Back to Dashboard
|
||||
</a>
|
||||
<button class="btn btn-success js-print">
|
||||
<i class="bi bi-printer me-2"></i>Print Report
|
||||
</button>
|
||||
<a href="/api/dashboard/service-requests/{{ request.id }}/invoice" class="btn btn-outline-primary">
|
||||
<i class="bi bi-receipt me-2"></i>View Invoice
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h6 class="mb-3">Need Help?</h6>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/docs" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-book me-1"></i>Documentation
|
||||
</a>
|
||||
<a href="https://threefoldfaq.crisp.help/en/" class="btn btn-sm btn-outline-success" target="_blank">
|
||||
<i class="bi bi-chat-dots me-1"></i>Live Chat
|
||||
</a>
|
||||
<a href="mailto:support@threefold.io" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-envelope me-1"></i>Email Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Timeline -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-clock-history me-2"></i>Service Timeline
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="timeline">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-check-circle-fill text-success fs-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Request Submitted</div>
|
||||
<small class="text-muted">
|
||||
{% if request.created_date %}
|
||||
{{ request.created_date }}
|
||||
{% else %}
|
||||
{{ request.requested_date }}
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-check-circle-fill text-success fs-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Service Started</div>
|
||||
<small class="text-muted">{{ request.requested_date }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% if request.status == "Completed" %}
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-check-circle-fill text-success fs-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Service Completed</div>
|
||||
<small class="text-muted">
|
||||
{% if request.completed_date %}
|
||||
{{ request.completed_date }}
|
||||
{% else %}
|
||||
Recently completed
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-exclamation-triangle fs-1 text-warning mb-3"></i>
|
||||
<h3>Service Request Not Found</h3>
|
||||
<p class="text-muted">The requested service request could not be found.</p>
|
||||
<a href="/dashboard/service-provider" class="btn btn-primary">Back to Dashboard</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script type="application/json" id="service-report-data">{}</script>
|
||||
<script src="/static/js/print-utils.js"></script>
|
||||
</body>
|
||||
</html>
|
670
src/views/dashboard/settings.html
Normal file
670
src/views/dashboard/settings.html
Normal file
@@ -0,0 +1,670 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - Settings{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<h1>Account Settings</h1>
|
||||
<p class="lead">Manage your ThreeFold account preferences and security settings</p>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-md-3">
|
||||
<div class="nav flex-column nav-pills me-3" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||
<button class="nav-link active" id="v-pills-profile-tab" data-bs-toggle="pill" data-bs-target="#v-pills-profile" type="button" role="tab" aria-controls="v-pills-profile" aria-selected="true">Profile Information</button>
|
||||
<button class="nav-link" id="v-pills-password-tab" data-bs-toggle="pill" data-bs-target="#v-pills-password" type="button" role="tab" aria-controls="v-pills-password" aria-selected="false">Password</button>
|
||||
<button class="nav-link" id="v-pills-ssh-keys-tab" data-bs-toggle="pill" data-bs-target="#v-pills-ssh-keys" type="button" role="tab" aria-controls="v-pills-ssh-keys" aria-selected="false">SSH Keys</button>
|
||||
<button class="nav-link" id="v-pills-currency-tab" data-bs-toggle="pill" data-bs-target="#v-pills-currency" type="button" role="tab" aria-controls="v-pills-currency" aria-selected="false">Currency Preferences</button>
|
||||
<button class="nav-link" id="v-pills-delete-tab" data-bs-toggle="pill" data-bs-target="#v-pills-delete" type="button" role="tab" aria-controls="v-pills-delete" aria-selected="false">Delete Account</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<div class="tab-content" id="v-pills-tabContent">
|
||||
<!-- Profile Information -->
|
||||
<div class="tab-pane fade show active" id="v-pills-profile" role="tabpanel" aria-labelledby="v-pills-profile-tab">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Profile Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="profileForm">
|
||||
<div class="row mb-3">
|
||||
<label for="name" class="col-sm-3 col-form-label">Name</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="name" name="name" value="{{ user.name | default(value='') }}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="email" class="col-sm-3 col-form-label">Email</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="email" class="form-control" id="email" value="{{ user.email }}" readonly>
|
||||
<small class="text-muted">Email address cannot be changed</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="country" class="col-sm-3 col-form-label">Country</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-select" id="country" name="country">
|
||||
<option value="">Choose country...</option>
|
||||
<option value="Afghanistan" {% if user.country == "Afghanistan" %}selected{% endif %}>Afghanistan</option>
|
||||
<option value="Albania" {% if user.country == "Albania" %}selected{% endif %}>Albania</option>
|
||||
<option value="Algeria" {% if user.country == "Algeria" %}selected{% endif %}>Algeria</option>
|
||||
<option value="Andorra" {% if user.country == "Andorra" %}selected{% endif %}>Andorra</option>
|
||||
<option value="Angola" {% if user.country == "Angola" %}selected{% endif %}>Angola</option>
|
||||
<option value="Antigua and Barbuda" {% if user.country == "Antigua and Barbuda" %}selected{% endif %}>Antigua and Barbuda</option>
|
||||
<option value="Argentina" {% if user.country == "Argentina" %}selected{% endif %}>Argentina</option>
|
||||
<option value="Armenia" {% if user.country == "Armenia" %}selected{% endif %}>Armenia</option>
|
||||
<option value="Australia" {% if user.country == "Australia" %}selected{% endif %}>Australia</option>
|
||||
<option value="Austria" {% if user.country == "Austria" %}selected{% endif %}>Austria</option>
|
||||
<option value="Azerbaijan" {% if user.country == "Azerbaijan" %}selected{% endif %}>Azerbaijan</option>
|
||||
<option value="Bahamas" {% if user.country == "Bahamas" %}selected{% endif %}>Bahamas</option>
|
||||
<option value="Bahrain" {% if user.country == "Bahrain" %}selected{% endif %}>Bahrain</option>
|
||||
<option value="Bangladesh" {% if user.country == "Bangladesh" %}selected{% endif %}>Bangladesh</option>
|
||||
<option value="Barbados" {% if user.country == "Barbados" %}selected{% endif %}>Barbados</option>
|
||||
<option value="Belarus" {% if user.country == "Belarus" %}selected{% endif %}>Belarus</option>
|
||||
<option value="Belgium" {% if user.country == "Belgium" %}selected{% endif %}>Belgium</option>
|
||||
<option value="Belize" {% if user.country == "Belize" %}selected{% endif %}>Belize</option>
|
||||
<option value="Benin" {% if user.country == "Benin" %}selected{% endif %}>Benin</option>
|
||||
<option value="Bhutan" {% if user.country == "Bhutan" %}selected{% endif %}>Bhutan</option>
|
||||
<option value="Bolivia" {% if user.country == "Bolivia" %}selected{% endif %}>Bolivia</option>
|
||||
<option value="Bosnia and Herzegovina" {% if user.country == "Bosnia and Herzegovina" %}selected{% endif %}>Bosnia and Herzegovina</option>
|
||||
<option value="Botswana" {% if user.country == "Botswana" %}selected{% endif %}>Botswana</option>
|
||||
<option value="Brazil" {% if user.country == "Brazil" %}selected{% endif %}>Brazil</option>
|
||||
<option value="Brunei" {% if user.country == "Brunei" %}selected{% endif %}>Brunei</option>
|
||||
<option value="Bulgaria" {% if user.country == "Bulgaria" %}selected{% endif %}>Bulgaria</option>
|
||||
<option value="Burkina Faso" {% if user.country == "Burkina Faso" %}selected{% endif %}>Burkina Faso</option>
|
||||
<option value="Burundi" {% if user.country == "Burundi" %}selected{% endif %}>Burundi</option>
|
||||
<option value="Cabo Verde" {% if user.country == "Cabo Verde" %}selected{% endif %}>Cabo Verde</option>
|
||||
<option value="Cambodia" {% if user.country == "Cambodia" %}selected{% endif %}>Cambodia</option>
|
||||
<option value="Cameroon" {% if user.country == "Cameroon" %}selected{% endif %}>Cameroon</option>
|
||||
<option value="Canada" {% if user.country == "Canada" %}selected{% endif %}>Canada</option>
|
||||
<option value="Central African Republic" {% if user.country == "Central African Republic" %}selected{% endif %}>Central African Republic</option>
|
||||
<option value="Chad" {% if user.country == "Chad" %}selected{% endif %}>Chad</option>
|
||||
<option value="Chile" {% if user.country == "Chile" %}selected{% endif %}>Chile</option>
|
||||
<option value="China" {% if user.country == "China" %}selected{% endif %}>China</option>
|
||||
<option value="Colombia" {% if user.country == "Colombia" %}selected{% endif %}>Colombia</option>
|
||||
<option value="Comoros" {% if user.country == "Comoros" %}selected{% endif %}>Comoros</option>
|
||||
<option value="Congo" {% if user.country == "Congo" %}selected{% endif %}>Congo</option>
|
||||
<option value="Costa Rica" {% if user.country == "Costa Rica" %}selected{% endif %}>Costa Rica</option>
|
||||
<option value="Croatia" {% if user.country == "Croatia" %}selected{% endif %}>Croatia</option>
|
||||
<option value="Cuba" {% if user.country == "Cuba" %}selected{% endif %}>Cuba</option>
|
||||
<option value="Cyprus" {% if user.country == "Cyprus" %}selected{% endif %}>Cyprus</option>
|
||||
<option value="Czech Republic" {% if user.country == "Czech Republic" %}selected{% endif %}>Czech Republic</option>
|
||||
<option value="Democratic Republic of the Congo" {% if user.country == "Democratic Republic of the Congo" %}selected{% endif %}>Democratic Republic of the Congo</option>
|
||||
<option value="Denmark" {% if user.country == "Denmark" %}selected{% endif %}>Denmark</option>
|
||||
<option value="Djibouti" {% if user.country == "Djibouti" %}selected{% endif %}>Djibouti</option>
|
||||
<option value="Dominica" {% if user.country == "Dominica" %}selected{% endif %}>Dominica</option>
|
||||
<option value="Dominican Republic" {% if user.country == "Dominican Republic" %}selected{% endif %}>Dominican Republic</option>
|
||||
<option value="Ecuador" {% if user.country == "Ecuador" %}selected{% endif %}>Ecuador</option>
|
||||
<option value="Egypt" {% if user.country == "Egypt" %}selected{% endif %}>Egypt</option>
|
||||
<option value="El Salvador" {% if user.country == "El Salvador" %}selected{% endif %}>El Salvador</option>
|
||||
<option value="Equatorial Guinea" {% if user.country == "Equatorial Guinea" %}selected{% endif %}>Equatorial Guinea</option>
|
||||
<option value="Eritrea" {% if user.country == "Eritrea" %}selected{% endif %}>Eritrea</option>
|
||||
<option value="Estonia" {% if user.country == "Estonia" %}selected{% endif %}>Estonia</option>
|
||||
<option value="Eswatini" {% if user.country == "Eswatini" %}selected{% endif %}>Eswatini</option>
|
||||
<option value="Ethiopia" {% if user.country == "Ethiopia" %}selected{% endif %}>Ethiopia</option>
|
||||
<option value="Fiji" {% if user.country == "Fiji" %}selected{% endif %}>Fiji</option>
|
||||
<option value="Finland" {% if user.country == "Finland" %}selected{% endif %}>Finland</option>
|
||||
<option value="France" {% if user.country == "France" %}selected{% endif %}>France</option>
|
||||
<option value="Gabon" {% if user.country == "Gabon" %}selected{% endif %}>Gabon</option>
|
||||
<option value="Gambia" {% if user.country == "Gambia" %}selected{% endif %}>Gambia</option>
|
||||
<option value="Georgia" {% if user.country == "Georgia" %}selected{% endif %}>Georgia</option>
|
||||
<option value="Germany" {% if user.country == "Germany" %}selected{% endif %}>Germany</option>
|
||||
<option value="Ghana" {% if user.country == "Ghana" %}selected{% endif %}>Ghana</option>
|
||||
<option value="Greece" {% if user.country == "Greece" %}selected{% endif %}>Greece</option>
|
||||
<option value="Grenada" {% if user.country == "Grenada" %}selected{% endif %}>Grenada</option>
|
||||
<option value="Guatemala" {% if user.country == "Guatemala" %}selected{% endif %}>Guatemala</option>
|
||||
<option value="Guinea" {% if user.country == "Guinea" %}selected{% endif %}>Guinea</option>
|
||||
<option value="Guinea-Bissau" {% if user.country == "Guinea-Bissau" %}selected{% endif %}>Guinea-Bissau</option>
|
||||
<option value="Guyana" {% if user.country == "Guyana" %}selected{% endif %}>Guyana</option>
|
||||
<option value="Haiti" {% if user.country == "Haiti" %}selected{% endif %}>Haiti</option>
|
||||
<option value="Honduras" {% if user.country == "Honduras" %}selected{% endif %}>Honduras</option>
|
||||
<option value="Hungary" {% if user.country == "Hungary" %}selected{% endif %}>Hungary</option>
|
||||
<option value="Iceland" {% if user.country == "Iceland" %}selected{% endif %}>Iceland</option>
|
||||
<option value="India" {% if user.country == "India" %}selected{% endif %}>India</option>
|
||||
<option value="Indonesia" {% if user.country == "Indonesia" %}selected{% endif %}>Indonesia</option>
|
||||
<option value="Iran" {% if user.country == "Iran" %}selected{% endif %}>Iran</option>
|
||||
<option value="Iraq" {% if user.country == "Iraq" %}selected{% endif %}>Iraq</option>
|
||||
<option value="Ireland" {% if user.country == "Ireland" %}selected{% endif %}>Ireland</option>
|
||||
<option value="Israel" {% if user.country == "Israel" %}selected{% endif %}>Israel</option>
|
||||
<option value="Italy" {% if user.country == "Italy" %}selected{% endif %}>Italy</option>
|
||||
<option value="Ivory Coast" {% if user.country == "Ivory Coast" %}selected{% endif %}>Ivory Coast</option>
|
||||
<option value="Jamaica" {% if user.country == "Jamaica" %}selected{% endif %}>Jamaica</option>
|
||||
<option value="Japan" {% if user.country == "Japan" %}selected{% endif %}>Japan</option>
|
||||
<option value="Jordan" {% if user.country == "Jordan" %}selected{% endif %}>Jordan</option>
|
||||
<option value="Kazakhstan" {% if user.country == "Kazakhstan" %}selected{% endif %}>Kazakhstan</option>
|
||||
<option value="Kenya" {% if user.country == "Kenya" %}selected{% endif %}>Kenya</option>
|
||||
<option value="Kiribati" {% if user.country == "Kiribati" %}selected{% endif %}>Kiribati</option>
|
||||
<option value="Kuwait" {% if user.country == "Kuwait" %}selected{% endif %}>Kuwait</option>
|
||||
<option value="Kyrgyzstan" {% if user.country == "Kyrgyzstan" %}selected{% endif %}>Kyrgyzstan</option>
|
||||
<option value="Laos" {% if user.country == "Laos" %}selected{% endif %}>Laos</option>
|
||||
<option value="Latvia" {% if user.country == "Latvia" %}selected{% endif %}>Latvia</option>
|
||||
<option value="Lebanon" {% if user.country == "Lebanon" %}selected{% endif %}>Lebanon</option>
|
||||
<option value="Lesotho" {% if user.country == "Lesotho" %}selected{% endif %}>Lesotho</option>
|
||||
<option value="Liberia" {% if user.country == "Liberia" %}selected{% endif %}>Liberia</option>
|
||||
<option value="Libya" {% if user.country == "Libya" %}selected{% endif %}>Libya</option>
|
||||
<option value="Liechtenstein" {% if user.country == "Liechtenstein" %}selected{% endif %}>Liechtenstein</option>
|
||||
<option value="Lithuania" {% if user.country == "Lithuania" %}selected{% endif %}>Lithuania</option>
|
||||
<option value="Luxembourg" {% if user.country == "Luxembourg" %}selected{% endif %}>Luxembourg</option>
|
||||
<option value="Madagascar" {% if user.country == "Madagascar" %}selected{% endif %}>Madagascar</option>
|
||||
<option value="Malawi" {% if user.country == "Malawi" %}selected{% endif %}>Malawi</option>
|
||||
<option value="Malaysia" {% if user.country == "Malaysia" %}selected{% endif %}>Malaysia</option>
|
||||
<option value="Maldives" {% if user.country == "Maldives" %}selected{% endif %}>Maldives</option>
|
||||
<option value="Mali" {% if user.country == "Mali" %}selected{% endif %}>Mali</option>
|
||||
<option value="Malta" {% if user.country == "Malta" %}selected{% endif %}>Malta</option>
|
||||
<option value="Marshall Islands" {% if user.country == "Marshall Islands" %}selected{% endif %}>Marshall Islands</option>
|
||||
<option value="Mauritania" {% if user.country == "Mauritania" %}selected{% endif %}>Mauritania</option>
|
||||
<option value="Mauritius" {% if user.country == "Mauritius" %}selected{% endif %}>Mauritius</option>
|
||||
<option value="Mexico" {% if user.country == "Mexico" %}selected{% endif %}>Mexico</option>
|
||||
<option value="Micronesia" {% if user.country == "Micronesia" %}selected{% endif %}>Micronesia</option>
|
||||
<option value="Moldova" {% if user.country == "Moldova" %}selected{% endif %}>Moldova</option>
|
||||
<option value="Monaco" {% if user.country == "Monaco" %}selected{% endif %}>Monaco</option>
|
||||
<option value="Mongolia" {% if user.country == "Mongolia" %}selected{% endif %}>Mongolia</option>
|
||||
<option value="Montenegro" {% if user.country == "Montenegro" %}selected{% endif %}>Montenegro</option>
|
||||
<option value="Morocco" {% if user.country == "Morocco" %}selected{% endif %}>Morocco</option>
|
||||
<option value="Mozambique" {% if user.country == "Mozambique" %}selected{% endif %}>Mozambique</option>
|
||||
<option value="Myanmar" {% if user.country == "Myanmar" %}selected{% endif %}>Myanmar</option>
|
||||
<option value="Namibia" {% if user.country == "Namibia" %}selected{% endif %}>Namibia</option>
|
||||
<option value="Nauru" {% if user.country == "Nauru" %}selected{% endif %}>Nauru</option>
|
||||
<option value="Nepal" {% if user.country == "Nepal" %}selected{% endif %}>Nepal</option>
|
||||
<option value="Netherlands" {% if user.country == "Netherlands" %}selected{% endif %}>Netherlands</option>
|
||||
<option value="New Zealand" {% if user.country == "New Zealand" %}selected{% endif %}>New Zealand</option>
|
||||
<option value="Nicaragua" {% if user.country == "Nicaragua" %}selected{% endif %}>Nicaragua</option>
|
||||
<option value="Niger" {% if user.country == "Niger" %}selected{% endif %}>Niger</option>
|
||||
<option value="Nigeria" {% if user.country == "Nigeria" %}selected{% endif %}>Nigeria</option>
|
||||
<option value="North Korea" {% if user.country == "North Korea" %}selected{% endif %}>North Korea</option>
|
||||
<option value="North Macedonia" {% if user.country == "North Macedonia" %}selected{% endif %}>North Macedonia</option>
|
||||
<option value="Norway" {% if user.country == "Norway" %}selected{% endif %}>Norway</option>
|
||||
<option value="Oman" {% if user.country == "Oman" %}selected{% endif %}>Oman</option>
|
||||
<option value="Pakistan" {% if user.country == "Pakistan" %}selected{% endif %}>Pakistan</option>
|
||||
<option value="Palau" {% if user.country == "Palau" %}selected{% endif %}>Palau</option>
|
||||
<option value="Palestine" {% if user.country == "Palestine" %}selected{% endif %}>Palestine</option>
|
||||
<option value="Panama" {% if user.country == "Panama" %}selected{% endif %}>Panama</option>
|
||||
<option value="Papua New Guinea" {% if user.country == "Papua New Guinea" %}selected{% endif %}>Papua New Guinea</option>
|
||||
<option value="Paraguay" {% if user.country == "Paraguay" %}selected{% endif %}>Paraguay</option>
|
||||
<option value="Peru" {% if user.country == "Peru" %}selected{% endif %}>Peru</option>
|
||||
<option value="Philippines" {% if user.country == "Philippines" %}selected{% endif %}>Philippines</option>
|
||||
<option value="Poland" {% if user.country == "Poland" %}selected{% endif %}>Poland</option>
|
||||
<option value="Portugal" {% if user.country == "Portugal" %}selected{% endif %}>Portugal</option>
|
||||
<option value="Qatar" {% if user.country == "Qatar" %}selected{% endif %}>Qatar</option>
|
||||
<option value="Romania" {% if user.country == "Romania" %}selected{% endif %}>Romania</option>
|
||||
<option value="Russia" {% if user.country == "Russia" %}selected{% endif %}>Russia</option>
|
||||
<option value="Rwanda" {% if user.country == "Rwanda" %}selected{% endif %}>Rwanda</option>
|
||||
<option value="Saint Kitts and Nevis" {% if user.country == "Saint Kitts and Nevis" %}selected{% endif %}>Saint Kitts and Nevis</option>
|
||||
<option value="Saint Lucia" {% if user.country == "Saint Lucia" %}selected{% endif %}>Saint Lucia</option>
|
||||
<option value="Saint Vincent and the Grenadines" {% if user.country == "Saint Vincent and the Grenadines" %}selected{% endif %}>Saint Vincent and the Grenadines</option>
|
||||
<option value="Samoa" {% if user.country == "Samoa" %}selected{% endif %}>Samoa</option>
|
||||
<option value="San Marino" {% if user.country == "San Marino" %}selected{% endif %}>San Marino</option>
|
||||
<option value="Sao Tome and Principe" {% if user.country == "Sao Tome and Principe" %}selected{% endif %}>Sao Tome and Principe</option>
|
||||
<option value="Saudi Arabia" {% if user.country == "Saudi Arabia" %}selected{% endif %}>Saudi Arabia</option>
|
||||
<option value="Senegal" {% if user.country == "Senegal" %}selected{% endif %}>Senegal</option>
|
||||
<option value="Serbia" {% if user.country == "Serbia" %}selected{% endif %}>Serbia</option>
|
||||
<option value="Seychelles" {% if user.country == "Seychelles" %}selected{% endif %}>Seychelles</option>
|
||||
<option value="Sierra Leone" {% if user.country == "Sierra Leone" %}selected{% endif %}>Sierra Leone</option>
|
||||
<option value="Singapore" {% if user.country == "Singapore" %}selected{% endif %}>Singapore</option>
|
||||
<option value="Slovakia" {% if user.country == "Slovakia" %}selected{% endif %}>Slovakia</option>
|
||||
<option value="Slovenia" {% if user.country == "Slovenia" %}selected{% endif %}>Slovenia</option>
|
||||
<option value="Solomon Islands" {% if user.country == "Solomon Islands" %}selected{% endif %}>Solomon Islands</option>
|
||||
<option value="Somalia" {% if user.country == "Somalia" %}selected{% endif %}>Somalia</option>
|
||||
<option value="South Africa" {% if user.country == "South Africa" %}selected{% endif %}>South Africa</option>
|
||||
<option value="South Korea" {% if user.country == "South Korea" %}selected{% endif %}>South Korea</option>
|
||||
<option value="South Sudan" {% if user.country == "South Sudan" %}selected{% endif %}>South Sudan</option>
|
||||
<option value="Spain" {% if user.country == "Spain" %}selected{% endif %}>Spain</option>
|
||||
<option value="Sri Lanka" {% if user.country == "Sri Lanka" %}selected{% endif %}>Sri Lanka</option>
|
||||
<option value="Sudan" {% if user.country == "Sudan" %}selected{% endif %}>Sudan</option>
|
||||
<option value="Suriname" {% if user.country == "Suriname" %}selected{% endif %}>Suriname</option>
|
||||
<option value="Sweden" {% if user.country == "Sweden" %}selected{% endif %}>Sweden</option>
|
||||
<option value="Switzerland" {% if user.country == "Switzerland" %}selected{% endif %}>Switzerland</option>
|
||||
<option value="Syria" {% if user.country == "Syria" %}selected{% endif %}>Syria</option>
|
||||
<option value="Taiwan" {% if user.country == "Taiwan" %}selected{% endif %}>Taiwan</option>
|
||||
<option value="Tajikistan" {% if user.country == "Tajikistan" %}selected{% endif %}>Tajikistan</option>
|
||||
<option value="Tanzania" {% if user.country == "Tanzania" %}selected{% endif %}>Tanzania</option>
|
||||
<option value="Thailand" {% if user.country == "Thailand" %}selected{% endif %}>Thailand</option>
|
||||
<option value="Timor-Leste" {% if user.country == "Timor-Leste" %}selected{% endif %}>Timor-Leste</option>
|
||||
<option value="Togo" {% if user.country == "Togo" %}selected{% endif %}>Togo</option>
|
||||
<option value="Tonga" {% if user.country == "Tonga" %}selected{% endif %}>Tonga</option>
|
||||
<option value="Trinidad and Tobago" {% if user.country == "Trinidad and Tobago" %}selected{% endif %}>Trinidad and Tobago</option>
|
||||
<option value="Tunisia" {% if user.country == "Tunisia" %}selected{% endif %}>Tunisia</option>
|
||||
<option value="Turkey" {% if user.country == "Turkey" %}selected{% endif %}>Turkey</option>
|
||||
<option value="Turkmenistan" {% if user.country == "Turkmenistan" %}selected{% endif %}>Turkmenistan</option>
|
||||
<option value="Tuvalu" {% if user.country == "Tuvalu" %}selected{% endif %}>Tuvalu</option>
|
||||
<option value="Uganda" {% if user.country == "Uganda" %}selected{% endif %}>Uganda</option>
|
||||
<option value="Ukraine" {% if user.country == "Ukraine" %}selected{% endif %}>Ukraine</option>
|
||||
<option value="United Arab Emirates" {% if user.country == "United Arab Emirates" %}selected{% endif %}>United Arab Emirates</option>
|
||||
<option value="United Kingdom" {% if user.country == "United Kingdom" %}selected{% endif %}>United Kingdom</option>
|
||||
<option value="United States" {% if user.country == "United States" %}selected{% endif %}>United States</option>
|
||||
<option value="Uruguay" {% if user.country == "Uruguay" %}selected{% endif %}>Uruguay</option>
|
||||
<option value="Uzbekistan" {% if user.country == "Uzbekistan" %}selected{% endif %}>Uzbekistan</option>
|
||||
<option value="Vanuatu" {% if user.country == "Vanuatu" %}selected{% endif %}>Vanuatu</option>
|
||||
<option value="Vatican City" {% if user.country == "Vatican City" %}selected{% endif %}>Vatican City</option>
|
||||
<option value="Venezuela" {% if user.country == "Venezuela" %}selected{% endif %}>Venezuela</option>
|
||||
<option value="Vietnam" {% if user.country == "Vietnam" %}selected{% endif %}>Vietnam</option>
|
||||
<option value="Yemen" {% if user.country == "Yemen" %}selected{% endif %}>Yemen</option>
|
||||
<option value="Zambia" {% if user.country == "Zambia" %}selected{% endif %}>Zambia</option>
|
||||
<option value="Zimbabwe" {% if user.country == "Zimbabwe" %}selected{% endif %}>Zimbabwe</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="timezone" class="col-sm-3 col-form-label">Time Zone</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-select" id="timezone" name="timezone">
|
||||
<option value="">Choose timezone...</option>
|
||||
<option value="UTC-12:00" {% if user.timezone == "UTC-12:00" %}selected{% endif %}>UTC-12:00 (Baker Island)</option>
|
||||
<option value="UTC-11:00" {% if user.timezone == "UTC-11:00" %}selected{% endif %}>UTC-11:00 (American Samoa, Niue)</option>
|
||||
<option value="UTC-10:00" {% if user.timezone == "UTC-10:00" %}selected{% endif %}>UTC-10:00 (Hawaii-Aleutian Standard Time)</option>
|
||||
<option value="UTC-09:30" {% if user.timezone == "UTC-09:30" %}selected{% endif %}>UTC-09:30 (Marquesas Islands)</option>
|
||||
<option value="UTC-09:00" {% if user.timezone == "UTC-09:00" %}selected{% endif %}>UTC-09:00 (Alaska Standard Time)</option>
|
||||
<option value="UTC-08:00" {% if user.timezone == "UTC-08:00" %}selected{% endif %}>UTC-08:00 (Pacific Standard Time - Los Angeles, Vancouver)</option>
|
||||
<option value="UTC-07:00" {% if user.timezone == "UTC-07:00" %}selected{% endif %}>UTC-07:00 (Mountain Standard Time - Denver, Calgary)</option>
|
||||
<option value="UTC-06:00" {% if user.timezone == "UTC-06:00" %}selected{% endif %}>UTC-06:00 (Central Standard Time - Chicago, Mexico City)</option>
|
||||
<option value="UTC-05:00" {% if user.timezone == "UTC-05:00" %}selected{% endif %}>UTC-05:00 (Eastern Standard Time - New York, Toronto)</option>
|
||||
<option value="UTC-04:00" {% if user.timezone == "UTC-04:00" %}selected{% endif %}>UTC-04:00 (Atlantic Standard Time - Halifax, Caracas)</option>
|
||||
<option value="UTC-03:30" {% if user.timezone == "UTC-03:30" %}selected{% endif %}>UTC-03:30 (Newfoundland Standard Time)</option>
|
||||
<option value="UTC-03:00" {% if user.timezone == "UTC-03:00" %}selected{% endif %}>UTC-03:00 (Argentina, Brazil, Uruguay)</option>
|
||||
<option value="UTC-02:00" {% if user.timezone == "UTC-02:00" %}selected{% endif %}>UTC-02:00 (South Georgia and the South Sandwich Islands)</option>
|
||||
<option value="UTC-01:00" {% if user.timezone == "UTC-01:00" %}selected{% endif %}>UTC-01:00 (Azores, Cape Verde)</option>
|
||||
<option value="UTC+00:00" {% if user.timezone == "UTC+00:00" %}selected{% endif %}>UTC+00:00 (Greenwich Mean Time - London, Dublin, Lisbon)</option>
|
||||
<option value="UTC+01:00" {% if user.timezone == "UTC+01:00" %}selected{% endif %}>UTC+01:00 (Central European Time - Berlin, Paris, Rome)</option>
|
||||
<option value="UTC+02:00" {% if user.timezone == "UTC+02:00" %}selected{% endif %}>UTC+02:00 (Eastern European Time - Athens, Cairo, Helsinki)</option>
|
||||
<option value="UTC+03:00" {% if user.timezone == "UTC+03:00" %}selected{% endif %}>UTC+03:00 (Moscow Standard Time - Moscow, Istanbul, Nairobi)</option>
|
||||
<option value="UTC+03:30" {% if user.timezone == "UTC+03:30" %}selected{% endif %}>UTC+03:30 (Iran Standard Time - Tehran)</option>
|
||||
<option value="UTC+04:00" {% if user.timezone == "UTC+04:00" %}selected{% endif %}>UTC+04:00 (Gulf Standard Time - Dubai, Baku)</option>
|
||||
<option value="UTC+04:30" {% if user.timezone == "UTC+04:30" %}selected{% endif %}>UTC+04:30 (Afghanistan Time - Kabul)</option>
|
||||
<option value="UTC+05:00" {% if user.timezone == "UTC+05:00" %}selected{% endif %}>UTC+05:00 (Pakistan Standard Time - Karachi, Tashkent)</option>
|
||||
<option value="UTC+05:30" {% if user.timezone == "UTC+05:30" %}selected{% endif %}>UTC+05:30 (India Standard Time - Mumbai, Delhi, Colombo)</option>
|
||||
<option value="UTC+05:45" {% if user.timezone == "UTC+05:45" %}selected{% endif %}>UTC+05:45 (Nepal Time - Kathmandu)</option>
|
||||
<option value="UTC+06:00" {% if user.timezone == "UTC+06:00" %}selected{% endif %}>UTC+06:00 (Bangladesh Standard Time - Dhaka, Almaty)</option>
|
||||
<option value="UTC+06:30" {% if user.timezone == "UTC+06:30" %}selected{% endif %}>UTC+06:30 (Myanmar Time - Yangon, Cocos Islands)</option>
|
||||
<option value="UTC+07:00" {% if user.timezone == "UTC+07:00" %}selected{% endif %}>UTC+07:00 (Indochina Time - Bangkok, Jakarta, Ho Chi Minh City)</option>
|
||||
<option value="UTC+08:00" {% if user.timezone == "UTC+08:00" %}selected{% endif %}>UTC+08:00 (China Standard Time - Beijing, Singapore, Manila)</option>
|
||||
<option value="UTC+08:45" {% if user.timezone == "UTC+08:45" %}selected{% endif %}>UTC+08:45 (Australian Central Western Standard Time)</option>
|
||||
<option value="UTC+09:00" {% if user.timezone == "UTC+09:00" %}selected{% endif %}>UTC+09:00 (Japan Standard Time - Tokyo, Seoul, Pyongyang)</option>
|
||||
<option value="UTC+09:30" {% if user.timezone == "UTC+09:30" %}selected{% endif %}>UTC+09:30 (Australian Central Standard Time - Adelaide, Darwin)</option>
|
||||
<option value="UTC+10:00" {% if user.timezone == "UTC+10:00" %}selected{% endif %}>UTC+10:00 (Australian Eastern Standard Time - Sydney, Melbourne)</option>
|
||||
<option value="UTC+10:30" {% if user.timezone == "UTC+10:30" %}selected{% endif %}>UTC+10:30 (Lord Howe Standard Time)</option>
|
||||
<option value="UTC+11:00" {% if user.timezone == "UTC+11:00" %}selected{% endif %}>UTC+11:00 (Solomon Islands, New Caledonia)</option>
|
||||
<option value="UTC+12:00" {% if user.timezone == "UTC+12:00" %}selected{% endif %}>UTC+12:00 (New Zealand Standard Time - Auckland, Fiji)</option>
|
||||
<option value="UTC+12:45" {% if user.timezone == "UTC+12:45" %}selected{% endif %}>UTC+12:45 (Chatham Standard Time)</option>
|
||||
<option value="UTC+13:00" {% if user.timezone == "UTC+13:00" %}selected{% endif %}>UTC+13:00 (Tonga, Samoa)</option>
|
||||
<option value="UTC+14:00" {% if user.timezone == "UTC+14:00" %}selected{% endif %}>UTC+14:00 (Line Islands, Kiribati)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary">Save Changes</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="tab-pane fade" id="v-pills-password" role="tabpanel" aria-labelledby="v-pills-password-tab">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Change Password</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="passwordForm">
|
||||
<div class="row mb-3">
|
||||
<label for="current-password" class="col-sm-3 col-form-label">Current Password</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" id="current-password" name="current_password" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="new-password" class="col-sm-3 col-form-label">New Password</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" id="new-password" name="new_password" minlength="12" required>
|
||||
<small class="text-muted">Password must be at least 12 characters long with a mix of letters, numbers, and special characters</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="confirm-password" class="col-sm-3 col-form-label">Confirm Password</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" id="confirm-password" name="confirm_password" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary">Update Password</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SSH Keys -->
|
||||
<div class="tab-pane fade" id="v-pills-ssh-keys" role="tabpanel" aria-labelledby="v-pills-ssh-keys-tab">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5>SSH Keys</h5>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="addSSHKeyBtn">
|
||||
<i class="bi bi-plus-circle me-1"></i>Add SSH Key
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>SSH Keys for Self-Managed Resources:</strong> Upload your SSH public keys to access self-managed VMs and Kubernetes clusters. Your keys are stored securely and can be used across multiple deployments.
|
||||
</div>
|
||||
|
||||
<!-- SSH Keys List -->
|
||||
<div id="sshKeysList">
|
||||
<div class="text-center p-4" id="noSSHKeysMessage">
|
||||
<i class="bi bi-key display-4 text-muted"></i>
|
||||
<p class="mt-2 text-muted">No SSH keys found. Add your first SSH key to get started.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SSH Key Template (hidden, used for JS cloning) -->
|
||||
<div class="d-none" id="sshKeyTemplate">
|
||||
<div class="card mb-3 ssh-key-item" data-key-id="">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-key me-2 text-primary"></i>
|
||||
<div>
|
||||
<h6 class="mb-1 ssh-key-name">Key Name</h6>
|
||||
<small class="text-muted ssh-key-type">Key Type</small>
|
||||
<span class="badge bg-success ms-2 ssh-key-default d-none">Default</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<small class="text-muted">
|
||||
<strong>Fingerprint:</strong> <code class="ssh-key-fingerprint">SHA256:...</code>
|
||||
</small>
|
||||
</div>
|
||||
<div class="mt-1">
|
||||
<small class="text-muted ssh-key-created">Added: Never</small>
|
||||
<small class="text-muted ssh-key-last-used ms-3">Last used: Never</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 text-end">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm set-default-btn">
|
||||
Set Default
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm edit-ssh-key-btn">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm delete-ssh-key-btn">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Currency Preferences -->
|
||||
<div class="tab-pane fade" id="v-pills-currency" role="tabpanel" aria-labelledby="v-pills-currency-tab">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Currency Preferences</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="currencyForm">
|
||||
<div class="row mb-4">
|
||||
<label for="displayCurrency" class="col-sm-3 col-form-label">Display Currency</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-select" id="displayCurrency" name="display_currency">
|
||||
<option value="USD" {% if user_display_currency == "USD" %}selected{% endif %}>USD - US Dollar</option>
|
||||
<option value="TFC" {% if user_display_currency == "TFC" %}selected{% endif %}>TFC - ThreeFold Credits</option>
|
||||
<option value="EUR" {% if user_display_currency == "EUR" %}selected{% endif %}>EUR - Euro</option>
|
||||
<option value="CAD" {% if user_display_currency == "CAD" %}selected{% endif %}>CAD - Canadian Dollar</option>
|
||||
</select>
|
||||
<small class="text-muted">Choose your preferred currency for displaying prices in the marketplace</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>Note:</strong> All transactions are processed in USD Credits. Display currency is used for convenience only and prices are converted in real-time.
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary">Save Currency Preferences</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete Account -->
|
||||
<div class="tab-pane fade" id="v-pills-delete" role="tabpanel" aria-labelledby="v-pills-delete-tab">
|
||||
<div class="card border-danger">
|
||||
<div class="card-header bg-danger text-white">
|
||||
<h5>Delete Account</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-warning">
|
||||
<h5><i class="bi bi-exclamation-triangle me-2"></i>Warning: This action is irreversible</h5>
|
||||
<p>Deleting your account will permanently remove all your data, including:</p>
|
||||
<ul>
|
||||
<li>Your profile information</li>
|
||||
<li>Your deployment configurations</li>
|
||||
<li>Your billing history</li>
|
||||
</ul>
|
||||
<p class="mb-0"><strong>Note:</strong> Any active deployments must be manually terminated before account deletion.</p>
|
||||
</div>
|
||||
<form id="deleteAccountForm" class="mt-4">
|
||||
<div class="mb-3">
|
||||
<label for="deleteConfirmation" class="form-label">Type "DELETE" to confirm</label>
|
||||
<input type="text" class="form-control" id="deleteConfirmation" name="confirmation" placeholder="Type DELETE in all caps" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="deletePassword" class="form-label">Your current password</label>
|
||||
<input type="password" class="form-control" id="deletePassword" name="password" required>
|
||||
<div id="deletePasswordFeedback" class="invalid-feedback">Incorrect password.</div>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="deleteCheck" required>
|
||||
<label class="form-check-label" for="deleteCheck">I understand this action cannot be undone</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-danger">Delete My Account</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom Delete Confirmation Modal -->
|
||||
<div class="modal fade" id="deleteConfirmationModal" tabindex="-1" aria-labelledby="deleteConfirmationModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-danger">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5 class="modal-title" id="deleteConfirmationModalLabel">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>Final Confirmation Required
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-warning">
|
||||
<h6><strong>This is your final warning!</strong></h6>
|
||||
<p class="mb-0">You are about to permanently delete your account. This action will:</p>
|
||||
</div>
|
||||
<ul class="mb-3">
|
||||
<li>Mark your account as deleted (data preserved for recovery)</li>
|
||||
<li>Prevent you from logging in</li>
|
||||
<li>Hide your services and apps from the marketplace</li>
|
||||
<li>Require administrator assistance to recover</li>
|
||||
</ul>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>Type "I UNDERSTAND" to proceed:</strong></label>
|
||||
<input type="text" class="form-control" id="finalConfirmationInput" placeholder="Type I UNDERSTAND">
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="text-muted mb-0">Deletion will proceed in <span id="countdownTimer" class="fw-bold text-danger">10</span> seconds after confirmation</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" id="finalDeleteButton" disabled>
|
||||
<span id="deleteButtonText">Confirm Deletion</span>
|
||||
<span id="deleteButtonSpinner" class="spinner-border spinner-border-sm ms-2 d-none" role="status"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SSH Key Management Modals -->
|
||||
|
||||
<!-- Add SSH Key Modal -->
|
||||
<div class="modal fade" id="addSSHKeyModal" tabindex="-1" aria-labelledby="addSSHKeyModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addSSHKeyModalLabel">
|
||||
<i class="bi bi-key me-2"></i>Add SSH Key
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="addSSHKeyForm">
|
||||
<div class="mb-3">
|
||||
<label for="sshKeyName" class="form-label">Key Name</label>
|
||||
<input type="text" class="form-control" id="sshKeyName" name="name" placeholder="e.g., MacBook Pro, Work Laptop" required>
|
||||
<div class="form-text">Choose a descriptive name to identify this key</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="sshPublicKey" class="form-label">SSH Public Key</label>
|
||||
<textarea class="form-control" id="sshPublicKey" name="public_key" rows="4" placeholder="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... user@example.com" required></textarea>
|
||||
<div class="form-text">
|
||||
Paste your SSH public key here. Supported formats: Ed25519, ECDSA, RSA (2048+ bits)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="setAsDefault" name="is_default">
|
||||
<label class="form-check-label" for="setAsDefault">
|
||||
Set as default key for new deployments
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>How to find your SSH public key:</strong>
|
||||
<ul class="mb-0 mt-2">
|
||||
<li><strong>Linux/macOS:</strong> <code>cat ~/.ssh/id_ed25519.pub</code> or <code>cat ~/.ssh/id_rsa.pub</code></li>
|
||||
<li><strong>Windows:</strong> <code>type %USERPROFILE%\.ssh\id_ed25519.pub</code></li>
|
||||
<li><strong>Generate new key:</strong> <code>ssh-keygen -t ed25519 -C "your_email@example.com"</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Key validation feedback -->
|
||||
<div id="keyValidationFeedback" class="d-none">
|
||||
<div class="alert alert-success" id="keyValidationSuccess">
|
||||
<i class="bi bi-check-circle me-2"></i>
|
||||
<span id="keyValidationSuccessText">Valid SSH key detected!</span>
|
||||
</div>
|
||||
<div class="alert alert-danger" id="keyValidationError">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
<span id="keyValidationErrorText">Invalid SSH key format</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="addSSHKeyForm" class="btn btn-primary" id="addSSHKeySubmit">
|
||||
<span id="addSSHKeyText">Add SSH Key</span>
|
||||
<span id="addSSHKeySpinner" class="spinner-border spinner-border-sm ms-2 d-none" role="status"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit SSH Key Modal -->
|
||||
<div class="modal fade" id="editSSHKeyModal" tabindex="-1" aria-labelledby="editSSHKeyModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="editSSHKeyModalLabel">
|
||||
<i class="bi bi-pencil me-2"></i>Edit SSH Key
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="editSSHKeyForm">
|
||||
<input type="hidden" id="editSSHKeyId" name="keyId">
|
||||
<div class="mb-3">
|
||||
<label for="editSSHKeyName" class="form-label">Key Name</label>
|
||||
<input type="text" class="form-control" id="editSSHKeyName" name="name" required>
|
||||
<div class="form-text">Choose a descriptive name to identify this key</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="editSetAsDefault" name="is_default">
|
||||
<label class="form-check-label" for="editSetAsDefault">
|
||||
Set as default key for new deployments
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="editSSHKeyForm" class="btn btn-primary" id="editSSHKeySubmit">
|
||||
<span id="editSSHKeyText">Update SSH Key</span>
|
||||
<span id="editSSHKeySpinner" class="spinner-border spinner-border-sm ms-2 d-none" role="status"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete SSH Key Modal -->
|
||||
<div class="modal fade" id="deleteSSHKeyModal" tabindex="-1" aria-labelledby="deleteSSHKeyModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deleteSSHKeyModalLabel">
|
||||
<i class="bi bi-trash me-2"></i>Delete SSH Key
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="deleteSSHKeyForm">
|
||||
<input type="hidden" id="deleteSSHKeyId" name="keyId">
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
<strong>Are you sure?</strong>
|
||||
</div>
|
||||
<p>You are about to delete the SSH key:</p>
|
||||
<p><strong id="deleteSSHKeyName">Key Name</strong></p>
|
||||
<p class="text-muted">This action cannot be undone. If this key is currently used for deployments, you may lose access to those resources.</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="deleteSSHKeyForm" class="btn btn-danger" id="deleteSSHKeySubmit">
|
||||
<span id="deleteSSHKeyText">Delete SSH Key</span>
|
||||
<span id="deleteSSHKeySpinner" class="spinner-border spinner-border-sm ms-2 d-none" role="status"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SSH Keys Data Hydration -->
|
||||
<script type="application/json" id="ssh-keys-data">{{ ssh_keys_json | default(value="[]") | safe }}</script>
|
||||
|
||||
<script src="/static/js/dashboard-settings.js"></script>
|
||||
|
||||
<!-- SSH Key Management Script -->
|
||||
<script src="/static/js/dashboard-ssh-keys.js"></script>
|
||||
{% endblock %}
|
492
src/views/dashboard/user.html
Normal file
492
src/views/dashboard/user.html
Normal file
@@ -0,0 +1,492 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - User{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<h1>User Dashboard</h1>
|
||||
<p class="lead">Manage your applications, resources, and monitor usage</p>
|
||||
|
||||
<!-- Status Summary -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card primary">
|
||||
<h5 class="card-title">Active Apps</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ active_applications_count | default(value=0) }}</h2>
|
||||
<small class="text-muted">Deployments</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card success">
|
||||
<h5 class="card-title">Slices</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ active_compute_resources_count | default(value=0) }}</h2>
|
||||
<small class="text-muted">Active Resources</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card info">
|
||||
<h5 class="card-title">Uptime</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ average_sla_percentage | default(value=99.0) | round(precision=1) }}%</h2>
|
||||
<small class="text-muted">Average</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card warning">
|
||||
<h5 class="card-title">Cost Rate</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ total_monthly_cost | default(value=0) | format_decimal(precision=2) }}</h2>
|
||||
<small class="text-muted">{{ currency_symbol | default(value="$") }}/month</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Quick Actions</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<a href="/marketplace/applications" class="btn btn-primary w-100 mb-2">
|
||||
<i class="bi bi-box-seam me-2"></i> Deploy Applications
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<a href="/marketplace/compute" class="btn btn-success w-100 mb-2">
|
||||
<i class="bi bi-cpu me-2"></i> Deploy Slices
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Applications Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>My Applications</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Status</th>
|
||||
<th>Uptime</th>
|
||||
<th>Resources</th>
|
||||
<th>Cost</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="applications-table">
|
||||
<tr>
|
||||
<td colspan="7" class="text-center text-muted">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
Loading applications...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Compute Resources (Slices) Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h3>My Compute Resources</h3>
|
||||
<a href="/marketplace/compute" class="btn btn-outline-primary">
|
||||
<i class="bi bi-plus-circle me-2"></i> Reserve More Resources
|
||||
</a>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Resource ID</th>
|
||||
<th>Type</th>
|
||||
<th>Specs</th>
|
||||
<th>Location</th>
|
||||
<th>Status</th>
|
||||
<th>SLA</th>
|
||||
<th>Cost</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="compute-resources-table">
|
||||
<tr>
|
||||
<td colspan="8" class="text-center text-muted">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
Loading compute resources...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Slice Rentals Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h3>My Slice Rentals</h3>
|
||||
<div>
|
||||
<button type="button" class="btn btn-outline-secondary me-2" id="refresh-slice-rentals">
|
||||
<i class="fas fa-sync-alt me-1"></i> Refresh
|
||||
</button>
|
||||
<a href="/marketplace/compute" class="btn btn-outline-primary">
|
||||
<i class="fas fa-plus me-1"></i> Rent More Slices
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Slice Rentals Stats -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card primary">
|
||||
<h6 class="card-title">Active Rentals</h6>
|
||||
<h4 class="mb-0" id="active-rentals-count">0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card success">
|
||||
<h6 class="card-title">VM Deployments</h6>
|
||||
<h4 class="mb-0" id="vm-deployments-count">0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card info">
|
||||
<h6 class="card-title">Kubernetes Clusters</h6>
|
||||
<h4 class="mb-0" id="k8s-deployments-count">0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card warning">
|
||||
<h6 class="card-title">Monthly Cost</h6>
|
||||
<h4 class="mb-0" id="slice-monthly-cost">$0</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Slice Rentals Cards Container -->
|
||||
<div class="row" id="slice-rentals-container">
|
||||
<div class="col-12 text-center py-5">
|
||||
<div class="spinner-border text-primary me-2" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<span class="text-muted">Loading slice rentals...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Deployment Management Modal -->
|
||||
<div class="modal fade" id="deploymentModal" tabindex="-1" aria-labelledby="deploymentModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deploymentModalLabel">Manage Deployment</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Content will be populated by JavaScript -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cancel Rental Modal -->
|
||||
<div class="modal fade" id="cancelModal" tabindex="-1" aria-labelledby="cancelModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="cancelModalLabel">Cancel Slice Rental</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Content will be populated by JavaScript -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" id="confirmCancelBtn">Confirm Cancellation</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Bookings Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h3>My Service Bookings</h3>
|
||||
<a href="/marketplace/services" class="btn btn-outline-primary">
|
||||
<i class="bi bi-plus-circle me-2"></i> Book More Services
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Service Bookings Stats (populated by JS) -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card primary">
|
||||
<h6 class="card-title">Active Bookings</h6>
|
||||
<h4 class="mb-0" id="active-bookings-count">0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card success">
|
||||
<h6 class="card-title">Completed</h6>
|
||||
<h4 class="mb-0" id="completed-bookings-count">0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card info">
|
||||
<h6 class="card-title">Total Spent</h6>
|
||||
<h4 class="mb-0" id="total-spent">$0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card warning">
|
||||
<h6 class="card-title">Monthly Spending</h6>
|
||||
<h4 class="mb-0" id="monthly-spending">$0</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Bookings Table (populated by JS) -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Service</th>
|
||||
<th>Provider</th>
|
||||
<th>Status</th>
|
||||
<th>Progress</th>
|
||||
<th>Budget</th>
|
||||
<th>Requested Date</th>
|
||||
<th>Priority</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="service-bookings-tbody">
|
||||
<tr>
|
||||
<td colspan="8" class="text-center text-muted">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
Loading service bookings...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Favorite Providers (optional, populated by JS if available) -->
|
||||
<div class="mt-4" id="favorite-providers-section" style="display: none;">
|
||||
<h5>Favorite Providers</h5>
|
||||
<div class="d-flex flex-wrap gap-2" id="favorite-providers"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Usage Monitoring Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Usage Monitoring</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Credits Usage Trend</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="creditsUsageChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Resource Utilization</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="resourceUtilizationChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Additional Charts Row -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>User Activity Trends</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="userActivityChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Deployment Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="deploymentDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activities Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Recent Activities</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Action</th>
|
||||
<th>Status</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="recent-activities-tbody">
|
||||
<!-- Activities will be populated by JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resource Utilization Progress Bars -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Current Resource Utilization</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<span class="text-muted">CPU Usage</span>
|
||||
<span id="cpu-percentage" class="fw-bold">0%</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div id="cpu-progress" class="progress-bar bg-primary" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<span class="text-muted">Memory Usage</span>
|
||||
<span id="memory-percentage" class="fw-bold">0%</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div id="memory-progress" class="progress-bar bg-success" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<span class="text-muted">Storage Usage</span>
|
||||
<span id="storage-percentage" class="fw-bold">0%</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div id="storage-progress" class="progress-bar bg-warning" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<span class="text-muted">Network Usage</span>
|
||||
<span id="network-percentage" class="fw-bold">0%</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div id="network-progress" class="progress-bar bg-danger" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Booking Details Modal -->
|
||||
<div class="modal fade" id="bookingDetailsModal" tabindex="-1" aria-labelledby="bookingDetailsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="bookingDetailsModalLabel">Service Booking Details</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="bookingDetailsContent">
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<p class="mt-2">Loading booking details...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" id="contactProviderBtn" style="display: none;">
|
||||
<i class="bi bi-chat-dots me-1"></i> Contact Provider
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||
|
||||
<!-- Load dashboard JavaScript -->
|
||||
<script src="/static/js/dashboard-user.js"></script>
|
||||
|
||||
<style>
|
||||
/* Ensure charts have consistent sizes */
|
||||
.card-body {
|
||||
min-height: 340px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
442
src/views/dashboard/wallet.html
Normal file
442
src/views/dashboard/wallet.html
Normal file
@@ -0,0 +1,442 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Credits Wallet</h1>
|
||||
</div>
|
||||
|
||||
<!-- Wallet Balance Card -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card bg-primary text-white">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<i class="bi bi-coin"></i> Current Balance
|
||||
</h5>
|
||||
<h2 class="card-text" id="wallet-balance">
|
||||
{% if wallet_balance %}
|
||||
{{ currency_symbol | default(value="$") }}{{ wallet_balance | format_decimal(precision=2) }}
|
||||
{% else %}
|
||||
{{ currency_symbol | default(value="$") }}0.00
|
||||
{% endif %}
|
||||
</h2>
|
||||
<small class="text-light">Credits ({{ display_currency | default(value="USD") }})</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card bg-success text-white">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<i class="bi bi-graph-up"></i> Available Balance
|
||||
</h5>
|
||||
<h2 class="card-text" id="usd-equivalent">
|
||||
{% if wallet_balance %}
|
||||
{{ currency_symbol | default(value="$") }}{{ wallet_balance | format_decimal(precision=2) }}
|
||||
{% else %}
|
||||
{{ currency_symbol | default(value="$") }}0.00
|
||||
{% endif %}
|
||||
</h2>
|
||||
<small class="text-light">Ready to spend</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Wallet Actions</h5>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#buyCreditsModal">
|
||||
<i class="bi bi-plus-circle"></i> Buy Credits
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#transferCreditsModal">
|
||||
<i class="bi bi-send"></i> Transfer Credits
|
||||
</button>
|
||||
<button type="button" class="btn btn-info" data-action="refresh-wallet">
|
||||
<i class="bi bi-arrow-clockwise"></i> Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Auto Top-Up Settings -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="bi bi-lightning-charge"></i> Auto Top-Up Settings
|
||||
</h5>
|
||||
<span class="badge bg-secondary" id="autoTopUpStatus">Loading...</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="autoTopUpContent">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<button type="button" class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#configureAutoTopUpModal">
|
||||
<i class="bi bi-gear"></i> Configure Auto Top-Up
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Owned Products and Active Rentals -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="bi bi-box"></i> Owned Products
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if owned_products and owned_products|length > 0 %}
|
||||
<div class="list-group list-group-flush">
|
||||
{% for product_id in owned_products %}
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<strong>Product {{ product_id }}</strong><br>
|
||||
<small class="text-muted">Owned Product</small>
|
||||
</div>
|
||||
<span class="badge bg-success rounded-pill">Owned</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-muted">No owned products yet.</p>
|
||||
<a href="/marketplace" class="btn btn-outline-primary btn-sm">Browse Marketplace</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="bi bi-clock"></i> Active Rentals
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if active_rentals and active_rentals|length > 0 %}
|
||||
<div class="list-group list-group-flush">
|
||||
{% for rental_id in active_rentals %}
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<strong>Rental {{ rental_id }}</strong><br>
|
||||
<small class="text-muted">Active Rental</small>
|
||||
</div>
|
||||
<span class="badge bg-primary rounded-pill">Active</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-muted">No active rentals.</p>
|
||||
<a href="/marketplace" class="btn btn-outline-primary btn-sm">Browse Marketplace</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Transactions -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="bi bi-clock-history"></i> Recent Transactions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" id="transactions-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Type</th>
|
||||
<th>Amount ({{ currency_symbol | default(value="$") }})</th>
|
||||
<th>Status</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="transactions-tbody">
|
||||
{% if transaction_history %}
|
||||
{% for transaction in transaction_history %}
|
||||
<tr>
|
||||
<td>{{ transaction.formatted_timestamp }}</td>
|
||||
<td>
|
||||
{% if transaction.transaction_type.CreditsPurchase %}
|
||||
<span class="badge bg-success">Credits Purchase</span>
|
||||
{% elif transaction.transaction_type.CreditsSale %}
|
||||
<span class="badge bg-danger">Credits Sale</span>
|
||||
{% elif transaction.transaction_type.Rental %}
|
||||
<span class="badge bg-primary">Rental</span>
|
||||
{% elif transaction.transaction_type.Purchase %}
|
||||
<span class="badge bg-danger">Purchase</span>
|
||||
{% elif transaction.transaction_type.InstantPurchase %}
|
||||
<span class="badge bg-danger">Purchase</span>
|
||||
{% elif transaction.transaction_type.CreditsTransfer or transaction.transaction_type.Transfer %}
|
||||
<span class="badge bg-info">Credits Transfer</span>
|
||||
{% elif transaction.transaction_type.Earning %}
|
||||
<span class="badge bg-success">Earning</span>
|
||||
{% elif transaction.transaction_type.Exchange %}
|
||||
<span class="badge bg-secondary">Exchange</span>
|
||||
{% elif transaction.transaction_type.Stake %}
|
||||
<span class="badge bg-primary">Stake</span>
|
||||
{% elif transaction.transaction_type.Unstake %}
|
||||
<span class="badge bg-warning">Unstake</span>
|
||||
{% else %}
|
||||
<span class="badge bg-light text-dark">Unknown</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if transaction.transaction_type.CreditsPurchase or transaction.transaction_type.Earning or transaction.transaction_type.Unstake %}
|
||||
<span class="text-success">+{{ transaction.amount | format_decimal(precision=2) }}</span>
|
||||
{% elif transaction.transaction_type.CreditsSale %}
|
||||
<span class="text-danger">-{{ transaction.amount | format_decimal(precision=2) }}</span>
|
||||
{% elif transaction.transaction_type.Exchange %}
|
||||
{% if transaction.amount > 0 %}
|
||||
<span class="text-success">+{{ transaction.amount | format_decimal(precision=2) }}</span>
|
||||
{% else %}
|
||||
<span class="text-danger">-{{ transaction.amount | abs | format_decimal(precision=2) }}</span>
|
||||
{% endif %}
|
||||
{% elif transaction.transaction_type.Purchase or transaction.transaction_type.InstantPurchase or transaction.transaction_type.Rental or transaction.transaction_type.Transfer or transaction.transaction_type.CreditsTransfer or transaction.transaction_type.Stake %}
|
||||
<span class="text-danger">-{{ transaction.amount | format_decimal(precision=2) }}</span>
|
||||
{% else %}
|
||||
<span class="text-muted">{{ transaction.amount | format_decimal(precision=2) }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if transaction.status == "Completed" %}
|
||||
<span class="badge bg-success">{{ transaction.status }}</span>
|
||||
{% elif transaction.status == "Pending" %}
|
||||
<span class="badge bg-warning">{{ transaction.status }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-danger">{{ transaction.status }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ transaction.id }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="5" class="text-center text-muted">No transactions yet</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy Credits Modal -->
|
||||
<div class="modal fade" id="buyCreditsModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Buy Credits</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="buyCreditsForm">
|
||||
<div class="mb-3">
|
||||
<label for="creditsAmount" class="form-label">Amount ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="creditsAmount" min="1" max="10000" step="1" required>
|
||||
<div class="form-text">Minimum: {{ currency_symbol | default(value="$") }}1, Maximum: {{ currency_symbol | default(value="$") }}10,000</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="paymentMethod" class="form-label">Payment Method</label>
|
||||
<select class="form-select" id="paymentMethod" required>
|
||||
<option value="">Select payment method</option>
|
||||
<option value="credit_card">Credit Card</option>
|
||||
<option value="paypal">PayPal</option>
|
||||
<option value="bank_transfer">Bank Transfer</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="alert alert-info">
|
||||
<strong>Rate:</strong> 1 Credit = {{ currency_symbol | default(value="$") }}1 {{ display_currency | default(value="USD") }}<br>
|
||||
<strong>Total Cost:</strong> {{ currency_symbol | default(value="$") }}<span id="totalCost">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-action="buy-credits">Purchase Credits</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transfer Credits Modal -->
|
||||
<div class="modal fade" id="transferCreditsModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Transfer Credits</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="transferCreditsForm">
|
||||
<div class="mb-3">
|
||||
<label for="recipientEmail" class="form-label">Recipient Email</label>
|
||||
<input type="email" class="form-control" id="recipientEmail" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="transferAmount" class="form-label">Amount ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="transferAmount" min="1" step="1" required>
|
||||
<div class="form-text">Available balance: {{ currency_symbol | default(value="$") }}<span id="availableBalance">{% if wallet_balance %}{{ wallet_balance | format_decimal(precision=2) }}{% else %}0.00{% endif %}</span></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="transferNote" class="form-label">Note (Optional)</label>
|
||||
<textarea class="form-control" id="transferNote" rows="2" placeholder="Add a note for this transfer"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-action="transfer-credits">Send Transfer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Configure Auto Top-Up Modal -->
|
||||
<div class="modal fade" id="configureAutoTopUpModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">
|
||||
<i class="bi bi-lightning-charge"></i> Configure Auto Top-Up
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="autoTopUpForm">
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="autoTopUpEnabled">
|
||||
<label class="form-check-label" for="autoTopUpEnabled">
|
||||
<strong>Enable Auto Top-Up</strong>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-text">Automatically add credits when your balance falls below the threshold</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="autoTopUpSettings" style="display: none;">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="thresholdAmount" class="form-label">Threshold Amount ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="thresholdAmount" min="1" max="1000" step="1" value="10">
|
||||
<div class="form-text">Trigger auto top-up when balance falls below this amount</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="topUpAmount" class="form-label">Top-Up Amount ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="topUpAmount" min="5" max="1000" step="5" value="50">
|
||||
<div class="form-text">Amount to add when auto top-up is triggered</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-3">
|
||||
<label for="autoTopUpPaymentMethod" class="form-label">Payment Method</label>
|
||||
<select class="form-select" id="autoTopUpPaymentMethod" required>
|
||||
<option value="">Select payment method</option>
|
||||
<option value="credit_card">Credit Card</option>
|
||||
<option value="paypal">PayPal</option>
|
||||
<option value="bank_transfer">Bank Transfer</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="dailyLimit" class="form-label">Daily Limit ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="dailyLimit" min="0" max="5000" step="10" value="200">
|
||||
<div class="form-text">Maximum auto top-up per day (0 = no limit)</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="monthlyLimit" class="form-label">Monthly Limit ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="monthlyLimit" min="0" max="50000" step="50" value="2000">
|
||||
<div class="form-text">Maximum auto top-up per month (0 = no limit)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<h6 class="alert-heading">
|
||||
<i class="bi bi-info-circle"></i> How Auto Top-Up Works
|
||||
</h6>
|
||||
<ul class="mb-0">
|
||||
<li>When your balance falls below the threshold, we'll automatically add the specified top-up amount</li>
|
||||
<li>Auto top-up only triggers during purchase attempts, not continuously</li>
|
||||
<li>Daily and monthly limits help control spending</li>
|
||||
<li>You can disable auto top-up at any time</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-action="save-auto-topup-settings">
|
||||
<i class="bi bi-check-lg"></i> Save Settings
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Container for Success Messages -->
|
||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||
<div id="successToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-success text-white">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>
|
||||
<strong class="me-auto">Success</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="successToastBody">
|
||||
Operation completed successfully!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="errorToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-danger text-white">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<strong class="me-auto">Error</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="errorToastBody">
|
||||
An error occurred!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="application/json" id="wallet-hydration">
|
||||
{
|
||||
"currency_symbol": {{ currency_symbol | default(value='$') | json_encode() }},
|
||||
"display_currency": {{ display_currency | default(value='USD') | json_encode() }}
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/dashboard_wallet.js"></script>
|
||||
{% endblock %}
|
91
src/views/dashboard/welcome.html
Normal file
91
src/views/dashboard/welcome.html
Normal file
@@ -0,0 +1,91 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - Welcome{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-10">
|
||||
<div class="card shadow-lg border-0">
|
||||
<div class="card-body p-5">
|
||||
<div class="text-center mb-5">
|
||||
<h1 class="display-4 fw-bold text-primary">Welcome to ThreeFold Dashboard</h1>
|
||||
<p class="lead text-muted">Your central hub for managing your ThreeFold experience</p>
|
||||
</div>
|
||||
|
||||
<div class="row mb-5 align-items-center">
|
||||
<div class="col-md-6 text-center">
|
||||
<img src="/static/images/dashboard-illustration.svg" alt="Dashboard Illustration" class="img-fluid" onerror="this.src='/static/images/logo_light.png'; this.onerror=null;">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>Access Your Dashboard</h2>
|
||||
<p class="mb-4">The ThreeFold Dashboard gives you all the tools to manage your resources, monitor your nodes, deploy applications, and more - all in one place.</p>
|
||||
|
||||
<div class="d-grid gap-3">
|
||||
<a href="/login" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-box-arrow-in-right me-2"></i> Log In
|
||||
</a>
|
||||
{% if gitea_enabled == false %}
|
||||
<a href="/register" class="btn btn-outline-primary btn-lg">
|
||||
<i class="bi bi-person-plus me-2"></i> Register
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-12">
|
||||
<h2 class="text-center mb-4">What You Can Do in Your Dashboard</h2>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-4 mb-3 text-primary">
|
||||
<i class="bi bi-person"></i>
|
||||
</div>
|
||||
<h5>As a User</h5>
|
||||
<p>Deploy applications, manage slices, monitor costs</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-4 mb-3 text-success">
|
||||
<i class="bi bi-hdd-rack"></i>
|
||||
</div>
|
||||
<h5>As a Farmer</h5>
|
||||
<p>Manage nodes, configure slices, set pricing</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-4 mb-3 text-info">
|
||||
<i class="bi bi-app"></i>
|
||||
</div>
|
||||
<h5>As an App Provider</h5>
|
||||
<p>Offer applications, monitor deployments</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-4 mb-3 text-warning">
|
||||
<i class="bi bi-person-workspace"></i>
|
||||
</div>
|
||||
<h5>As a Service Provider</h5>
|
||||
<p>Offer services, manage maintenance requests</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
Reference in New Issue
Block a user