feat: Enable core to use local config files while being managed via the web (#1540)

This commit is contained in:
Mg Pig
2025-11-08 20:32:00 +08:00
committed by GitHub
parent b50744690e
commit 1273426009
24 changed files with 800 additions and 228 deletions
@@ -56,6 +56,23 @@ const onLazyLoadNetworkMetas = async (event: VirtualScrollerLazyEvent) => {
.map(item => item.uuid);
await loadNetworkMetas(instanceIds);
};
const currentNetworkMeta = computed(() => {
if (!instanceId.value) {
return undefined;
}
return networkMetaCache.value[instanceId.value];
});
const currentNetworkControl = {
remoteSave: computed(() => {
return Api.ConfigFilePermission.isRemoveSaveable(currentNetworkMeta.value?.config_permission ?? 0);
}),
editable: computed(() => {
return Api.ConfigFilePermission.isEditable(currentNetworkMeta.value?.config_permission ?? 0);
}),
deletable: computed(() => {
return Api.ConfigFilePermission.isDeletable(currentNetworkMeta.value?.config_permission ?? 0);
})
}
const instanceList = ref<Array<{ uuid: string; meta?: Api.NetworkMeta }>>([]);
const updateInstanceList = () => {
@@ -150,17 +167,12 @@ const loadCurrentNetworkConfig = async () => {
currentNetworkConfig.value = ret;
}
const updateNetworkState = async (disabled: boolean) => {
const stopNetwork = async () => {
if (!selectedInstanceId.value) {
return;
}
if (disabled || !currentNetworkConfig.value) {
await props.api.update_network_instance_state(selectedInstanceId.value.uuid, disabled);
} else if (currentNetworkConfig.value) {
await props.api.delete_network(currentNetworkConfig.value.instance_id);
await props.api.run_network(currentNetworkConfig.value);
}
await props.api.update_network_instance_state(selectedInstanceId.value.uuid, true);
await loadNetworkInstanceIds();
}
@@ -199,7 +211,7 @@ const saveAndRunNewNetwork = async () => {
}
try {
await props.api.delete_network(instanceId.value!);
let ret = await props.api.run_network(currentNetworkConfig.value);
let ret = await props.api.run_network(currentNetworkConfig.value, currentNetworkControl.remoteSave.value);
console.debug("saveAndRunNewNetwork", ret);
delete networkMetaCache.value[currentNetworkConfig.value.instance_id];
@@ -377,7 +389,7 @@ const actionMenu: Ref<MenuItem[]> = ref([
{
label: t('web.device_management.edit_network'),
icon: 'pi pi-pencil',
visible: () => !(networkIsDisabled.value ?? true),
visible: () => !(networkIsDisabled.value ?? true) && currentNetworkControl.editable.value,
command: () => editNetwork()
},
{
@@ -389,6 +401,7 @@ const actionMenu: Ref<MenuItem[]> = ref([
label: t('web.device_management.delete_network'),
icon: 'pi pi-trash',
class: 'p-error',
visible: () => currentNetworkControl.deletable.value,
command: () => confirmDeleteNetwork(new Event('click'))
}
]);
@@ -443,7 +456,7 @@ onUnmounted(() => {
<span class="truncate block">
&nbsp;
<span v-if="slotProps.value.meta">
{{ slotProps.value.meta.instance_name }} ({{ slotProps.value.uuid }})
{{ slotProps.value.meta.network_name }} ({{ slotProps.value.uuid }})
</span>
<span v-else>
{{ slotProps.value.uuid }}
@@ -463,7 +476,7 @@ onUnmounted(() => {
<div class="flex items-center min-w-0">
<div class="mr-4 min-w-0 flex-1">
<span class="truncate block">{{ t('network_name') }}: {{
slotProps.option.meta.instance_name }}</span>
slotProps.option.meta.network_name }}</span>
</div>
<Tag class="my-auto leading-3 shrink-0"
:severity="isRunning(slotProps.option.uuid) ? 'success' : 'info'"
@@ -544,8 +557,9 @@ onUnmounted(() => {
<Message v-else severity="error" class="mb-4">{{ curNetworkInfo?.error_msg }}</Message>
<div class="text-center mt-4">
<Button @click="updateNetworkState(true)" :label="t('web.device_management.disable_network')"
severity="warning" icon="pi pi-power-off" iconPos="left" />
<Button @click="stopNetwork" :disabled="!currentNetworkControl.deletable.value"
:label="t('web.device_management.disable_network')" severity="danger" icon="pi pi-power-off"
iconPos="left" />
</div>
</div>
+21 -2
View File
@@ -26,8 +26,27 @@ export interface CollectNetworkInfoResponse {
}
}
export namespace ConfigFilePermission {
export type Flags = number;
export const READ_ONLY: Flags = 1 << 0;
export const NO_DELETE: Flags = 1 << 1;
export function hasPermission(perm: Flags, flag: Flags): boolean {
return (perm & flag) === flag;
}
export function isRemoveSaveable(perm: Flags): boolean {
return !hasPermission(perm, NO_DELETE);
}
export function isEditable(perm: Flags): boolean {
return !hasPermission(perm, READ_ONLY);
}
export function isDeletable(perm: Flags): boolean {
return !hasPermission(perm, NO_DELETE);
}
}
export interface NetworkMeta {
instance_name: string;
network_name: string;
config_permission: ConfigFilePermission.Flags;
}
export interface GetNetworkMetasResponse {
@@ -36,7 +55,7 @@ export interface GetNetworkMetasResponse {
export interface RemoteClient {
validate_config(config: NetworkConfig): Promise<ValidateConfigResponse>;
run_network(config: NetworkConfig): Promise<undefined>;
run_network(config: NetworkConfig, save: boolean): Promise<undefined>;
get_network_info(inst_id: string): Promise<NetworkInstanceRunningInfo | undefined>;
list_network_instance_ids(): Promise<ListNetworkInstanceIdResponse>;
delete_network(inst_id: string): Promise<undefined>;
+2 -1
View File
@@ -193,9 +193,10 @@ class WebRemoteClient implements Api.RemoteClient {
});
return response;
}
async run_network(config: NetworkTypes.NetworkConfig): Promise<undefined> {
async run_network(config: NetworkTypes.NetworkConfig, save: boolean): Promise<undefined> {
await this.client.post<string>(`/machines/${this.machine_id}/networks`, {
config: config,
save: save
});
}
async get_network_info(inst_id: string): Promise<NetworkTypes.NetworkInstanceRunningInfo | undefined> {
@@ -280,6 +280,7 @@ impl Session {
config: Some(
serde_json::from_str::<NetworkConfig>(&c.network_config).unwrap(),
),
overwrite: false,
},
)
.await;
+2 -10
View File
@@ -155,7 +155,7 @@ impl Storage<(UserIdInDb, Uuid), user_running_network_configs::Model, DbErr> for
(user_id, _): (UserIdInDb, Uuid),
network_inst_id: Uuid,
disabled: bool,
) -> Result<user_running_network_configs::Model, DbErr> {
) -> Result<(), DbErr> {
use entity::user_running_network_configs as urnc;
urnc::Entity::update_many()
@@ -169,15 +169,7 @@ impl Storage<(UserIdInDb, Uuid), user_running_network_configs::Model, DbErr> for
.exec(self.orm_db())
.await?;
urnc::Entity::find()
.filter(urnc::Column::UserId.eq(user_id))
.filter(urnc::Column::NetworkInstanceId.eq(network_inst_id.to_string()))
.one(self.orm_db())
.await?
.ok_or(DbErr::RecordNotFound(format!(
"Network config not found for user {} and network instance {}",
user_id, network_inst_id
)))
Ok(())
}
async fn list_network_configs(
+2
View File
@@ -59,6 +59,7 @@ struct SaveNetworkJsonReq {
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct RunNetworkJsonReq {
config: NetworkConfig,
save: bool,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
@@ -132,6 +133,7 @@ impl NetworkApi {
.handle_run_network_instance(
(Self::get_user_id(&auth_session)?, machine_id),
payload.config,
payload.save,
)
.await
.map_err(convert_error)?;