You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

215 lines
6.7 KiB

package app
import (
"fmt"
"github.com/seaweedfs/seaweedfs/weed/admin/dash"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables"
)
templ IcebergCatalog(data dash.IcebergCatalogData) {
<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="fas fa-snowflake me-2"></i>Iceberg Catalog
</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group me-2">
<a href={ templ.SafeURL("/v1/config") } target="_blank" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-external-link-alt me-1"></i>REST API
</a>
</div>
</div>
</div>
<div id="iceberg-catalog-content">
<!-- Info Alert about Iceberg REST -->
<div class="alert alert-info mb-4">
<div class="d-flex align-items-center">
<i class="fas fa-info-circle fa-2x me-3"></i>
<div>
<strong>Iceberg REST Catalog</strong>
<p class="mb-0 mt-1">
Connect your Iceberg clients (DuckDB, Spark, etc.) to:
<code>http://<span id="iceberg-host">localhost</span>:{fmt.Sprintf("%d", data.IcebergPort)}/v1</code>
</p>
<script>
document.getElementById('iceberg-host').innerText = window.location.hostname;
</script>
</div>
</div>
</div>
<!-- Stats Cards -->
<div class="row mb-4">
<div class="col-xl-4 col-md-6 mb-4">
<div class="card border-left-primary shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
Catalogs (Table Buckets)
</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
{ fmt.Sprintf("%d", data.TotalCatalogs) }
</div>
</div>
<div class="col-auto">
<i class="fas fa-database fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-md-6 mb-4">
<div class="card border-left-success shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">
REST Port
</div>
<div class="h5 mb-0 font-weight-bold text-gray-800">
{ fmt.Sprintf("%d", data.IcebergPort) }
</div>
</div>
<div class="col-auto">
<i class="fas fa-plug fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-md-6 mb-4">
<div class="card border-left-info shadow h-100 py-2">
<div class="card-body">
<div class="row no-gutters align-items-center">
<div class="col mr-2">
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">
Last Updated
</div>
<div class="h6 mb-0 font-weight-bold text-gray-800">
{ data.LastUpdated.Format("15:04") }
</div>
</div>
<div class="col-auto">
<i class="fas fa-clock fa-2x text-gray-300"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Catalog List -->
<div class="row">
<div class="col-12">
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold text-primary">
<i class="fas fa-snowflake me-2"></i>Available Catalogs
</h6>
</div>
<div class="card-body">
<p class="text-muted mb-3">
Each S3 Table Bucket acts as an Iceberg catalog. Use the bucket name as the catalog prefix in your REST API calls.
</p>
<div class="table-responsive">
<table class="table table-hover" width="100%" cellspacing="0" id="icebergCatalogsTable">
<thead>
<tr>
<th>Catalog Name</th>
<th>Owner</th>
<th>REST Endpoint</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
for _, catalog := range data.Catalogs {
<tr>
<td>
<i class="fas fa-snowflake text-info me-2"></i>
<strong>{ catalog.Name }</strong>
</td>
<td>{ catalog.OwnerAccountID }</td>
<td>
<code class="small">/v1/{ catalog.Name }/namespaces</code>
</td>
<td>{ catalog.CreatedAt.Format("2006-01-02 15:04") }</td>
<td>
<div class="btn-group btn-group-sm" role="group">
{{ bucketName, parseErr := s3tables.ParseBucketNameFromARN(catalog.ARN) }}
if parseErr == nil {
<a class="btn btn-outline-primary btn-sm" href={ templ.SafeURL(fmt.Sprintf("/object-store/iceberg/%s/namespaces", bucketName)) } title="Browse Namespaces">
<i class="fas fa-folder-open"></i>
</a>
}
</div>
</td>
</tr>
}
if len(data.Catalogs) == 0 {
<tr>
<td colspan="5" class="text-center text-muted py-4">
<i class="fas fa-snowflake fa-3x mb-3 text-muted"></i>
<div>
<h5>No catalogs available</h5>
<p>Create an S3 Table Bucket first to use as an Iceberg catalog.</p>
<a href="/object-store/s3tables/buckets" class="btn btn-primary">
<i class="fas fa-plus me-1"></i>Create Table Bucket
</a>
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Example Usage Card -->
<div class="row">
<div class="col-12">
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary">
<i class="fas fa-code me-2"></i>Example Usage
</h6>
</div>
<div class="card-body">
<h6>DuckDB</h6>
<pre class="bg-light p-3 border rounded"><code>{ `-- Install and load Iceberg extension
INSTALL iceberg;
LOAD iceberg;
-- Create a catalog connection
CREATE SECRET (
TYPE ICEBERG,
ENDPOINT 'http://localhost:` + fmt.Sprintf("%d", data.IcebergPort) + `',
SCOPE 's3://my-table-bucket/'
);
-- Query tables
SELECT * FROM iceberg_scan('s3://my-table-bucket/my-namespace/my-table');` }</code></pre>
<h6 class="mt-4">Python (PyIceberg)</h6>
<pre class="bg-light p-3 border rounded"><code>{ `from pyiceberg.catalog import load_catalog
catalog = load_catalog(
name="seaweedfs",
**{
"type": "rest",
"uri": "http://localhost:` + fmt.Sprintf("%d", data.IcebergPort) + `",
}
)
# List namespaces
namespaces = catalog.list_namespaces()` }</code></pre>
</div>
</div>
</div>
</div>
</div>
}