List certificates
This commit is contained in:
parent
a3a94f127f
commit
e242d229e4
5 changed files with 666 additions and 10 deletions
403
lib/form-layout.less
Normal file
403
lib/form-layout.less
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
/* Form layout */
|
||||
|
||||
@import "./variables.less";
|
||||
|
||||
:root {
|
||||
// CSS variable to define the number of (label + control) columns.
|
||||
// It dynamically changes on narrow pages (see media query below).
|
||||
--ct-form-columns: 2;
|
||||
}
|
||||
|
||||
// Cockpit Form Layout: Automatically have Cockpit display your form in
|
||||
// an optimal layout.
|
||||
//
|
||||
// By default, all labels are aligned and sized properly and form elements
|
||||
// stretch to take up the remaining space.
|
||||
//
|
||||
//
|
||||
// There are additional classes and attributes you can add to each
|
||||
// control directly under `ct-form`:
|
||||
//
|
||||
// `ct-form-split`: The grid can be split on a `form-control`
|
||||
// level by adding a this class. If you want two elements next to each
|
||||
// other, both should have this class. Widths are equal by default.
|
||||
// See ct-form-minmax & ct-form-maxmin for alternate sizing.
|
||||
//
|
||||
// `ct-form-relax`: Form elements normally stretch to take up the
|
||||
// full space. You can relax their width by adding this class to the
|
||||
// control. Inputs with a size attribute are auto-relaxed and do not
|
||||
// need this class.
|
||||
//
|
||||
// `ct-form-stretch`: If a control has a width specified
|
||||
// elsewhere, you can force it to stretch. This is mainly useful when
|
||||
// using <div role="group"> to group elements.
|
||||
//
|
||||
// `ct-form-full`: Force a widget to be the full width of the form,
|
||||
// invading the label space.
|
||||
//
|
||||
// role="group": When there are two related elements, such as a text
|
||||
// input and a dropdown, you can group them together using this HTML
|
||||
// attribute. It's similar in purpose to a <fieldset>, but works for
|
||||
// layouts in Chrome (unlike fieldset). This can be attached to any
|
||||
// container element, but will most likely be used with <div>. The role
|
||||
// adds semantic meaning to the element for screen readers, and we key
|
||||
// the CSS off of the role.
|
||||
//
|
||||
// `ct-form-box`: Visual styling for encapsulating a block of sub-options.
|
||||
// Creates a gray box around elements.
|
||||
//
|
||||
// <hr>: While this is an element, it has a special meaning and is used
|
||||
// to add some vertical spacing to a form.
|
||||
//
|
||||
//
|
||||
// Alternate grid sizing:
|
||||
// You can override division of space for controls by adding a class
|
||||
// at grid level (.ct-form) to adjust size for "split" widgets:
|
||||
// `ct-form-maxmin: First widget is wide; second is small.
|
||||
// `ct-form-minmax`: First widget is small; second is wide.
|
||||
//
|
||||
//
|
||||
// Most of the time, you can simply ignore all the optional classes (and
|
||||
// attribute and hr element) and simply wrap your labels & controls in
|
||||
// a <form class="ct-form"> and layout magic happens.
|
||||
|
||||
.ct-form {
|
||||
// Locally redefine padding to Bootstrap values for this LESS block
|
||||
@padding-large-vertical: 1rem;
|
||||
@padding-small-vertical: 0.5rem;
|
||||
@padding-small-horizontal: 1.5rem;
|
||||
// Bootstrap & PatternFly use a 1px border around widgets
|
||||
@border-width: 1px;
|
||||
@widget-height: 2.25rem; // (36px for PF4 widgets)
|
||||
|
||||
align-self: start; // Don't vertically fill content by default
|
||||
display: grid;
|
||||
grid-gap: @padding-small-vertical @padding-small-horizontal;
|
||||
// Repeat a label that is a minimum of 4em and its control that
|
||||
// fills the remaining space by a CSS variable (default: 2)
|
||||
grid-template-columns: repeat(var(--ct-form-columns), max-content 1fr);
|
||||
justify-items: stretch;
|
||||
align-content: baseline;
|
||||
|
||||
// All <label> elements describing form elements in PatternFly are
|
||||
// supposed to have a `control-label` class.
|
||||
// These precede control elements.
|
||||
> .control-label {
|
||||
text-align: right;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
> :not(hr):not(p) {
|
||||
line-height: 2.25rem;
|
||||
}
|
||||
|
||||
> p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// Put all control elements to the right of the labels,
|
||||
// stretching to the rightmost column
|
||||
> :not(.control-label):not(hr):not(.ct-form-split):not(.ct-form-full) {
|
||||
grid-column: ~"2 / -1";
|
||||
}
|
||||
|
||||
// Auto-stretch elements to the grid (except when relaxed)
|
||||
> :not(.ct-form-relax):not(.spinner) {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
// Horizontal rules directly under a form-layout container serve to
|
||||
// add some vertical space in forms. This is useful for visually
|
||||
// grouping similar elements with whitespace.
|
||||
//
|
||||
// It's not the same as actually grouping elements (which can be done
|
||||
// in the usual ways as well as adding a role="group".
|
||||
> hr {
|
||||
border: none;
|
||||
// LESS needs this to be escaped with ~"". You'll see it below too.
|
||||
// CSS wants the string to be 1 / -1 without escaping.
|
||||
grid-column: ~"1 / -1";
|
||||
height: 0.5rem;
|
||||
// Reset padding to ensure all browsers treat this the same
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Auto-relax inputs with size
|
||||
> input[size],
|
||||
> .ct-validation-wrapper > input[size] {
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
> .ct-validation-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
// Hack to allow number inputs to be sized on WebKit-based browsers
|
||||
input[type=number] {
|
||||
-webkit-appearance: textarea;
|
||||
}
|
||||
|
||||
// Special considerations for widgets (and widget-like elements)
|
||||
// This is a LESS mixin that will not be in the compiled CSS.
|
||||
.widget-rules() {
|
||||
> input,
|
||||
> textarea,
|
||||
> select,
|
||||
> .bootstrap-select,
|
||||
> .ct-select,
|
||||
> .dropdown,
|
||||
> .combobox-container,
|
||||
> fieldset,
|
||||
> [role=group],
|
||||
> [data-field],
|
||||
> .form-group,
|
||||
> .btn-group,
|
||||
> label.checkbox,
|
||||
> label.radio,
|
||||
> .checkbox-inline,
|
||||
> .radio-inline {
|
||||
line-height: var(--pf-global--LineHeight--md);
|
||||
}
|
||||
}
|
||||
|
||||
&, > .ct-validation-wrapper {
|
||||
.widget-rules();
|
||||
}
|
||||
|
||||
// Some elements need special width considerations
|
||||
// as PatternFly normally fixes the width
|
||||
> :not(.ct-form-relax):not(.spinner) {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
// Elements with role="group" are used to group elements —
|
||||
// fieldset was going to be used, but Chrome doesn't allow
|
||||
// grid or flex placement for fieldsets (yet).
|
||||
//
|
||||
// Adding a group role is the same thing accessibilty-wise
|
||||
// and lets us target all browsers properly.
|
||||
//
|
||||
// You can use this like:
|
||||
// <div role="group">
|
||||
//
|
||||
// And non-div elements are also supported.
|
||||
> [role=group],
|
||||
> .ct-validation-wrapper > [role=group] {
|
||||
align-self: start;
|
||||
align-content: center;
|
||||
display: grid;
|
||||
grid-gap: @padding-small-vertical;
|
||||
min-height: 2.25rem;
|
||||
justify-content: start;
|
||||
// Only support 3 splits for now (can change to 3 later, if needed)
|
||||
grid-template-columns: repeat(3, auto);
|
||||
|
||||
&.ct-form-vertical {
|
||||
> :not(.ct-form-split) {
|
||||
// Stretch across the grid (unless it's a split)
|
||||
grid-column: ~"1 / -1";
|
||||
}
|
||||
}
|
||||
|
||||
> .checkbox,
|
||||
> .radio {
|
||||
// Spacing is handled by grid, not margin
|
||||
margin: 0;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> [role=group],
|
||||
> .ct-validation-wrapper > [role=group],
|
||||
> .ct-validation-wrapper > [data-field] {
|
||||
// Allow dropdowns to expand as needed
|
||||
&:not(.ct-form-relax) {
|
||||
> .dropdown {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
// <select>s need to be coaxed to be 100%
|
||||
> .ct-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vertically align checkboxes and radios properly using flex
|
||||
label.checkbox,
|
||||
label.radio,
|
||||
.checkbox > label,
|
||||
.radio > label,
|
||||
.checkbox-inline,
|
||||
.radio-inline {
|
||||
display: inline-flex;
|
||||
padding-left: 0;
|
||||
padding-right: @padding-small-horizontal;
|
||||
align-items: center;
|
||||
|
||||
> input[type="checkbox"],
|
||||
> input[type="radio"] {
|
||||
margin: 0 0.5em 0 0;
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove vertical spacing for fieldsets,
|
||||
// as this is handled by the grid gap
|
||||
fieldset {
|
||||
> .checkbox,
|
||||
> .radio {
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// List groups override the grid gap, so we're adding it manually
|
||||
.list-group {
|
||||
margin-bottom: @padding-small-vertical;
|
||||
}
|
||||
|
||||
// Relax split elements to only take up one column
|
||||
> .ct-form-split {
|
||||
grid-column: ~"auto / auto";
|
||||
}
|
||||
|
||||
// Stretch to full width
|
||||
> .ct-form-full {
|
||||
grid-column: ~"1 / -1";
|
||||
}
|
||||
|
||||
// Move warnings, errors, info, etc. up a bit to associate with previous field
|
||||
.bump-up() {
|
||||
position: relative;
|
||||
margin-top: -0.5rem;
|
||||
}
|
||||
|
||||
> .has-success,
|
||||
> .has-warning,
|
||||
> .has-error {
|
||||
&:not(.form-group):not(fieldset):not([role=group]) {
|
||||
//.bump-up();
|
||||
}
|
||||
}
|
||||
|
||||
> .help-block {
|
||||
.bump-up();
|
||||
}
|
||||
|
||||
.help-block {
|
||||
--help-line-height: calc(var(--pf-global--LineHeight--md) * 1rem);
|
||||
line-height: var(--help-line-height);
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
position: relative;
|
||||
// (baseline - height - border) / 2
|
||||
top: calc((var(--help-line-height) - 16px - 2px) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
.ct-form-box {
|
||||
background: var(--color-gray-1);
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: var(--color-gray-5);
|
||||
padding: 0.5rem;
|
||||
padding-top: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// Force a form element to stretch. Add as a class to `form-control`.
|
||||
.ct-form-stretch {
|
||||
justify-content: stretch !important;
|
||||
}
|
||||
|
||||
// Instruct a `form-control` to not stretch.
|
||||
.ct-form-relax {
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
// Reset .ct-form-split for small dialogs, as they don't have
|
||||
// much width. This allows for using the same HTML layout in both
|
||||
// narrow and normal dialogs.
|
||||
.modal-dialog.modal-sm .ct-form > .ct-form-split {
|
||||
grid-column: ~"2 / -1";
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
// When inside of lists or modals & the page isn't wide enough,
|
||||
// collapse (label + control) columns down to 1, to force splits on
|
||||
// their own lines
|
||||
.listing-ct-body,
|
||||
.modal {
|
||||
--ct-form-columns: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Alternate layout, for a split, used at ct-form grid-level:
|
||||
// First form widget is as small as possible;
|
||||
// Second takes up the rest of the space
|
||||
.ct-form-minmax {
|
||||
grid-template-columns: max-content min-content max-content 1fr;
|
||||
}
|
||||
|
||||
// Alternate layout, for a split, used at ct-form grid-level:
|
||||
// First form widget takes up as much space as it can;
|
||||
// Second form widget is as small as possible
|
||||
.ct-form-maxmin {
|
||||
grid-template-columns: max-content 1fr max-content min-content;
|
||||
}
|
||||
|
||||
@media (max-width: @screen-xs) {
|
||||
// When inside of lists or modals & the page is *very* narrow,
|
||||
// collapse the grid further, so labels are above controls
|
||||
//
|
||||
// Note: Padding variables below are outside the local scope of the
|
||||
// .ct-form block, so they default to the global PatternFly
|
||||
// values.
|
||||
|
||||
.listing-ct-body,
|
||||
.modal {
|
||||
.ct-form {
|
||||
// Completely deconstruct the grid layout
|
||||
grid-template-columns: initial;
|
||||
|
||||
> * {
|
||||
// Don't restrict grid placement
|
||||
grid-column: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
// As control labels fill the row, left align and remove padding
|
||||
> .control-label {
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
|
||||
// Everything but the first label should have space to breathe
|
||||
&:not(:first-child) {
|
||||
margin: @padding-large-vertical 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce vertical height spacing between groups of elements
|
||||
> hr {
|
||||
height: @padding-large-vertical * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
lib/variables.less
Normal file
23
lib/variables.less
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
@import (less) "../node_modules/bootstrap-less/bootstrap/variables.less";
|
||||
@import (less) "../node_modules/patternfly/dist/less/variables.less";
|
||||
|
||||
@metadata-color: var(--color-subtle-copy);
|
||||
|
||||
@listing-ct-hover: var(--color-ct-list-hover-bg);
|
||||
@listing-ct-hover-icon: var(--color-ct-list-hover-icon);
|
||||
@listing-ct-active: var(--color-ct-list-active-bg);
|
||||
@listing-ct-padding: 0.5rem;
|
||||
@listing-ct-spacing: 1rem;
|
||||
@listing-ct-open: #f5f5f5;
|
||||
@listing-ct-open-width: 3px;
|
||||
@listing-ct-metadata: @metadata-color;
|
||||
@listing-ct-warning-color: var(--color-ct-light-red-1);
|
||||
@listing-ct-border: var(--color-light-gray);
|
||||
@listing-ct-border-light: var(--color-gray-2);
|
||||
@listing-ct-border-maybe: var(--color-light-gray-3);
|
||||
|
||||
@screen-lg-max: (@screen-xlg-min - 1);
|
||||
@screen-xlg-min: 1600px;
|
||||
@screen-xs: 480px;
|
||||
@screen-xs-min: @screen-xs;
|
||||
@screen-xxs-max: (@screen-xs-min - 1);
|
||||
20
src/app.jsx
20
src/app.jsx
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
* Copyright (C) 2020 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
|
|
@ -17,9 +17,13 @@
|
|||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import cockpit from 'cockpit';
|
||||
import React from 'react';
|
||||
import './app.scss';
|
||||
import cockpit from "cockpit";
|
||||
import React from "react";
|
||||
import "./app.scss";
|
||||
|
||||
// import { Accordion, AccordionItem, AccordionContent, AccordionToggle } from "@patternfly/react-core";
|
||||
|
||||
import CertificateList from "./certificateList.jsx";
|
||||
|
||||
const _ = cockpit.gettext;
|
||||
|
||||
|
|
@ -28,20 +32,16 @@ export class Application extends React.Component {
|
|||
super();
|
||||
this.state = { hostname: _("Unknown") };
|
||||
|
||||
cockpit.file('/etc/hostname').watch(content => {
|
||||
cockpit.file("/etc/hostname").watch(content => {
|
||||
this.setState({ hostname: content.trim() });
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const path = getRequests();
|
||||
|
||||
return (
|
||||
<div className="container-fluid">
|
||||
<h2>Certificates</h2>
|
||||
<p>
|
||||
{ cockpit.format(_("Running on $0"), path) }
|
||||
</p>
|
||||
<CertificateList />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
193
src/certificateList.jsx
Normal file
193
src/certificateList.jsx
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
|
||||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2020 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// import cockpit from "cockpit";
|
||||
import React from "react";
|
||||
import moment from "moment";
|
||||
|
||||
import { Accordion, AccordionItem, AccordionContent, AccordionToggle, Flex, FlexItem, FlexModifiers } from "@patternfly/react-core";
|
||||
|
||||
import '../lib/form-layout.less';
|
||||
import { getRequests, getRequest } from "./dbus.js";
|
||||
|
||||
const _ = cockpit.gettext;
|
||||
function prettyTime(unixTime) {
|
||||
moment.locale(cockpit.language, {
|
||||
longDateFormat : {
|
||||
LT: "hh:mm:ss",
|
||||
L: "DD/MM/YYYY",
|
||||
}
|
||||
});
|
||||
const yesterday = _("Yesterday");
|
||||
const today = _("Today");
|
||||
moment.locale(cockpit.language, {
|
||||
calendar : {
|
||||
lastDay : `[${yesterday}] LT`,
|
||||
sameDay : `[${today}] LT`,
|
||||
sameElse : "L LT"
|
||||
}
|
||||
});
|
||||
|
||||
return moment(Number(unixTime) * 1000).calendar();
|
||||
}
|
||||
|
||||
class CertificateList extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
certs: [],
|
||||
expanded: [],
|
||||
};
|
||||
this.toggle = this.toggle.bind(this);
|
||||
this.onValueChanged = this.onValueChanged.bind(this);
|
||||
|
||||
getRequests()
|
||||
.fail(error => {
|
||||
console.log(JSON.stringify(error)); // TODO better error handling
|
||||
})
|
||||
.then(paths => {
|
||||
paths[0].forEach(p => {
|
||||
getRequest(p)
|
||||
.fail(error => {
|
||||
console.log(JSON.stringify(error)); // TODO better error handling
|
||||
})
|
||||
.then(ret => {
|
||||
const certs = [...this.state.certs, ret[0]];
|
||||
this.onValueChanged("certs", certs);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
toggle(certId) {
|
||||
const expanded = [...this.state.expanded];
|
||||
const certIndex = expanded.findIndex(e => e === certId);
|
||||
|
||||
if (certIndex < 0)
|
||||
expanded.push(certId);
|
||||
else
|
||||
expanded.splice(certIndex, 1);
|
||||
|
||||
this.setState({ expanded });
|
||||
}
|
||||
|
||||
onValueChanged(key, value) {
|
||||
this.setState({ [key]: value });
|
||||
}
|
||||
|
||||
render() {
|
||||
const certs = this.state.certs;
|
||||
|
||||
console.log(certs);
|
||||
const items = certs.map(cert => (
|
||||
<AccordionItem key={cert.nickname.v}>
|
||||
<AccordionToggle
|
||||
onClick={() => this.toggle(cert.nickname.v)}
|
||||
isExpanded={this.state.expanded.includes(cert.nickname.v)}
|
||||
id={cert.nickname.v + "toggle"}
|
||||
>
|
||||
{cert["cert-nickname"].v}
|
||||
</AccordionToggle>
|
||||
<AccordionContent
|
||||
id={cert.nickname.v + "content"}
|
||||
isHidden={!this.state.expanded.includes(cert.nickname.v)}
|
||||
isFixed
|
||||
>
|
||||
<div className="overview-tab-grid">
|
||||
<label className='control-label label-title'> {_("General")} </label>
|
||||
<span />
|
||||
<Flex breakpointMods={[{modifier: FlexModifiers["justify-content-space-between"]}]}>
|
||||
<Flex breakpointMods={[{modifier: FlexModifiers["column", "flex-1"]}]}>
|
||||
<div className="ct-form">
|
||||
<label className='control-label label-title'>{_("Status")}</label>
|
||||
<div>{cert.status.v}</div>
|
||||
<label className='control-label label-title'>{_("Auto-renewal")}</label>
|
||||
<div>{cert.autorenew.v ? _("Yes") : _("No")}</div>
|
||||
<label className='control-label label-title'>{_("Stuck")}</label>
|
||||
<div>{cert.stuck.v ? _("Yes") : _("No")}</div>
|
||||
</div>
|
||||
</Flex>
|
||||
<Flex breakpointMods={[{modifier: FlexModifiers["column", "flex-1"]}]}>
|
||||
<div className="ct-form">
|
||||
<label className='control-label label-title'>{_("Not valid after")}</label>
|
||||
<div>{prettyTime(cert["not-valid-after"].v)}</div>
|
||||
<label className='control-label label-title'>{_("Not valid before")}</label>
|
||||
<div>{prettyTime(cert["not-valid-before"].v)}</div>
|
||||
</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<label className='control-label label-title'> {_("Key")} </label>
|
||||
<span />
|
||||
<Flex breakpointMods={[{modifier: FlexModifiers["justify-content-space-between"]}]}>
|
||||
<Flex breakpointMods={[{modifier: FlexModifiers["column", "flex-1"]}]}>
|
||||
<div className="ct-form">
|
||||
<label className='control-label label-title'>{_("Nickname")}</label>
|
||||
<div>{cert["key-nickname"].v}</div>
|
||||
<label className='control-label label-title'>{_("Type")}</label>
|
||||
<div>{cert["key-type"].v}</div>
|
||||
<label className='control-label label-title'>{_("Token")}</label>
|
||||
<div>{cert["key-token"].v}</div>
|
||||
</div>
|
||||
</Flex>
|
||||
<Flex breakpointMods={[{modifier: FlexModifiers["column", "flex-1"]}]}>
|
||||
<div className="ct-form">
|
||||
<label className='control-label label-title'>{_("Location")}</label>
|
||||
<div>{cert["key-database"].v}</div>
|
||||
<label className='control-label label-title'>{_("Storage")}</label>
|
||||
<div>{cert["key-storage"].v}</div>
|
||||
</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<label className='control-label label-title'> {_("Cert")} </label>
|
||||
<span />
|
||||
<Flex breakpointMods={[{modifier: FlexModifiers["justify-content-space-between"]}]}>
|
||||
<Flex breakpointMods={[{modifier: FlexModifiers["column", "flex-1"]}]}>
|
||||
<div className="ct-form">
|
||||
<label className='control-label label-title'>{_("Nickname")}</label>
|
||||
<div>{cert["cert-nickname"].v}</div>
|
||||
<label className='control-label label-title'>{_("Token")}</label>
|
||||
<div>{cert["cert-token"].v}</div>
|
||||
</div>
|
||||
</Flex>
|
||||
<Flex breakpointMods={[{modifier: FlexModifiers["column", "flex-1"]}]}>
|
||||
<div className="ct-form">
|
||||
<label className='control-label label-title'>{_("Location")}</label>
|
||||
<div>{cert["cert-database"].v}</div>
|
||||
<label className='control-label label-title'>{_("Storage")}</label>
|
||||
<div>{cert["cert-storage"].v}</div>
|
||||
</div>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</div>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
));
|
||||
|
||||
return (
|
||||
<Accordion asDefinitionList={false}>
|
||||
{items}
|
||||
</Accordion>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CertificateList;
|
||||
37
src/dbus.js
Normal file
37
src/dbus.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of Cockpit.
|
||||
*
|
||||
* Copyright (C) 2020 Red Hat, Inc.
|
||||
*
|
||||
* Cockpit is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Cockpit is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import cockpit from "cockpit";
|
||||
|
||||
function dbusCall(objectPath, iface, method, args) {
|
||||
const clientCertmonger = cockpit.dbus("org.fedorahosted.certmonger",
|
||||
{ superuser: "try" });
|
||||
|
||||
return clientCertmonger.call(objectPath, iface, method, args);
|
||||
}
|
||||
|
||||
export function getRequest(path) {
|
||||
return dbusCall(path, "org.freedesktop.DBus.Properties", "GetAll",
|
||||
["org.fedorahosted.certmonger.request"]);
|
||||
}
|
||||
|
||||
export function getRequests() {
|
||||
return dbusCall("/org/fedorahosted/certmonger", "org.fedorahosted.certmonger",
|
||||
"get_requests", []);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue