Skip to content

Commit 4d4791c

Browse files
committed
feat: add advanced controls for iptables management
1 parent 1d81280 commit 4d4791c

File tree

2 files changed

+124
-77
lines changed

2 files changed

+124
-77
lines changed

frontend/src/views/host/firewall/filter/index.vue

Lines changed: 77 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,61 @@
22
<div>
33
<FireRouter />
44

5-
<div v-if="!isIptables">
6-
<LayoutContent :divider="true">
7-
<template #main>
8-
<div class="app-warn">
9-
<div class="flex flex-col gap-2 items-center justify-center w-full sm:flex-row">
10-
<span>{{ $t('firewall.advancedControlNotAvailable', [firewallName]) }}</span>
5+
<div v-loading="loading">
6+
<FireStatus
7+
ref="fireStatusRef"
8+
@search="search"
9+
@advanced-operate="onApplyFirewall"
10+
v-model:loading="loading"
11+
v-model:mask-show="maskShow"
12+
v-model:is-active="isActive"
13+
v-model:name="fireName"
14+
:show-advanced-controls="true"
15+
:can-apply="canApply"
16+
:is-applied="isApplied"
17+
/>
18+
<div v-if="fireName === '-'">
19+
<LayoutContent :divider="true">
20+
<template #main>
21+
<div class="app-warn">
22+
<div class="flex flex-col gap-2 items-center justify-center w-full sm:flex-row">
23+
<span>{{ $t('firewall.advancedControlNotAvailable', [firewallName]) }}</span>
24+
</div>
25+
<div>
26+
<img src="@/assets/images/no_app.svg" />
27+
</div>
1128
</div>
12-
<div>
13-
<img src="@/assets/images/no_app.svg" />
29+
</template>
30+
</LayoutContent>
31+
</div>
32+
33+
<div v-else-if="!isIptablesComputed">
34+
<LayoutContent :divider="true">
35+
<template #main>
36+
<div class="app-warn">
37+
<div class="flex flex-col gap-2 items-center justify-center w-full sm:flex-row">
38+
<span>{{ $t('firewall.advancedControlNotAvailable', [fireName]) }}</span>
39+
</div>
40+
<div>
41+
<img src="@/assets/images/no_app.svg" />
42+
</div>
1443
</div>
15-
</div>
16-
</template>
17-
</LayoutContent>
18-
</div>
44+
</template>
45+
</LayoutContent>
46+
</div>
1947

20-
<div v-else v-loading="loading">
21-
<el-card>
22-
<div class="flex w-full flex-col gap-4 md:flex-row">
23-
<div class="flex flex-wrap gap-4 ml-3">
24-
<el-tag effect="dark" type="success">{{ 'iptables v' + iptablesVersion }}</el-tag>
25-
<el-tag :type="inputChainInfo?.isApplied ? 'success' : 'info'" size="small">
26-
{{ inputChainInfo?.isApplied ? $t('firewall.applied') : $t('firewall.notApplied') }}
27-
</el-tag>
28-
</div>
29-
</div>
30-
</el-card>
31-
<div>
32-
<LayoutContent :title="$t('firewall.filterRule')">
48+
<div v-else>
49+
<el-card v-if="!isActive && maskShow" class="mask-prompt">
50+
<span>{{ $t('firewall.firewallNotStart') }}</span>
51+
</el-card>
52+
<LayoutContent :title="$t('firewall.filterRule')" :class="{ mask: !isActive }">
3353
<template #leftToolBar>
3454
<el-button type="primary" @click="onOpenDialog('create')" :disabled="!isCustomChain">
3555
{{ $t('firewall.create') }}
3656
</el-button>
3757
<el-button @click="onDelete(null)" plain :disabled="selects.length === 0 || !isCustomChain">
3858
{{ $t('commons.button.delete') }}
3959
</el-button>
40-
<el-button @click="onInitChains" plain>
41-
{{ $t('firewall.initChains') }}
42-
</el-button>
43-
<el-button @click="onApplyFirewall('apply')" plain type="success" :disabled="!canApply">
44-
{{ $t('firewall.applyFirewall') }}
45-
</el-button>
46-
<el-button @click="onApplyFirewall('unload')" plain type="warning" :disabled="!isApplied">
47-
{{ $t('firewall.unloadFirewall') }}
48-
</el-button>
4960
</template>
5061

