mirror of https://github.com/certd/certd
perf: 证书直接查看
parent
64c4933645
commit
5dde5bd3f7
|
@ -307,13 +307,15 @@ export class Executor {
|
|||
//更新pipeline vars
|
||||
if (Object.keys(instance._result.pipelineVars).length > 0) {
|
||||
// 判断 pipelineVars 有值时更新
|
||||
const vars = await this.pipelineContext.getObj("vars");
|
||||
let vars = await this.pipelineContext.getObj("vars");
|
||||
vars = vars || {};
|
||||
merge(vars, instance._result.pipelineVars);
|
||||
await this.pipelineContext.setObj("vars", vars);
|
||||
}
|
||||
if (Object.keys(instance._result.pipelinePrivateVars).length > 0) {
|
||||
// 判断 pipelineVars 有值时更新
|
||||
const vars = await this.pipelineContext.getObj("privateVars");
|
||||
let vars = await this.pipelineContext.getObj("privateVars");
|
||||
vars = vars || {};
|
||||
merge(vars, instance._result.pipelinePrivateVars);
|
||||
await this.pipelineContext.setObj("privateVars", vars);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ export class RunHistory {
|
|||
start(runnable: Runnable): HistoryResult {
|
||||
const now = new Date().getTime();
|
||||
this.logs[runnable.id] = [];
|
||||
this._loggers[runnable.id] = buildLogger((text) => {
|
||||
this._loggers[runnable.id] = buildLogger((text: string) => {
|
||||
this.logs[runnable.id].push(text);
|
||||
});
|
||||
const status: HistoryResult = {
|
||||
|
|
|
@ -166,7 +166,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
|||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return (form.sslProvider === 'zerossl' || !form.zerosslCommonEabAccessId) || (form.sslProvider === 'google' && !form.googleCommonEabAccessId)
|
||||
return (form.sslProvider === 'zerossl' && !form.zerosslCommonEabAccessId) || (form.sslProvider === 'google' && !form.googleCommonEabAccessId)
|
||||
})
|
||||
}
|
||||
`,
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
<template>
|
||||
<a-config-provider :locale="locale" :theme="settingStore.themeToken">
|
||||
<contextHolder />
|
||||
<fs-form-provider>
|
||||
<router-view v-if="routerEnabled" />
|
||||
</fs-form-provider>
|
||||
</a-config-provider>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
<script lang="ts" setup>
|
||||
import zhCN from "ant-design-vue/es/locale/zh_CN";
|
||||
import enUS from "ant-design-vue/es/locale/en_US";
|
||||
import { nextTick, provide, ref } from "vue";
|
||||
|
@ -16,19 +17,22 @@ import { useSettingStore } from "/@/store/modules/settings";
|
|||
import "dayjs/locale/zh-cn";
|
||||
import "dayjs/locale/en";
|
||||
import dayjs from "dayjs";
|
||||
import { Modal } from "ant-design-vue";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
setup() {
|
||||
//刷新页面方法
|
||||
const routerEnabled = ref(true);
|
||||
const locale = ref(zhCN);
|
||||
async function reload() {
|
||||
defineOptions({
|
||||
name: "App"
|
||||
});
|
||||
const [modal, contextHolder] = Modal.useModal();
|
||||
provide("modal", modal);
|
||||
//刷新页面方法
|
||||
const routerEnabled = ref(true);
|
||||
const locale = ref(zhCN);
|
||||
async function reload() {
|
||||
// routerEnabled.value = false;
|
||||
// await nextTick();
|
||||
// routerEnabled.value = true;
|
||||
}
|
||||
function localeChanged(value: any) {
|
||||
}
|
||||
function localeChanged(value: any) {
|
||||
console.log("locale changed:", value);
|
||||
if (value === "zh-cn") {
|
||||
locale.value = zhCN;
|
||||
|
@ -37,23 +41,15 @@ export default {
|
|||
locale.value = enUS;
|
||||
dayjs.locale("en");
|
||||
}
|
||||
}
|
||||
localeChanged("zh-cn");
|
||||
provide("fn:router.reload", reload);
|
||||
provide("fn:locale.changed", localeChanged);
|
||||
}
|
||||
localeChanged("zh-cn");
|
||||
provide("fn:router.reload", reload);
|
||||
provide("fn:locale.changed", localeChanged);
|
||||
|
||||
//其他初始化
|
||||
const resourceStore = useResourceStore();
|
||||
resourceStore.init();
|
||||
const pageStore = usePageStore();
|
||||
pageStore.init();
|
||||
const settingStore = useSettingStore();
|
||||
|
||||
return {
|
||||
routerEnabled,
|
||||
locale,
|
||||
settingStore
|
||||
};
|
||||
}
|
||||
};
|
||||
//其他初始化
|
||||
const resourceStore = useResourceStore();
|
||||
resourceStore.init();
|
||||
const pageStore = usePageStore();
|
||||
pageStore.init();
|
||||
const settingStore = useSettingStore();
|
||||
</script>
|
||||
|
|
|
@ -43,7 +43,6 @@ async function loginWithOTPCode(otpCode: string) {
|
|||
const [modal, contextHolder] = Modal.useModal();
|
||||
async function getDeviceId() {
|
||||
//打开对话框
|
||||
|
||||
modal.confirm({
|
||||
title: "请输入OTP验证码",
|
||||
maskClosable: true,
|
||||
|
|
|
@ -213,6 +213,7 @@ h1, h2, h3, h4, h5, h6 {
|
|||
|
||||
|
||||
.fs-copyable {
|
||||
display: inline-flex;
|
||||
.text {
|
||||
flex: 1
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import { inject } from "vue";
|
||||
import type { ModalStaticFunctions } from "ant-design-vue/es/modal/confirm";
|
||||
import { ModalFuncWithRef } from "ant-design-vue/es/modal/useModal";
|
||||
|
||||
export function useModal(): ModalStaticFunctions<ModalFuncWithRef> {
|
||||
return inject("modal");
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<div class="cert-view">
|
||||
<a-list item-layout="vertical" :data-source="certFiles">
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item key="item.key">
|
||||
<a-list-item-meta>
|
||||
<template #title>
|
||||
<div class="title">
|
||||
<div>{{ item.name }}({{ item.fileName }})</div>
|
||||
<fs-copyable :model-value="item.content" :button="{ show: false }">
|
||||
<a-tag type="success">复制</a-tag>
|
||||
</fs-copyable>
|
||||
</div>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
<div>
|
||||
<a-textarea :value="item.content" rows="5" />
|
||||
</div>
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { CertInfo } from "/@/views/certd/pipeline/api";
|
||||
import { ref } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
cert: CertInfo;
|
||||
}>();
|
||||
|
||||
const certFiles = ref([
|
||||
{ name: "证书", fileName: "fullchain.pem", key: "crt", content: props.cert.crt },
|
||||
{ name: "私钥", fileName: "private.pem", key: "key", content: props.cert.key },
|
||||
{ name: "中间证书", fileName: "chain.pem", key: "ic", content: props.cert.ic }
|
||||
]);
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.cert-view {
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.ant-list-item-meta {
|
||||
margin-block-end: 0px !important;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -11,7 +11,9 @@ import { useUserStore } from "/@/store/modules/user";
|
|||
import dayjs from "dayjs";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import _ from "lodash-es";
|
||||
|
||||
import { useModal } from "/@/use/use-modal";
|
||||
import CertView from "./cert-view.vue";
|
||||
import { eachRunnable, eachStages } from "./utils";
|
||||
export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
|
@ -149,6 +151,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||
});
|
||||
}
|
||||
|
||||
const model = useModal();
|
||||
const viewCert = async (row: any) => {
|
||||
const cert = await api.GetCert(row.id);
|
||||
if (!cert) {
|
||||
|
@ -156,34 +159,20 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||
return;
|
||||
}
|
||||
|
||||
Modal.success({
|
||||
model.success({
|
||||
title: "查看证书",
|
||||
maskClosable: true,
|
||||
okText: "关闭",
|
||||
width: 800,
|
||||
content: () => {
|
||||
return (
|
||||
<div class={"view-cert"}>
|
||||
<div class={"cert-txt"}>
|
||||
<h3>fullchain.pem</h3>
|
||||
<div>{cert.crt}</div>
|
||||
</div>
|
||||
<div class={"cert-txt"}>
|
||||
<h3>private.pem</h3>
|
||||
<div>{cert.key}</div>
|
||||
</div>
|
||||
<div class={"cert-txt"}>
|
||||
<h3>中间证书.pem</h3>
|
||||
<div>{cert.ic}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <CertView cert={cert}></CertView>;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const downloadCert = async (row: any) => {
|
||||
const files = await api.GetFiles(row.id);
|
||||
Modal.success({
|
||||
model.success({
|
||||
title: "文件下载",
|
||||
maskClosable: true,
|
||||
okText: "↑↑↑ 点击上面链接下载",
|
||||
|
@ -198,11 +187,6 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||
{file.filename}
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<a-button type={"primary"} onClick={viewCert}>
|
||||
直接查看证书
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -253,7 +237,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||
buttons: {
|
||||
play: {
|
||||
order: -999,
|
||||
title: null,
|
||||
title: "运行流水线",
|
||||
type: "link",
|
||||
icon: "ant-design:play-circle-outlined",
|
||||
click({ row }) {
|
||||
|
@ -268,6 +252,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||
}
|
||||
},
|
||||
view: {
|
||||
show: false,
|
||||
click({ row }) {
|
||||
router.push({ path: "/certd/pipeline/detail", query: { id: row.id, editMode: "false" } });
|
||||
}
|
||||
|
@ -289,7 +274,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||
},
|
||||
config: {
|
||||
order: 1,
|
||||
title: null,
|
||||
title: "修改流水线内容",
|
||||
type: "link",
|
||||
icon: "ant-design:edit-outlined",
|
||||
click({ row }) {
|
||||
|
@ -298,12 +283,22 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||
},
|
||||
edit: {
|
||||
order: 2,
|
||||
title: "修改流水线运行配置",
|
||||
icon: "ant-design:setting-outlined"
|
||||
},
|
||||
download: {
|
||||
viewCert: {
|
||||
order: 3,
|
||||
title: null,
|
||||
title: "查看证书",
|
||||
type: "link",
|
||||
icon: "ph:certificate",
|
||||
async click({ row }) {
|
||||
viewCert(row);
|
||||
}
|
||||
},
|
||||
download: {
|
||||
order: 4,
|
||||
type: "link",
|
||||
title: "下载证书",
|
||||
icon: "ant-design:download-outlined",
|
||||
async click({ row }) {
|
||||
downloadCert(row);
|
||||
|
@ -373,32 +368,53 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||
}
|
||||
},
|
||||
content: {
|
||||
title: "定时任务数",
|
||||
type: "number",
|
||||
title: "流水线内容",
|
||||
form: { show: false },
|
||||
column: {
|
||||
align: "center",
|
||||
width: 100,
|
||||
cellRender({ value }) {
|
||||
if (value && value.triggers) {
|
||||
return value.triggers?.length > 0 ? value.triggers.length : "-";
|
||||
}
|
||||
return "-";
|
||||
}
|
||||
show: false
|
||||
},
|
||||
valueBuilder({ row }) {
|
||||
if (row.content) {
|
||||
row.content = JSON.parse(row.content);
|
||||
const pipeline = row.content;
|
||||
let stepCount = 0;
|
||||
eachStages(pipeline.stages, (item, runnableType) => {
|
||||
if (runnableType === "step") {
|
||||
stepCount++;
|
||||
}
|
||||
});
|
||||
row._stepCount = stepCount;
|
||||
if (pipeline.triggers) {
|
||||
row._triggerCount = pipeline.triggers?.length > 0 ? pipeline.triggers.length : "-";
|
||||
}
|
||||
}
|
||||
},
|
||||
valueResolve({ row }) {
|
||||
if (row.content) {
|
||||
row.content = JSON.stringify(row.content);
|
||||
}
|
||||
}
|
||||
},
|
||||
_triggerCount: {
|
||||
title: "定时任务数",
|
||||
type: "number",
|
||||
column: {
|
||||
align: "center",
|
||||
width: 100
|
||||
},
|
||||
form: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
_stepCount: {
|
||||
title: "部署任务数",
|
||||
type: "number",
|
||||
form: { show: false },
|
||||
column: {
|
||||
align: "center",
|
||||
width: 100
|
||||
}
|
||||
},
|
||||
lastVars: {
|
||||
title: "到期剩余",
|
||||
type: "number",
|
||||
|
@ -418,18 +434,6 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||
width: 150
|
||||
}
|
||||
},
|
||||
lastHistoryTime: {
|
||||
title: "最后运行",
|
||||
type: "datetime",
|
||||
form: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 150,
|
||||
align: "center"
|
||||
}
|
||||
},
|
||||
status: {
|
||||
title: "状态",
|
||||
type: "dict-select",
|
||||
|
@ -445,7 +449,18 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
|
|||
align: "center"
|
||||
}
|
||||
},
|
||||
|
||||
lastHistoryTime: {
|
||||
title: "最后运行",
|
||||
type: "datetime",
|
||||
form: {
|
||||
show: false
|
||||
},
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 150,
|
||||
align: "center"
|
||||
}
|
||||
},
|
||||
disabled: {
|
||||
title: "启用",
|
||||
type: "dict-switch",
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { forEach } from "lodash-es";
|
||||
|
||||
export function eachStages(list: any[], exec: (item: any, runnableType: string) => void, runnableType: string = "stage") {
|
||||
if (!list || list.length <= 0) {
|
||||
return;
|
||||
}
|
||||
forEach(list, (item) => {
|
||||
exec(item, runnableType);
|
||||
if (runnableType === "stage") {
|
||||
eachStages(item.tasks, exec, "task");
|
||||
} else if (runnableType === "task") {
|
||||
eachStages(item.steps, exec, "step");
|
||||
}
|
||||
});
|
||||
}
|
|
@ -15,7 +15,7 @@ export class CertController extends BaseController {
|
|||
async getCert(@Query('id') id: number) {
|
||||
const userId = this.getUserId();
|
||||
await this.pipelineService.checkUserId(id, userId);
|
||||
const privateVars = this.storeService.getPipelinePrivateVars(id);
|
||||
return this.ok(privateVars);
|
||||
const privateVars = await this.storeService.getPipelinePrivateVars(id);
|
||||
return this.ok(privateVars.cert);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,12 +60,17 @@ export class StorageService extends BaseService<StorageEntity> {
|
|||
if (pipelineId == null) {
|
||||
throw new Error('pipelineId 不能为空');
|
||||
}
|
||||
return await this.repository.find({
|
||||
const res = await this.repository.findOne({
|
||||
where: {
|
||||
scope: 'pipeline',
|
||||
namespace: pipelineId + '',
|
||||
key: 'privateVars',
|
||||
},
|
||||
});
|
||||
if (!res) {
|
||||
return {};
|
||||
}
|
||||
const value = JSON.parse(res.value);
|
||||
return value.value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ export class HostShellExecutePlugin extends AbstractTaskPlugin {
|
|||
name: 'a-textarea',
|
||||
vModel: 'value',
|
||||
rows: 6,
|
||||
placeholder: 'systemctl restart nginx',
|
||||
},
|
||||
helper: '注意:如果目标主机是windows,且终端是cmd,系统会自动将多行命令通过“&&”连接成一行',
|
||||
required: true,
|
||||
|
|
Loading…
Reference in New Issue