Files
projectmycelium/src/views/marketplace/compute_resources.html

445 lines
18 KiB
HTML

{% extends "marketplace/layout.html" %}
{% block title %}Mycelium Marketplace - Compute Resources{% endblock %}
{% block marketplace_content %}
<div class="my-4">
<h1>Compute Resources (Slices)</h1>
<p class="lead">Find and acquire the compute resources you need for your workloads.</p>
<!-- Enhanced Filter Section -->
<div class="filter-section p-4 mb-4">
<h5 class="mb-3">Filter Resources</h5>
<form id="filterForm" method="GET">
<div class="enhanced-filters">
<div>
<label class="form-label">Location</label>
<select name="location" class="form-select">
<option value="">All Locations</option>
<option value="Belgium">Belgium</option>
<option value="Austria">Austria</option>
<option value="Switzerland">Switzerland</option>
<option value="Netherlands">Netherlands</option>
<option value="Germany">Germany</option>
<option value="France">France</option>
<option value="UK">UK</option>
<option value="Canada">Canada</option>
<option value="USA">USA</option>
<option value="Japan">Japan</option>
</select>
</div>
<div>
<label class="form-label">Min vCores</label>
<select name="min_cores" class="form-select">
<option value="">Any</option>
<option value="1">1 Core+</option>
<option value="2">2 Cores+</option>
<option value="4">4 Cores+</option>
<option value="8">8 Cores+</option>
<option value="16">16 Cores+</option>
</select>
</div>
<div>
<label class="form-label">Min RAM (GB)</label>
<select name="min_memory" class="form-select">
<option value="">Any</option>
<option value="4">4 GB+</option>
<option value="8">8 GB+</option>
<option value="16">16 GB+</option>
<option value="32">32 GB+</option>
</select>
</div>
<div>
<label class="form-label">Min Storage (GB)</label>
<select name="min_storage" class="form-select">
<option value="">Any</option>
<option value="200">200 GB+</option>
<option value="500">500 GB+</option>
<option value="1000">1 TB+</option>
<option value="2000">2 TB+</option>
</select>
</div>
<div>
<label class="form-label">Min Uptime (%)</label>
<select name="min_uptime" class="form-select">
<option value="">Any</option>
<option value="95">95%+</option>
<option value="98">98%+</option>
<option value="99">99%+</option>
<option value="99.9">99.9%+</option>
</select>
</div>
<div>
<label class="form-label">Min Bandwidth (Mbps)</label>
<select name="min_bandwidth" class="form-select">
<option value="">Any</option>
<option value="100">100 Mbps+</option>
<option value="500">500 Mbps+</option>
<option value="1000">1 Gbps+</option>
</select>
</div>
<div>
<label class="form-label">Price Range ($)</label>
<div class="d-flex gap-2">
<input type="number" name="min_price" class="form-control" placeholder="Min" style="width: 80px;">
<input type="number" name="max_price" class="form-control" placeholder="Max" style="width: 80px;">
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Apply Filters</button>
<a href="/marketplace/compute" class="btn btn-outline-secondary ms-2">Clear</a>
</div>
</div>
</form>
</div>
<!-- Table Section -->
{% if compute_products and compute_products | length > 0 %}
<div class="compute-table">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead>
<tr>
<th style="width: 15%;">Type</th>
<th style="width: 12%;">Provider</th>
<th style="width: 10%;">Location</th>
<th style="width: 8%;">vCores</th>
<th style="width: 8%;">RAM</th>
<th style="width: 10%;">Storage (SSD)</th>
<th style="width: 10%;">Uptime SLA</th>
<th style="width: 10%;">Bandwidth SLA</th>
<th style="width: 8%;">Price/Hour</th>
<th style="width: 9%;">Actions</th>
</tr>
</thead>
<tbody>
{% for product_data in compute_products %}
<tr>
<td>
<div class="slice-name">{{ product_data.product.name }}</div>
<div class="slice-info">
<small class="text-muted d-block">
{% if product_data.product.attributes.cpu_cores %}
{{ product_data.product.attributes.cpu_cores.value }}x Base Unit
{% else %}
Compute slice
{% endif %}
</small>
</div>
</td>
<td>
<div class="provider-name">
{% if product_data.product.attributes.resource_provider_email %}
{{ product_data.product.attributes.resource_provider_email.value | truncate(length=15) }}
{% else %}
{% if product_data.product.provider %}{{ product_data.product.provider }}{% else %}Unknown{% endif %}
{% endif %}
</div>
</td>
<td>
{% if product_data.product.metadata.location %}
<span class="location-badge node-location"
data-location="{{ product_data.product.metadata.location }}">
{{ product_data.product.metadata.location }}
</span>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td>
{% if product_data.product.attributes.cpu_cores %}
<span class="spec-value">{{ product_data.product.attributes.cpu_cores.value }}</span>
<span class="spec-unit">cores</span>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td>
{% if product_data.product.attributes.memory_gb %}
<span class="spec-value">{{ product_data.product.attributes.memory_gb.value }}</span>
<span class="spec-unit">GB</span>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td>
{% if product_data.product.attributes.storage_gb %}
<span class="spec-value">{{ product_data.product.attributes.storage_gb.value }}</span>
<span class="spec-unit">GB</span>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td>
{% if product_data.product.attributes.uptime_percentage %}
<div class="sla-indicator sla-good">
<i class="bi bi-check-circle-fill"></i>
<span>{{ product_data.product.attributes.uptime_percentage.value | format_decimal(precision=1) }}%</span>
</div>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td>
{% if product_data.product.attributes.bandwidth_mbps %}
<div class="sla-indicator sla-good">
<i class="bi bi-speedometer2"></i>
<span>{{ product_data.product.attributes.bandwidth_mbps.value }} Mbps</span>
</div>
{% else %}
<div class="sla-indicator sla-good">
<i class="bi bi-speedometer2"></i>
<span>1000 Mbps</span>
</div>
{% endif %}
</td>
<td>
<div class="price-display">{{ product_data.formatted_price }}</div>
</td>
<td>
<div class="action-buttons">
<button class="btn btn-success btn-sm-custom buy-now-btn"
data-product-id="{{ product_data.product.id }}"
data-product-name="{{ product_data.product.name }}"
data-unit-price="{{ product_data.price.display_amount }}"
data-currency="{{ product_data.price.display_currency }}"
data-category="compute">
<i class="bi bi-lightning-charge"></i> Buy Now
</button>
<button class="btn btn-primary btn-sm-custom add-to-cart-btn"
data-product-id="{{ product_data.product.id }}"
data-product-name="{{ product_data.product.name }}"
data-unit-price="{{ product_data.price.display_amount }}"
data-currency="{{ product_data.price.display_currency }}">
<i class="bi bi-cart-plus"></i> Add to Cart
</button>
<a class="btn btn-outline-secondary btn-sm-custom" href="/products/{{ product_data.product.id }}">
<i class="bi bi-eye"></i> View
</a>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% else %}
<div class="text-center py-5">
<i class="bi bi-inbox display-1 text-muted"></i>
<h4 class="mt-3">No Compute Resources Available</h4>
<p class="text-muted">Check back later for new compute resources.</p>
</div>
{% endif %}
<!-- Pagination -->
{% if pagination and pagination.total_pages > 1 %}
<nav aria-label="Resource pages" class="mt-4">
<ul class="pagination justify-content-center">
<!-- Previous Page -->
<li class="page-item {% if not pagination.has_previous %}disabled{% endif %}">
{% if pagination.has_previous %}
<a class="page-link" href="?page={{ pagination.previous_page }}">Previous</a>
{% else %}
<span class="page-link" tabindex="-1" aria-disabled="true">Previous</span>
{% endif %}
</li>
<!-- Page 1 -->
<li class="page-item {% if pagination.current_page == 0 %}active{% endif %}">
{% if pagination.current_page == 0 %}
<span class="page-link">1</span>
{% else %}
<a class="page-link" href="?page=0">1</a>
{% endif %}
</li>
<!-- Page 2 (if exists) -->
{% if pagination.total_pages > 1 %}
<li class="page-item {% if pagination.current_page == 1 %}active{% endif %}">
{% if pagination.current_page == 1 %}
<span class="page-link">2</span>
{% else %}
<a class="page-link" href="?page=1">2</a>
{% endif %}
</li>
{% endif %}
<!-- Page 3 (if exists) -->
{% if pagination.total_pages > 2 %}
<li class="page-item {% if pagination.current_page == 2 %}active{% endif %}">
{% if pagination.current_page == 2 %}
<span class="page-link">3</span>
{% else %}
<a class="page-link" href="?page=2">3</a>
{% endif %}
</li>
{% endif %}
<!-- Page 4 (if exists) -->
{% if pagination.total_pages > 3 %}
<li class="page-item {% if pagination.current_page == 3 %}active{% endif %}">
{% if pagination.current_page == 3 %}
<span class="page-link">4</span>
{% else %}
<a class="page-link" href="?page=3">4</a>
{% endif %}
</li>
{% endif %}
<!-- Page 5 (if exists) -->
{% if pagination.total_pages > 4 %}
<li class="page-item {% if pagination.current_page == 4 %}active{% endif %}">
{% if pagination.current_page == 4 %}
<span class="page-link">5</span>
{% else %}
<a class="page-link" href="?page=4">5</a>
{% endif %}
</li>
{% endif %}
<!-- Next Page -->
<li class="page-item {% if not pagination.has_next %}disabled{% endif %}">
{% if pagination.has_next %}
<a class="page-link" href="?page={{ pagination.next_page }}">Next</a>
{% else %}
<span class="page-link" tabindex="-1" aria-disabled="true">Next</span>
{% endif %}
</li>
</ul>
</nav>
<!-- Results Info -->
<div class="text-center text-muted mt-2">
Showing page {{ pagination.current_page + 1 }} of {{ pagination.total_pages }}
({{ pagination.total_count }} total compute resources)
</div>
{% endif %}
</div>
<style>
.compute-table {
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
overflow: hidden;
}
.compute-table th {
background-color: #f8f9fa;
border-bottom: 2px solid #dee2e6;
font-weight: 600;
color: #495057;
padding: 12px 8px;
font-size: 0.9rem;
}
.compute-table td {
padding: 12px 8px;
vertical-align: middle;
border-bottom: 1px solid #f1f3f4;
}
.compute-table tbody tr:hover {
background-color: #f8f9fa;
}
.provider-name {
font-weight: 600;
color: #0d6efd;
font-size: 0.95rem;
}
.slice-info {
margin-top: 2px;
}
.slice-name {
font-weight: 500;
color: #212529;
font-size: 0.9rem;
}
.spec-value {
font-weight: 500;
color: #212529;
}
.spec-unit {
color: #6c757d;
font-size: 0.85rem;
}
.location-badge {
background-color: #e3f2fd;
color: #1976d2;
padding: 4px 8px;
border-radius: 12px;
font-size: 0.8rem;
font-weight: 500;
}
.sla-indicator {
display: flex;
align-items: center;
gap: 4px;
}
.sla-good { color: #28a745; }
.sla-medium { color: #ffc107; }
.sla-low { color: #dc3545; }
.price-display {
font-weight: 600;
color: #0d6efd;
font-size: 1.1rem;
}
.action-buttons {
display: flex;
gap: 4px;
flex-wrap: wrap;
}
.btn-sm-custom {
padding: 4px 8px;
font-size: 0.8rem;
border-radius: 4px;
}
@media (max-width: 768px) {
.compute-table {
font-size: 0.85rem;
}
.compute-table th,
.compute-table td {
padding: 8px 4px;
}
.action-buttons {
flex-direction: column;
}
}
.filter-section {
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.enhanced-filters {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
align-items: end;
}
</style>
{% endblock %}
{% block scripts %}
<script type="application/json" id="compute-hydration">{}</script>
<script src="/static/js/marketplace-compute.js"></script>
{% endblock %}