Improvements for certificates table, adds expansion object to certificates

This commit is contained in:
Jamie Curnow 2023-01-14 09:45:08 +10:00
parent 6c76c041c4
commit 456c59c746
9 changed files with 95 additions and 22 deletions

View File

@ -26,7 +26,7 @@ func GetCertificates() func(http.ResponseWriter, *http.Request) {
return return
} }
certificates, err := certificate.List(pageInfo, middleware.GetFiltersFromContext(r)) certificates, err := certificate.List(pageInfo, middleware.GetFiltersFromContext(r), getExpandFromContext(r))
if err != nil { if err != nil {
h.ResultErrorJSON(w, r, http.StatusBadRequest, err.Error(), nil) h.ResultErrorJSON(w, r, http.StatusBadRequest, err.Error(), nil)
} else { } else {
@ -46,11 +46,16 @@ func GetCertificate() func(http.ResponseWriter, *http.Request) {
return return
} }
cert, err := certificate.GetByID(certificateID) item, err := certificate.GetByID(certificateID)
if err != nil { switch err {
case sql.ErrNoRows:
h.ResultErrorJSON(w, r, http.StatusNotFound, "Not found", nil)
case nil:
// nolint: errcheck,gosec
item.Expand(getExpandFromContext(r))
h.ResultResponseJSON(w, r, http.StatusOK, item)
default:
h.ResultErrorJSON(w, r, http.StatusBadRequest, err.Error(), nil) h.ResultErrorJSON(w, r, http.StatusBadRequest, err.Error(), nil)
} else {
h.ResultResponseJSON(w, r, http.StatusOK, cert)
} }
} }
} }

View File

