384 lines
18 KiB
Plaintext
384 lines
18 KiB
Plaintext
<% @page_title = @pg[:name]
|
|
edit_perm = has_permission?("Postgres:edit", @pg[:id])
|
|
delete_perm = has_permission?("Postgres:delete", @pg[:id]) %>
|
|
|
|
<%== render(
|
|
"components/page_header",
|
|
locals: {
|
|
breadcrumbs: [
|
|
%w[Projects /project],
|
|
[@project_data[:name], @project_data[:path]],
|
|
["PostgreSQL Databases", "#{@project_data[:path]}/postgres"],
|
|
[@pg[:name], "#"]
|
|
],
|
|
right_items: [render("components/pg_state_label", locals: { state: @pg[:state], extra_class: "text-md" })]
|
|
}
|
|
) %>
|
|
|
|
<div class="grid gap-6">
|
|
<!-- Detail Card -->
|
|
<% data = [
|
|
["ID", @pg[:id]],
|
|
["Name", @pg[:name]],
|
|
["Location", @pg[:location]],
|
|
["Compute", @pg[:vm_size]],
|
|
["Storage", "#{@pg[:storage_size_gib]} GB"],
|
|
["Version", "Postgres #{@pg[:version]}"],
|
|
["High Availability", PG_HA_DATA[@pg[:ha_type]]]
|
|
]
|
|
|
|
if @pg[:connection_string]
|
|
data.push(["Connection String", @pg[:connection_string], { copyable: true, revealable: true }])
|
|
else
|
|
data.push(["Connection String", "Waiting for host to be ready..."])
|
|
end
|
|
|
|
if @pg[:ca_certificates]
|
|
data.push(
|
|
[
|
|
"CA Certificates",
|
|
render("components/download_button", locals: { link: "#{request.path}/ca-certificates" }),
|
|
{ escape: false }
|
|
]
|
|
)
|
|
else
|
|
data.push(["CA Certificates", "Waiting for host to be ready..."])
|
|
end %>
|
|
|
|
<div class="grid grid-cols-1 gap-6 md:grid-cols-6">
|
|
<div class="<%= (@pg[:flavor] == PostgresResource::Flavor::STANDARD) ? "col-span-6" : "md:col-span-3" %>">
|
|
<%== render("components/kv_data_card", locals: { data: data }) %>
|
|
</div>
|
|
<% if @pg[:flavor] == PostgresResource::Flavor::PARADEDB %>
|
|
<div class="md:col-span-3">
|
|
<div class="overflow-hidden rounded-lg shadow ring-1 ring-black ring-opacity-5 bg-white divide-y divide-gray-200">
|
|
<div class="px-4 py-5 sm:p-6">
|
|
<div class="space-y-2">
|
|
<img src="/logo-paradedb.png" class="h-6 object-contain mb-4"/>
|
|
<p class="text-sm text-gray-500 leading-6">
|
|
ParadeDB is an Elasticsearch alternative built on Postgres. ParadeDB instances are managed by the
|
|
ParadeDB team and are optimal for search and analytics workloads.
|
|
</p>
|
|
<div class="text-sm text-gray-500 leading-6">
|
|
<span class="font-semibold">Support:</span>
|
|
<ul class="list-disc list-inside ml-2">
|
|
<li>Via email at
|
|
<a href="mailto:support@paradedb.com" class="text-orange-600 font-semibold">support@paradedb.com</a></li>
|
|
<li>Via Slack at
|
|
<a
|
|
href="https://join.slack.com/t/paradedbcommunity/shared_invite/zt-2lkzdsetw-OiIgbyFeiibd1DG~6wFgTQ"
|
|
target="_blank"
|
|
class="text-orange-600 font-semibold"
|
|
>ParadeDB Community Slack</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="text-sm text-gray-500 leading-6">
|
|
<span class="font-semibold">Documentation:</span>
|
|
<ul class="list-disc list-inside ml-2">
|
|
<li>To start writing queries:
|
|
<a href="https://docs.paradedb.com/welcome/quickstart" class="text-orange-600 font-semibold">https://docs.paradedb.com/welcome/quickstart</a></li>
|
|
<li>To ingest data from existing database(s) or data lake(s):
|
|
<a href="https://docs.paradedb.com/ingest/quickstart" class="text-orange-600 font-semibold">https://docs.paradedb.com/ingest/quickstart</a></li>
|
|
</ul>
|
|
</div>
|
|
<p class="text-sm text-gray-500 leading-6">
|
|
* Note that ingesting into Ubicloud ParadeDB PostgreSQL via logical replication is not yet supported.
|
|
All other ParadeDB ingestion schemes are supported.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% elsif @pg[:flavor] == PostgresResource::Flavor::LANTERN %>
|
|
<div class="md:col-span-3">
|
|
<div class="overflow-hidden rounded-lg shadow ring-1 ring-black ring-opacity-5 bg-white divide-y divide-gray-200">
|
|
<div class="px-4 py-5 sm:p-6">
|
|
<div class="space-y-2">
|
|
<img src="/logo-lantern.png" class="h-6 object-contain mb-4"/>
|
|
<p class="text-sm text-gray-500 leading-6">
|
|
Lantern is a PostgreSQL-based vector database designed specifically for building AI applications.
|
|
Lantern instances are managed by the Lantern team and are optimal for AI workloads.
|
|
</p>
|
|
<div class="text-sm text-gray-500 leading-6">
|
|
You can reach to Lantern team for support at
|
|
<a href="mailto:support@lantern.dev" class="text-orange-600 font-semibold">support@lantern.dev</a>
|
|
</div>
|
|
<div class="text-sm text-gray-500 leading-6">
|
|
Check out
|
|
<a href="https://lantern.dev/docs" class="text-orange-600 font-semibold">Lantern Documentation</a>
|
|
to get more information about Lantern.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
<!-- Fork database -->
|
|
<% if @pg[:earliest_restore_time] && @pg[:latest_restore_time] > @pg[:earliest_restore_time] %>
|
|
<div class="overflow-hidden rounded-lg shadow ring-1 ring-black ring-opacity-5 bg-white divide-y divide-gray-200">
|
|
<div class="px-4 py-5 sm:p-6">
|
|
<form action="<%= "#{@project_data[:path]}#{@pg[:path]}/restore" %>" role="form" method="POST">
|
|
<%== csrf_tag("#{@project_data[:path]}#{@pg[:path]}/restore") %>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h2 class="text-lg font-medium leading-6 text-gray-900">Fork PostgreSQL database</h2>
|
|
<p class="mt-1 text-sm text-gray-500">
|
|
When you fork your existing PostgreSQL database, a new server will be provisioned.
|
|
</p>
|
|
</div>
|
|
<div class="grid grid-cols-12 gap-6">
|
|
<div class="col-span-12 sm:col-span-5">
|
|
<%== render("components/form/text", locals: { label: "New server name", name: "name", attributes: { required: true } }) %>
|
|
</div>
|
|
<div class="col-span-12 sm:col-span-5">
|
|
<%== render(
|
|
"components/form/datepicker",
|
|
locals: {
|
|
label: "Target Time (UTC)",
|
|
name: "restore_target",
|
|
default_date: @pg[:latest_restore_time],
|
|
max_date: @pg[:latest_restore_time],
|
|
min_date: @pg[:earliest_restore_time]
|
|
}
|
|
) %>
|
|
</div>
|
|
<div class="col-span-12 sm:col-span-2 flex justify-end items-end">
|
|
<%== render("components/form/submit_button", locals: { text: "Fork" }) %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
<!-- Firewall Rules Card -->
|
|
<div class="md:flex md:items-center md:justify-between pb-2 lg:pb-4">
|
|
<div class="min-w-0 flex-1">
|
|
<h3 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-2xl sm:tracking-tight">
|
|
Firewall Rules
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
<div class="overflow-hidden rounded-lg shadow ring-1 ring-black ring-opacity-5 bg-white divide-y divide-gray-200">
|
|
<table class="min-w-full divide-y divide-gray-300">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">CIDR</th>
|
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Port Range</th>
|
|
<% if edit_perm %>
|
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"></th>
|
|
<% end %>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-200 bg-white">
|
|
<% @pg[:firewall_rules].each do |fwr| %>
|
|
<tr>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row"><%= fwr[:cidr] %></td>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row">5432</td>
|
|
<% if edit_perm %>
|
|
<td
|
|
id="fwr-delete-<%=fwr[:id]%>"
|
|
class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6"
|
|
>
|
|
<%== render("components/delete_button", locals: { url: "#{request.path}/firewall-rule/#{fwr[:id]}", text: "" }) %>
|
|
</td>
|
|
<% end %>
|
|
</tr>
|
|
<% end %>
|
|
<% if edit_perm %>
|
|
<tr>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row">
|
|
<%== render(
|
|
"components/form/text",
|
|
locals: {
|
|
name: "cidr",
|
|
type: "cidr",
|
|
attributes: {
|
|
placeholder: "0.0.0.0/0",
|
|
required: true,
|
|
form: "form-pg-fwr-create"
|
|
}
|
|
}
|
|
) %>
|
|
</td>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row">
|
|
5432
|
|
</td>
|
|
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
|
|
<form action="<%= "#{request.path}/firewall-rule" %>" role="form" method="POST" id="form-pg-fwr-create">
|
|
<%== csrf_tag("#{request.path}/firewall-rule") %>
|
|
<%== render("components/form/submit_button", locals: { text: "Create", extra_class: "firewall-rule-create-button" }) %>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<!-- Metric Destination Card -->
|
|
<% if edit_perm %>
|
|
<div class="md:flex md:items-center md:justify-between pb-2 lg:pb-4">
|
|
<div class="min-w-0 flex-1">
|
|
<h3 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-2xl sm:tracking-tight">
|
|
Metric Destinations
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
<div class="overflow-hidden rounded-lg shadow ring-1 ring-black ring-opacity-5 bg-white divide-y divide-gray-200">
|
|
<table class="min-w-full divide-y divide-gray-300">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">URL</th>
|
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Username</th>
|
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Password</th>
|
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-200 bg-white">
|
|
<% @pg[:metric_destinations].each do |md| %>
|
|
<tr>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row"><%= md[:url] %></td>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row"><%= md[:username] %></td>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row">●●●●●●</td>
|
|
<td
|
|
id="md-delete-<%=md[:id]%>"
|
|
class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6"
|
|
>
|
|
<%== render("components/delete_button", locals: { url: "#{request.path}/metric-destination/#{md[:id]}", text: "" }) %>
|
|
</td>
|
|
</tr>
|
|
<% end %>
|
|
<tr>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row">
|
|
<%== render("components/form/text", locals: { name: "url", attributes: { form: "form-pg-md-create", required: true } }) %>
|
|
</td>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row">
|
|
<%== render("components/form/text", locals: { name: "username", attributes: { form: "form-pg-md-create", required: true } }) %>
|
|
</td>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row">
|
|
<%== render(
|
|
"components/form/text",
|
|
locals: {
|
|
name: "metric-destination-password",
|
|
type: "password",
|
|
attributes: {
|
|
required: true,
|
|
form: "form-pg-md-create",
|
|
autocomplete: "new-password"
|
|
},
|
|
extra_class: "metric-destination-password"
|
|
}
|
|
) %>
|
|
</td>
|
|
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
|
|
<form action="<%= "#{request.path}/metric-destination" %>" role="form" method="POST" id="form-pg-md-create">
|
|
<%== csrf_tag("#{request.path}/metric-destination") %>
|
|
<%== render("components/form/submit_button", locals: { text: "Create", extra_class: "metric-destination-create-button" }) %>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<% end %>
|
|
<!-- Danger Zone -->
|
|
<% if edit_perm || delete_perm || @pg[:primary] %>
|
|
<div>
|
|
<div class="md:flex md:items-center md:justify-between pb-2 lg:pb-4">
|
|
<div class="min-w-0 flex-1">
|
|
<h3 class="text-2xl font-bold leading-7 text-gray-900 sm:truncate sm:text-2xl sm:tracking-tight">
|
|
Danger Zone
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
<div class="overflow-hidden rounded-lg shadow ring-1 ring-black ring-opacity-5 bg-white divide-y divide-gray-200">
|
|
<!-- Reset password -->
|
|
<% if @pg[:primary] %>
|
|
<div class="px-4 py-5 sm:p-6">
|
|
<form action="<%= "#{@project_data[:path]}#{@pg[:path]}/reset-superuser-password" %>" role="form" method="POST">
|
|
<%== csrf_tag("#{@project_data[:path]}#{@pg[:path]}/reset-superuser-password") %>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h3 class="text-base font-semibold leading-6 text-gray-900">Reset superuser password</h3>
|
|
</div>
|
|
<div class="grid grid-cols-12 gap-6">
|
|
<div class="col-span-12 sm:col-span-5">
|
|
<%== render(
|
|
"components/form/text",
|
|
locals: {
|
|
label: "New password",
|
|
name: "password",
|
|
type: "password",
|
|
attributes: {
|
|
required: true
|
|
},
|
|
extra_class: "reset-superuser-password-new-password"
|
|
}
|
|
) %>
|
|
</div>
|
|
<div class="col-span-12 sm:col-span-5">
|
|
<%== render(
|
|
"components/form/text",
|
|
locals: {
|
|
label: "New password (repeat)",
|
|
name: "repeat_password",
|
|
type: "password",
|
|
attributes: {
|
|
required: true
|
|
},
|
|
extra_class: "reset-superuser-password-new-password-repeat"
|
|
}
|
|
) %>
|
|
</div>
|
|
<div class="col-span-12 sm:col-span-2 flex justify-end items-end">
|
|
<%== render("components/form/submit_button", locals: { text: "Reset" }) %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<% end %>
|
|
<!-- Restart Card -->
|
|
<% if edit_perm %>
|
|
<div class="px-4 py-5 sm:p-6">
|
|
<form action="<%= "#{@project_data[:path]}#{@pg[:path]}/restart" %>" role="form" method="POST">
|
|
<%== csrf_tag("#{@project_data[:path]}#{@pg[:path]}/restart") %>
|
|
<div class="sm:flex sm:items-center sm:justify-between">
|
|
<div>
|
|
<h3 class="text-base font-semibold leading-6 text-gray-900">Restart PostgreSQL database</h3>
|
|
<div class="mt-2 text-sm text-gray-500">
|
|
<p>This action will restart the PostgreSQL database. The database will be offline momentarily, and
|
|
all connections will be dropped.</p>
|
|
</div>
|
|
</div>
|
|
<div id="postgres-restart-<%=@pg[:id]%>" class="mt-5 sm:ml-6 sm:mt-0 sm:flex sm:flex-shrink-0 sm:items-center">
|
|
<div class="col-span-12 sm:col-span-2 flex justify-end items-end">
|
|
<%== render("components/form/submit_button", locals: { text: "Restart", extra_class: "restart-btn" }) %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<% end %>
|
|
<!-- Delete Card -->
|
|
<% if delete_perm %>
|
|
<div class="px-4 py-5 sm:p-6">
|
|
<div class="sm:flex sm:items-center sm:justify-between">
|
|
<div>
|
|
<h3 class="text-base font-semibold leading-6 text-gray-900">Delete PostgreSQL database</h3>
|
|
<div class="mt-2 text-sm text-gray-500">
|
|
<p>This action will permanently delete this PostgreSQL database.</p>
|
|
</div>
|
|
</div>
|
|
<div id="postgres-delete-<%=@pg[:id]%>" class="mt-5 sm:ml-6 sm:mt-0 sm:flex sm:flex-shrink-0 sm:items-center">
|
|
<%== render("components/delete_button", locals: { confirmation: @pg[:name], redirect: "#{@project_data[:path]}/postgres" }) %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|