5162
<template #rightToolBar>
@@ -156,9 +167,10 @@
156167

157168
<script lang="ts" setup>
158169
import FireRouter from '@/views/host/firewall/index.vue';
170+
import FireStatus from '@/views/host/firewall/status/index.vue';
159171
import OperateDialog from '@/views/host/firewall/filter/operate/index.vue';
160172
import { computed, onMounted, reactive, ref } from 'vue';
161-
import { getFilterRules, applyFilterFirewall, batchOperateFilterRule, loadFireBaseInfo } from '@/api/modules/host';
173+
import { getFilterRules, applyFilterFirewall, batchOperateFilterRule } from '@/api/modules/host';
162174
import { Host } from '@/api/interface/host';
163175
import i18n from '@/lang';
164176
import { MsgSuccess } from '@/utils/message';
@@ -169,7 +181,11 @@ const selects = ref<any>([]);
169181
const selectedChain = ref('1PANEL_INPUT');
170182
const iptablesVersion = ref('');
171183
const firewallName = ref('');
172-
const isIptables = ref(true);
184+
185+
const maskShow = ref(true);
186+
const isActive = ref(false);
187+
const fireName = ref();
188+
const fireStatusRef = ref();
173189
174190
const opRef = ref();
175191
@@ -189,6 +205,7 @@ const formatPort = (port?: number | null | string) => {
189205
return port;
190206
};
191207
208+
const isIptablesComputed = computed(() => fireName.value === 'iptables');
192209
const inputChainInfo = computed(() => chainInfoMap.value.get('INPUT'));
193210
const outputChainInfo = computed(() => chainInfoMap.value.get('OUTPUT'));
194211
@@ -216,6 +233,12 @@ const paginationConfig = reactive({
216233
});
217234
218235
const search = async () => {
236+
if (!isActive.value) {
237+
loading.value = false;
238+
chainInfoMap.value.clear();
239+
paginationConfig.total = 0;
240+
return;
241+
}
219242
const params: Host.IptablesFilterRuleSearch = {
220243
chains: ['INPUT', 'OUTPUT', '1PANEL_INPUT', '1PANEL_OUTPUT'],
221244
};
@@ -254,29 +277,20 @@ const onOpenDialog = async (title: string, rowData?: Host.IptablesFilterRuleOper
254277
dialogRef.value!.acceptParams(params);
255278
};
256279
257-
const onInitChains = async () => {
258-
ElMessageBox.confirm(i18n.global.t('firewall.initChainsConfirm'), i18n.global.t('firewall.initChains'), {
259-
confirmButtonText: i18n.global.t('commons.button.confirm'),
260-
cancelButtonText: i18n.global.t('commons.button.cancel'),
261-
}).then(async () => {
262-
loading.value = true;
263-
await applyFilterFirewall({ operation: 'init' })
264-
.then(() => {
265-
loading.value = false;
266-
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
267-
search();
268-
})
269-
.catch(() => {
270-
loading.value = false;
271-
});
272-
});
273-
};
274-
275280
const onApplyFirewall = async (operation: string) => {
276-
const confirmMsg =
277-
operation === 'apply' ? i18n.global.t('firewall.applyConfirm') : i18n.global.t('firewall.unloadConfirm');
278-
const title =
279-
operation === 'apply' ? i18n.global.t('firewall.applyFirewall') : i18n.global.t('firewall.unloadFirewall');
281+
let confirmMsg = '';
282+
let title = '';
283+
284+
if (operation === 'init') {
285+
confirmMsg = i18n.global.t('firewall.initChainsConfirm');
286+
title = i18n.global.t('firewall.initChains');
287+
} else if (operation === 'apply') {
288+
confirmMsg = i18n.global.t('firewall.applyConfirm');
289+
title = i18n.global.t('firewall.applyFirewall');
290+
} else {
291+
confirmMsg = i18n.global.t('firewall.unloadConfirm');
292+
title = i18n.global.t('firewall.unloadFirewall');
293+
}
280294
281295
ElMessageBox.confirm(confirmMsg, title, {
282296
confirmButtonText: i18n.global.t('commons.button.confirm'),
@@ -345,18 +359,11 @@ const buttons = [
345359
},
346360
];
347361
348-
onMounted(async () => {
349-
await loadFireBaseInfo()
350-
.then((res) => {
351-
firewallName.value = res.data.name;
352-
isIptables.value = res.data.name === 'iptables';
353-
if (isIptables.value) {
354-
search();
355-
}
356-
})
357-
.catch(() => {
358-
isIptables.value = false;
359-
});
362+
onMounted(() => {
363+
if (fireName.value !== '-') {
364+
loading.value = true;
365+
fireStatusRef.value.acceptParams();
366+
}
360367
});
361368
</script>
362369

frontend/src/views/host/firewall/status/index.vue

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,32 @@
99
<el-tag>{{ $t('app.version') }}: {{ baseInfo.version }}</el-tag>
1010
</div>
1111
<div class="mt-0.5">
12-
<el-button type="primary" v-if="baseInfo.isActive" @click="onOperate('stop')" link>
13-
{{ $t('commons.button.stop') }}
14-
</el-button>
15-
<el-button type="primary" v-if="!baseInfo.isActive" @click="onOperate('start')" link>
16-
{{ $t('commons.button.start') }}
17-
</el-button>
1812
<template v-if="baseInfo.name !== 'iptables'">
13+
<el-button type="primary" v-if="baseInfo.isActive" @click="onOperate('stop')" link>
14+
{{ $t('commons.button.stop') }}
15+
</el-button>
16+
<el-button type="primary" v-if="!baseInfo.isActive" @click="onOperate('start')" link>
17+
{{ $t('commons.button.start') }}
18+
</el-button>
1919
<el-divider direction="vertical" />
2020
<el-button type="primary" @click="onOperate('restart')" link>
2121
{{ $t('commons.button.restart') }}
2222
</el-button>
2323
</template>
24+
<template v-if="baseInfo.name === 'iptables' && showAdvancedControls">
25+
<el-divider direction="vertical" />
26+
<el-button type="primary" @click="onAdvancedOperate('init')" link>
27+
{{ $t('firewall.initChains') }}
28+
</el-button>
29+
<el-divider direction="vertical" />
30+
<el-button type="success" @click="onAdvancedOperate('apply')" link :disabled="!canApply">
31+
{{ $t('firewall.applyFirewall') }}
32+
</el-button>
33+
<el-divider direction="vertical" />
34+
<el-button type="warning" @click="onAdvancedOperate('unload')" link :disabled="!isApplied">
35+
{{ $t('firewall.unloadFirewall') }}
36+
</el-button>
37+
</template>
2438
<span v-if="onPing !== 'None'">
2539
<el-divider direction="vertical" />
2640
<el-button type="primary" link>{{ $t('firewall.noPing') }}</el-button>
@@ -61,6 +75,21 @@ import { MsgSuccess } from '@/utils/message';
6175
import { ElMessageBox } from 'element-plus';
6276
import { ref } from 'vue';
6377
78+
defineProps({
79+
showAdvancedControls: {
80+
type: Boolean,
81+
default: false,
82+
},
83+
canApply: {
84+
type: Boolean,
85+
default: false,
86+
},
87+
isApplied: {
88+
type: Boolean,
89+
default: false,
90+
},
91+
});
92+
6493
const baseInfo = ref<Host.FirewallBase>({ isActive: false, isExist: true, name: '', version: '', pingStatus: '' });
6594
const onPing = ref('Disable');
6695
const oldStatus = ref();
@@ -71,7 +100,14 @@ const withDockerRestart = ref(false);
71100
const acceptParams = (): void => {
72101
loadBaseInfo(true);
73102
};
74-
const emit = defineEmits(['search', 'update:is-active', 'update:loading', 'update:maskShow', 'update:name']);
103+
const emit = defineEmits([
104+
'search',
105+
'update:is-active',
106+
'update:loading',
107+
'update:maskShow',
108+
'update:name',
109+
'advanced-operate',
110+
]);
75111
76112
const loadBaseInfo = async (search: boolean) => {
77113
await loadFireBaseInfo()
@@ -153,6 +189,10 @@ const onPingOperate = async (operation: string) => {
153189
});
154190
};
155191
192+
const onAdvancedOperate = (operation: string) => {
193+
emit('advanced-operate', operation);
194+
};
195+
156196
defineExpose({
157197
acceptParams,
158198
});

0 commit comments

Comments
 (0)