@ -102,7 +102,7 @@ func Update(certificate *Model) error {
} }
// List will return a list of certificates // List will return a list of certificates
func List(pageInfo model.PageInfo, filters []model.Filter) (ListResponse, error) { func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ListResponse, error) {
var result ListResponse var result ListResponse
var exampleModel Model var exampleModel Model
@ -135,6 +135,15 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (ListResponse, error)
return result, err return result, err
} }
if expand != nil {
for idx := range items {
expandErr := items[idx].Expand(expand)
if expandErr != nil {
logger.Error("CertificatesExpansionError", expandErr)
}
}
}
result = ListResponse{ result = ListResponse{
Items: items, Items: items,
Total: totalRows, Total: totalRows,

View File

@ -13,8 +13,10 @@ import (
"npm/internal/database" "npm/internal/database"
"npm/internal/entity/certificateauthority" "npm/internal/entity/certificateauthority"
"npm/internal/entity/dnsprovider" "npm/internal/entity/dnsprovider"
"npm/internal/entity/user"
"npm/internal/logger" "npm/internal/logger"
"npm/internal/types" "npm/internal/types"
"npm/internal/util"
) )
const ( const (
@ -59,6 +61,7 @@ type Model struct {
// Expansions: // Expansions:
CertificateAuthority *certificateauthority.Model `json:"certificate_authority,omitempty"` CertificateAuthority *certificateauthority.Model `json:"certificate_authority,omitempty"`
DNSProvider *dnsprovider.Model `json:"dns_provider,omitempty"` DNSProvider *dnsprovider.Model `json:"dns_provider,omitempty"`
User *user.Model `json:"user,omitempty"`
} }
func (m *Model) getByQuery(query string, params []interface{}) error { func (m *Model) getByQuery(query string, params []interface{}) error {
@ -161,7 +164,8 @@ func (m *Model) ValidateWildcardSupport() bool {
} }
if hasWildcard { if hasWildcard {
m.Expand() // nolint: errcheck, gosec
m.Expand([]string{"certificate-authority", "dns-provider"})
if !m.CertificateAuthority.IsWildcardSupported { if !m.CertificateAuthority.IsWildcardSupported {
return false return false
} }
@ -182,15 +186,28 @@ func (m *Model) setDefaultStatus() {
} }
// Expand will populate attached objects for the model // Expand will populate attached objects for the model
func (m *Model) Expand() { func (m *Model) Expand(items []string) error {
if m.CertificateAuthorityID > 0 { var err error
certificateAuthority, _ := certificateauthority.GetByID(m.CertificateAuthorityID)
if util.SliceContainsItem(items, "certificate-authority") && m.CertificateAuthorityID > 0 {
var certificateAuthority certificateauthority.Model
certificateAuthority, err = certificateauthority.GetByID(m.CertificateAuthorityID)
m.CertificateAuthority = &certificateAuthority m.CertificateAuthority = &certificateAuthority
} }
if m.DNSProviderID > 0 {
dnsProvider, _ := dnsprovider.GetByID(m.DNSProviderID) if util.SliceContainsItem(items, "dns-provider") && m.DNSProviderID > 0 {
var dnsProvider dnsprovider.Model
dnsProvider, err = dnsprovider.GetByID(m.DNSProviderID)
m.DNSProvider = &dnsProvider m.DNSProvider = &dnsProvider
} }
if util.SliceContainsItem(items, "user") && m.ID > 0 {
var usr user.Model
usr, err = user.GetByID(m.UserID)
m.User = &usr
}
return err
} }
// GetCertificateLocations will return the paths on disk where the SSL // GetCertificateLocations will return the paths on disk where the SSL
@ -222,7 +239,8 @@ func (m *Model) GetCertificateLocations() (string, string, string) {
func (m *Model) Request() error { func (m *Model) Request() error {
logger.Info("Requesting certificate for: #%d %v", m.ID, m.Name) logger.Info("Requesting certificate for: #%d %v", m.ID, m.Name)
m.Expand() // nolint: errcheck, gosec
m.Expand([]string{"certificate-authority", "dns-provider"})
m.Status = StatusRequesting m.Status = StatusRequesting
if err := m.Save(); err != nil { if err := m.Save(); err != nil {
logger.Error("CertificateSaveError", err) logger.Error("CertificateSaveError", err)

View File

@ -11,7 +11,7 @@ export async function getCertificates(
const { result } = await api.get( const { result } = await api.get(
{ {
url: "certificates", url: "certificates",
params: { limit, offset, sort, ...filters }, params: { limit, offset, sort, expand: "user", ...filters },
}, },
abortController, abortController,
); );

View File

@ -0,0 +1,11 @@
import { Text, TextProps } from "@chakra-ui/react";
function Monospace(props: TextProps) {
return (
<Text as="span" className="monospace" {...props}>
{props.children}
</Text>
);
}
export { Monospace };

View File

@ -1,5 +1,5 @@
import { Avatar, Badge, Text, Tooltip } from "@chakra-ui/react"; import { Avatar, Badge, Text, Tooltip } from "@chakra-ui/react";
import { RowAction, RowActionsMenu } from "components"; import { Monospace, RowAction, RowActionsMenu } from "components";
import { intl } from "locale"; import { intl } from "locale";
import getNiceDNSProvider from "modules/Acmesh"; import getNiceDNSProvider from "modules/Acmesh";
@ -73,13 +73,19 @@ function CapabilitiesFormatter() {
function CertificateStatusFormatter() { function CertificateStatusFormatter() {
const formatCell = ({ value }: any) => { const formatCell = ({ value }: any) => {
return ( let color = "cyan.500";
<Badge color={value ? "cyan.500" : "red.400"}> switch (value) {
{value case "failed":
? intl.formatMessage({ id: "ready" }) color = "red.400";
: intl.formatMessage({ id: "setup-required" })} break;
</Badge> case "provided":
); color = "green.400";
break;
case "requesting":
color = "yellow.400";
break;
}
return <Badge color={color}>{intl.formatMessage({ id: value })}</Badge>;
}; };
return formatCell; return formatCell;
@ -185,6 +191,14 @@ function HostStatusFormatter() {
return formatCell; return formatCell;
} }
function MonospaceFormatter() {
const formatCell = ({ value }: any) => {
return <Monospace>{value}</Monospace>;
};
return formatCell;
}
function UpstreamStatusFormatter() { function UpstreamStatusFormatter() {
const formatCell = ({ value, row }: any) => { const formatCell = ({ value, row }: any) => {
if (value === "ready") { if (value === "ready") {
@ -245,6 +259,7 @@ export {
HostStatusFormatter, HostStatusFormatter,
HostTypeFormatter, HostTypeFormatter,
IDFormatter, IDFormatter,
MonospaceFormatter,
SecondsFormatter, SecondsFormatter,
UpstreamStatusFormatter, UpstreamStatusFormatter,
}; };

View File

@ -5,6 +5,7 @@ export * from "./HelpDrawer";
export * from "./Loader"; export * from "./Loader";
export * from "./Loading"; export * from "./Loading";
export * from "./LocalePicker"; export * from "./LocalePicker";
export * from "./Monospace";
export * from "./Navigation"; export * from "./Navigation";
export * from "./Permissions"; export * from "./Permissions";
export * from "./PrettyButton"; export * from "./PrettyButton";

View File

@ -25,6 +25,10 @@ table td.w-80 {
width: 80px; width: 80px;
} }
span.monospace {
font-family: monospace;
}
/* helpdoc */ /* helpdoc */
.helpdoc-body { .helpdoc-body {
p { p {

View File

@ -3,7 +3,10 @@ import { useEffect, useMemo } from "react";
import { import {
tableEvents, tableEvents,
ActionsFormatter, ActionsFormatter,
CertificateStatusFormatter,
GravatarFormatter,
IDFormatter, IDFormatter,
MonospaceFormatter,
TableFilter, TableFilter,
TableLayout, TableLayout,
TablePagination, TablePagination,
@ -41,6 +44,11 @@ function CertificatesTable({
}: CertificatesTableProps) { }: CertificatesTableProps) {
const [columns, tableData] = useMemo(() => { const [columns, tableData] = useMemo(() => {
const columns = [ const columns = [
{
accessor: "user.gravatarUrl",
Cell: GravatarFormatter(),
className: "w-80",
},
{ {
Header: intl.formatMessage({ id: "column.id" }), Header: intl.formatMessage({ id: "column.id" }),
accessor: "id", accessor: "id",
@ -53,6 +61,7 @@ function CertificatesTable({
accessor: "name", accessor: "name",
sortable: true, sortable: true,
Filter: TextFilter, Filter: TextFilter,
Cell: MonospaceFormatter(),
}, },
{ {
Header: intl.formatMessage({ id: "column.validation-type" }), Header: intl.formatMessage({ id: "column.validation-type" }),
@ -65,6 +74,7 @@ function CertificatesTable({
accessor: "status", accessor: "status",
sortable: true, sortable: true,
Filter: TextFilter, Filter: TextFilter,
Cell: CertificateStatusFormatter(),
}, },
{ {
id: "actions", id: "actions",