637 lines
29 KiB
Plaintext
637 lines
29 KiB
Plaintext
<% @page_title = @pg[:name]
|
|
edit_perm = has_permission?("Postgres:edit", @pg[:id])
|
|
delete_perm = has_permission?("Postgres:delete", @pg[:id]) %>
|
|
|
|
<% @enable_echarts = true %>
|
|
|
|
<%== part(
|
|
"components/page_header",
|
|
breadcrumbs: [
|
|
%w[Projects /project],
|
|
[@project_data[:name], @project_data[:path]],
|
|
["PostgreSQL Databases", "#{@project_data[:path]}/postgres"],
|
|
[@pg[:name], "#"]
|
|
],
|
|
right_items: [part("components/pg_state_label", 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", part("components/download_button", 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" %>">
|
|
<%== part("components/kv_data_card", 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>
|
|
<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">
|
|
Metrics
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
<div
|
|
id="metrics-container"
|
|
class="p-4 overflow-hidden rounded-lg shadow ring-1 ring-black ring-opacity-5 bg-white divide-y divide-gray-200"
|
|
>
|
|
<% if @pg[:state] == "running" %>
|
|
<div class="mb-4 flex flex-wrap items-end gap-4 justify-end">
|
|
<div class="relative inline-block text-left">
|
|
<div class="relative inline-block text-left">
|
|
<select
|
|
id="time-range"
|
|
class="py-1.5 md:align-top rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
|
name="time-range"
|
|
>
|
|
<option value="30m">Last 30 minutes</option>
|
|
<option value="1h" selected>Last 1 hour</option>
|
|
<option value="3h">Last 3 hours</option>
|
|
<option value="6h">Last 6 hours</option>
|
|
<option value="12h">Last 12 hours</option>
|
|
<option value="1d">Last 1 day</option>
|
|
<option value="2d">Last 2 days</option>
|
|
<option value="7d">Last 7 days</option>
|
|
<option value="30d">Last 30 days</option>
|
|
</select>
|
|
<%== part("components/button", attributes: {id: "refresh-button"}, text: " Refresh", type: "primary", icon: "hero-refresh") %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-1 xl:grid-cols-2 gap-4 !border-t-0">
|
|
<% Metrics::POSTGRES_METRICS.each do |key, metric| %>
|
|
<div class="relative p-4 bg-gray-50 rounded-lg border border-gray-100">
|
|
<h4 class="text-sm font-medium text-gray-900 mb-2"><%= metric.name %></h4>
|
|
<p class="text-xs text-gray-500 mt-2"><%= metric.description %></p>
|
|
<div
|
|
class="metric-chart h-64 w-full"
|
|
id="<%= key %>-chart"
|
|
data-metric-key="<%= key %>"
|
|
data-metric-unit="<%= metric.unit %>"
|
|
>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
<% else %>
|
|
<div class="flex flex-col items-center justify-center h-full">
|
|
<div class="text-center">
|
|
<h2 class="text-2xl font-semibold text-gray-900">No metrics available</h2>
|
|
<p class="text-gray-500 mt-2">Metrics will be available once the database is running.</p>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<% if !@pg[:read_replica] %>
|
|
<!-- Update target state of the database resource -->
|
|
<% form_elements = [
|
|
{
|
|
name: "family",
|
|
type: "radio_small_cards",
|
|
label: "Server family",
|
|
required: "required",
|
|
content_generator: ContentGenerator::Postgres.method(:family)
|
|
},
|
|
{
|
|
name: "size",
|
|
type: "radio_small_cards",
|
|
label: "Server size",
|
|
required: "required",
|
|
content_generator: ContentGenerator::Postgres.method(:size)
|
|
},
|
|
{
|
|
name: "storage_size",
|
|
type: "radio_small_cards",
|
|
label: "Storage size",
|
|
required: "required",
|
|
content_generator: ContentGenerator::Postgres.method(:storage_size)
|
|
},
|
|
{
|
|
name: "ha_type",
|
|
type: "radio_small_cards",
|
|
label: "High Availability",
|
|
required: "required",
|
|
content_generator: ContentGenerator::Postgres.method(:ha_type)
|
|
},
|
|
{
|
|
name: "failover_time_notice",
|
|
type: "section",
|
|
content:
|
|
"If a maintenance window is configured, failover to the new server with the desired configuration will occur during the first available maintenance window after the new server is ready. Otherwise, failover will take place as soon as the new server becomes ready. Depending on the size of the data, it may take several hours for the new server to become ready.",
|
|
separator: false
|
|
}
|
|
]
|
|
|
|
pre_selected_values = {
|
|
"flavor" => @pg[:flavor],
|
|
"location" => @location.ubid,
|
|
"family" => @family,
|
|
"size" => @pg[:vm_size],
|
|
"storage_size" => @pg[:storage_size_gib],
|
|
"ha_type" => @pg[:ha_type]
|
|
} %>
|
|
|
|
<%== render(
|
|
"components/form/resource_creation_form",
|
|
locals: {
|
|
action: "#{@project_data[:path]}#{@pg[:path]}",
|
|
method: "PATCH",
|
|
form_title: "Configure PostgreSQL database",
|
|
form_elements:,
|
|
pre_selected_values:,
|
|
option_tree: @option_tree,
|
|
option_parents: @option_parents,
|
|
mode: "update"
|
|
}
|
|
) %>
|
|
<!-- 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">
|
|
<%== part(
|
|
"components/form/text",
|
|
label: "New server name",
|
|
name: "name",
|
|
attributes: {
|
|
placeholder: @pg[:name] + "-fork",
|
|
required: true
|
|
}
|
|
) %>
|
|
</div>
|
|
<div class="col-span-12 sm:col-span-5">
|
|
<%== part(
|
|
"components/form/datepicker",
|
|
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">
|
|
<%== part("components/form/submit_button", text: "Fork") %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
<!-- Read Replicas -->
|
|
<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">
|
|
Read Replicas
|
|
</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">Name</th>
|
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">State</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-200 bg-white">
|
|
<% @pg[:read_replicas].each do |read_replica| %>
|
|
<tr>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row">
|
|
<a href="<%= @project_data[:path] + read_replica[:path] %>" class="text-orange-600 hover:text-orange-700">
|
|
<%= read_replica[:name] %>
|
|
</a>
|
|
</td>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row">
|
|
<%== part("components/pg_state_label", state: read_replica[:state], extra_class: "text-md") %>
|
|
</td>
|
|
</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">
|
|
<%== part(
|
|
"components/form/text",
|
|
name: "name",
|
|
attributes: {
|
|
placeholder: @pg[:name] + "-read-replica",
|
|
required: true,
|
|
form: "form-pg-read-replica-create"
|
|
}
|
|
) %>
|
|
</td>
|
|
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
|
|
<form
|
|
action="<%= "#{@project_data[:path]}#{@pg[:path]}/read-replica" %>"
|
|
role="form"
|
|
method="POST"
|
|
id="form-pg-read-replica-create"
|
|
>
|
|
<%== csrf_tag("#{request.path}/read-replica") %>
|
|
<%== part("components/form/submit_button", text: "Create", extra_class: "pg-read-replica-create-btn") %>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
<!-- Firewall Rules Card -->
|
|
<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">
|
|
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>
|
|
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Description</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, 6432</td>
|
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6" scope="row"><%= fwr[:description] %></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"
|
|
>
|
|
<%== part("components/delete_button", 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">
|
|
<%== part(
|
|
"components/form/text",
|
|
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, 6432
|
|
</td>
|
|
<td>
|
|
<%== part(
|
|
"components/form/text",
|
|
name: "description",
|
|
attributes: {
|
|
placeholder: "Description",
|
|
form: "form-pg-fwr-create"
|
|
}
|
|
) %>
|
|
</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") %>
|
|
<%== part("components/form/submit_button", text: "Create", extra_class: "firewall-rule-create-button") %>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<% end %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<!-- MMW Card -->
|
|
<% if edit_perm %>
|
|
<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">
|
|
Maintenance Window
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
<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]}/set-maintenance-window" %>" role="form" method="POST">
|
|
<%== csrf_tag("#{@project_data[:path]}#{@pg[:path]}/set-maintenance-window") %>
|
|
<div class="space-y-4">
|
|
<div class="grid grid-cols-12 gap-6">
|
|
<div class="col-span-12 sm:col-span-7">
|
|
<%== part(
|
|
"components/form/select",
|
|
name: "maintenance_window_start_at",
|
|
placeholder: "No Maintenance Window",
|
|
options:
|
|
(0..23).map do
|
|
[it, "#{"%02d" % it}:00 - #{"%02d" % ((it + PostgresResource::MAINTENANCE_DURATION_IN_HOURS) % 24)}:00 (UTC)"]
|
|
end,
|
|
label: "Maintenance Window:",
|
|
selected: @pg[:maintenance_window_start_at]
|
|
) %>
|
|
</div>
|
|
<div class="col-span-12 sm:col-span-5 flex justify-end items-end">
|
|
<%== part("components/form/submit_button", text: "Set") %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
<!-- Metric Destination Card -->
|
|
<% if edit_perm %>
|
|
<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">
|
|
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"
|
|
>
|
|
<%== part("components/delete_button", 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">
|
|
<%== part("components/form/text", 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">
|
|
<%== part("components/form/text", 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">
|
|
<%== part(
|
|
"components/form/text",
|
|
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") %>
|
|
<%== part("components/form/submit_button", text: "Create", extra_class: "metric-destination-create-button") %>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</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">
|
|
<% if @pg[:read_replica] %>
|
|
<div class="px-4 py-5 sm:p-6">
|
|
<form action="<%= "#{@project_data[:path]}#{@pg[:path]}/promote" %>" role="form" method="POST">
|
|
<%== csrf_tag("#{@project_data[:path]}#{@pg[:path]}/promote") %>
|
|
<div class="sm:flex sm:items-center sm:justify-between">
|
|
<div>
|
|
<h3 class="text-base font-semibold leading-6 text-gray-900">Promote PostgreSQL read replica database</h3>
|
|
<div class="mt-2 text-sm text-gray-500">
|
|
<p>This action will promote and restart the PostgreSQL database. The database will stop replicating
|
|
permanently. It will be offline momentarily, and all connections will be dropped.</p>
|
|
</div>
|
|
</div>
|
|
<div id="postgres-replica-promote-<%=@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">
|
|
<%== part("components/form/submit_button", text: "Promote", extra_class: "promote-btn") %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<% end %>
|
|
<!-- 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">
|
|
<%== part(
|
|
"components/form/text",
|
|
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">
|
|
<%== part(
|
|
"components/form/text",
|
|
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">
|
|
<%== part("components/form/submit_button", 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">
|
|
<%== part("components/form/submit_button", 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">
|
|
<%== part("components/delete_button", confirmation: @pg[:name], redirect: "#{@project_data[:path]}/postgres") %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|