✨feat(nacos): 增加应用名称支持,优化配置查询功能
- 新增应用名称字段到配置查询接口 - 更新前端界面以支持应用名称输入 - 调整后端逻辑以处理应用名称参数
This commit is contained in:
4 files changed
+40
-14
No files matched your search
@@ -49,6 +49,7 @@ const configLoading = ref(false);
|
|||||||
const configError = ref("");
|
const configError = ref("");
|
||||||
const configGroup = ref("");
|
const configGroup = ref("");
|
||||||
const configDataId = ref("");
|
const configDataId = ref("");
|
||||||
|
const configAppName = ref("");
|
||||||
const configPageNo = ref(1);
|
const configPageNo = ref(1);
|
||||||
const configPageSize = ref(20);
|
const configPageSize = ref(20);
|
||||||
const configs = ref<NacosConfigItem[]>([]);
|
const configs = ref<NacosConfigItem[]>([]);
|
||||||
@@ -370,6 +371,7 @@ async function loadConfigs(page = configPageNo.value) {
|
|||||||
namespace: namespace.value || undefined,
|
namespace: namespace.value || undefined,
|
||||||
group: configGroup.value.trim() || undefined,
|
group: configGroup.value.trim() || undefined,
|
||||||
dataId: configDataId.value.trim() || undefined,
|
dataId: configDataId.value.trim() || undefined,
|
||||||
|
appName: configAppName.value.trim() || undefined,
|
||||||
pageNo: configPageNo.value,
|
pageNo: configPageNo.value,
|
||||||
pageSize: configPageSize.value,
|
pageSize: configPageSize.value,
|
||||||
});
|
});
|
||||||
@@ -881,9 +883,10 @@ onBeforeUnmount(() => {
|
|||||||
<Splitpanes v-if="activeTab === 'configs'" class="nacos-admin-splitpanes min-h-0 flex-1" @resized="handleNacosSplitResized">
|
<Splitpanes v-if="activeTab === 'configs'" class="nacos-admin-splitpanes min-h-0 flex-1" @resized="handleNacosSplitResized">
|
||||||
<Pane :size="nacosSplitSize" min-size="24">
|
<Pane :size="nacosSplitSize" min-size="24">
|
||||||
<div class="flex h-full min-h-0 flex-col">
|
<div class="flex h-full min-h-0 flex-col">
|
||||||
<div class="grid shrink-0 grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto_auto] gap-2 border-b p-2">
|
<div class="grid shrink-0 grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_auto_auto] gap-2 border-b p-2">
|
||||||
<Input v-model="configDataId" class="h-8 min-w-0" placeholder="dataId" @keyup.enter="loadConfigsWithRetry(1)" />
|
<Input v-model="configDataId" class="h-8 min-w-0" placeholder="dataId" @keyup.enter="loadConfigsWithRetry(1)" />
|
||||||
<Input v-model="configGroup" class="h-8 min-w-0" :placeholder="t('nacos.allGroups')" @keyup.enter="loadConfigsWithRetry(1)" />
|
<Input v-model="configGroup" class="h-8 min-w-0" :placeholder="t('nacos.allGroups')" @keyup.enter="loadConfigsWithRetry(1)" />
|
||||||
|
<Input v-model="configAppName" class="h-8 min-w-0" :placeholder="t('nacos.application')" @keyup.enter="loadConfigsWithRetry(1)" />
|
||||||
<Button size="sm" variant="outline" class="h-8 w-9 px-0" :title="t('nacos.load')" :disabled="configLoading" @click="loadConfigsWithRetry(1)">
|
<Button size="sm" variant="outline" class="h-8 w-9 px-0" :title="t('nacos.load')" :disabled="configLoading" @click="loadConfigsWithRetry(1)">
|
||||||
<Loader2 v-if="configLoading" class="h-3.5 w-3.5 animate-spin" />
|
<Loader2 v-if="configLoading" class="h-3.5 w-3.5 animate-spin" />
|
||||||
<RefreshCw v-else class="h-3.5 w-3.5" />
|
<RefreshCw v-else class="h-3.5 w-3.5" />
|
||||||
@@ -894,16 +897,17 @@ onBeforeUnmount(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="configError" class="border-b px-3 py-2 text-xs text-destructive">{{ configError }}</div>
|
<div v-if="configError" class="border-b px-3 py-2 text-xs text-destructive">{{ configError }}</div>
|
||||||
<div class="min-h-0 flex-1 overflow-auto">
|
<div class="min-h-0 flex-1 overflow-auto">
|
||||||
<div class="sticky top-0 z-10 grid grid-cols-[minmax(0,1fr)_128px_84px] border-b bg-muted/70 px-3 py-2 text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
<div class="sticky top-0 z-20 grid grid-cols-4 border-b bg-muted px-3 py-2 text-[11px] font-medium uppercase tracking-wide text-muted-foreground shadow-sm">
|
||||||
<span>dataID</span>
|
<span class="truncate pr-3">dataID</span>
|
||||||
<span>{{ t("nacos.group") }}</span>
|
<span class="truncate pr-3">{{ t("nacos.group") }}</span>
|
||||||
<span>{{ t("nacos.format") }}</span>
|
<span class="truncate pr-3">{{ t("nacos.application") }}</span>
|
||||||
|
<span class="truncate">{{ t("nacos.format") }}</span>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
v-for="item in configs"
|
v-for="item in configs"
|
||||||
:key="`${item.namespace}:${item.group}:${item.dataId}`"
|
:key="`${item.namespace}:${item.group}:${item.dataId}`"
|
||||||
type="button"
|
type="button"
|
||||||
class="grid w-full grid-cols-[minmax(0,1fr)_128px_84px] items-center border-b px-3 py-2.5 text-left text-sm transition-colors hover:bg-accent/50"
|
class="grid w-full grid-cols-4 items-center border-b px-3 py-2.5 text-left text-sm transition-colors hover:bg-accent/50"
|
||||||
:class="{ 'bg-accent': selectedConfig?.dataId === item.dataId && selectedConfig?.group === item.group }"
|
:class="{ 'bg-accent': selectedConfig?.dataId === item.dataId && selectedConfig?.group === item.group }"
|
||||||
@click="selectConfig(item)"
|
@click="selectConfig(item)"
|
||||||
>
|
>
|
||||||
@@ -912,6 +916,7 @@ onBeforeUnmount(() => {
|
|||||||
<span class="truncate font-medium text-foreground">{{ item.dataId }}</span>
|
<span class="truncate font-medium text-foreground">{{ item.dataId }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="truncate pr-3 text-xs text-muted-foreground" :title="item.group || 'DEFAULT_GROUP'">{{ item.group || "DEFAULT_GROUP" }}</span>
|
<span class="truncate pr-3 text-xs text-muted-foreground" :title="item.group || 'DEFAULT_GROUP'">{{ item.group || "DEFAULT_GROUP" }}</span>
|
||||||
|
<span class="truncate pr-3 text-xs text-muted-foreground" :title="item.appName || '-'">{{ item.appName || "-" }}</span>
|
||||||
<span class="truncate text-xs text-muted-foreground" :title="configFormatLabel(item)">{{ configFormatLabel(item) }}</span>
|
<span class="truncate text-xs text-muted-foreground" :title="configFormatLabel(item)">{{ configFormatLabel(item) }}</span>
|
||||||
</button>
|
</button>
|
||||||
<div v-if="!configLoading && configs.length === 0" class="flex h-full items-center justify-center text-sm text-muted-foreground">{{ t("nacos.noConfigs") }}</div>
|
<div v-if="!configLoading && configs.length === 0" class="flex h-full items-center justify-center text-sm text-muted-foreground">{{ t("nacos.noConfigs") }}</div>
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ export interface NacosConfigQuery {
|
|||||||
namespace?: string;
|
namespace?: string;
|
||||||
group?: string;
|
group?: string;
|
||||||
dataId?: string;
|
dataId?: string;
|
||||||
|
appName?: string;
|
||||||
search?: string;
|
search?: string;
|
||||||
pageNo?: number;
|
pageNo?: number;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
|
|||||||
@@ -198,10 +198,11 @@ impl NacosOpenApiAdmin {
|
|||||||
namespace: &str,
|
namespace: &str,
|
||||||
search: &str,
|
search: &str,
|
||||||
group: &str,
|
group: &str,
|
||||||
|
app_name: &str,
|
||||||
page_no: u32,
|
page_no: u32,
|
||||||
page_size: u32,
|
page_size: u32,
|
||||||
) -> Result<Value, String> {
|
) -> Result<Value, String> {
|
||||||
let v3_params = vec![
|
let mut v3_params = vec![
|
||||||
("search".to_string(), "blur".to_string()),
|
("search".to_string(), "blur".to_string()),
|
||||||
("dataId".to_string(), search.to_string()),
|
("dataId".to_string(), search.to_string()),
|
||||||
("groupName".to_string(), group.to_string()),
|
("groupName".to_string(), group.to_string()),
|
||||||
@@ -209,10 +210,11 @@ impl NacosOpenApiAdmin {
|
|||||||
("pageNo".to_string(), page_no.to_string()),
|
("pageNo".to_string(), page_no.to_string()),
|
||||||
("pageSize".to_string(), page_size.to_string()),
|
("pageSize".to_string(), page_size.to_string()),
|
||||||
];
|
];
|
||||||
|
push_optional(&mut v3_params, "appName", Some(app_name.to_string()));
|
||||||
match self.get_json("/v3/console/cs/config/list", v3_params).await {
|
match self.get_json("/v3/console/cs/config/list", v3_params).await {
|
||||||
Ok(value) => Ok(value),
|
Ok(value) => Ok(value),
|
||||||
Err(v3_err) => {
|
Err(v3_err) => {
|
||||||
let v1_params = vec![
|
let mut v1_params = vec![
|
||||||
("search".to_string(), "blur".to_string()),
|
("search".to_string(), "blur".to_string()),
|
||||||
("dataId".to_string(), search.to_string()),
|
("dataId".to_string(), search.to_string()),
|
||||||
("group".to_string(), group.to_string()),
|
("group".to_string(), group.to_string()),
|
||||||
@@ -220,6 +222,7 @@ impl NacosOpenApiAdmin {
|
|||||||
("pageNo".to_string(), page_no.to_string()),
|
("pageNo".to_string(), page_no.to_string()),
|
||||||
("pageSize".to_string(), page_size.to_string()),
|
("pageSize".to_string(), page_size.to_string()),
|
||||||
];
|
];
|
||||||
|
push_optional(&mut v1_params, "appName", Some(app_name.to_string()));
|
||||||
self.get_json("/v1/cs/configs", v1_params).await.map_err(|v1_err| {
|
self.get_json("/v1/cs/configs", v1_params).await.map_err(|v1_err| {
|
||||||
format!("Failed to list Nacos configs with v3 and v1 APIs. v3: {v3_err}; v1: {v1_err}")
|
format!("Failed to list Nacos configs with v3 and v1 APIs. v3: {v3_err}; v1: {v1_err}")
|
||||||
})
|
})
|
||||||
@@ -285,6 +288,7 @@ impl NacosOpenApiAdmin {
|
|||||||
namespace: String,
|
namespace: String,
|
||||||
group: Option<String>,
|
group: Option<String>,
|
||||||
data_id_filter: Option<String>,
|
data_id_filter: Option<String>,
|
||||||
|
app_name_filter: Option<String>,
|
||||||
page_no: u32,
|
page_no: u32,
|
||||||
page_size: u32,
|
page_size: u32,
|
||||||
) -> Result<NacosConfigList, String> {
|
) -> Result<NacosConfigList, String> {
|
||||||
@@ -292,13 +296,15 @@ impl NacosOpenApiAdmin {
|
|||||||
return Ok(NacosConfigList { page_no, page_size, total_count: 0, items: Vec::new() });
|
return Ok(NacosConfigList { page_no, page_size, total_count: 0, items: Vec::new() });
|
||||||
};
|
};
|
||||||
let group = group.unwrap_or_default();
|
let group = group.unwrap_or_default();
|
||||||
|
let app_name = app_name_filter.unwrap_or_default();
|
||||||
let scan_page_size = page_size.max(self.cfg.page_size).clamp(100, 500);
|
let scan_page_size = page_size.max(self.cfg.page_size).clamp(100, 500);
|
||||||
let max_scan_pages = 10;
|
let max_scan_pages = 10;
|
||||||
let mut matched = Vec::new();
|
let mut matched = Vec::new();
|
||||||
let mut current_page = 1;
|
let mut current_page = 1;
|
||||||
|
|
||||||
while current_page <= max_scan_pages {
|
while current_page <= max_scan_pages {
|
||||||
let value = self.get_config_list_value(&namespace, "", &group, current_page, scan_page_size).await?;
|
let value =
|
||||||
|
self.get_config_list_value(&namespace, "", &group, &app_name, current_page, scan_page_size).await?;
|
||||||
let list = parse_config_list(value, namespace.clone(), current_page, scan_page_size);
|
let list = parse_config_list(value, namespace.clone(), current_page, scan_page_size);
|
||||||
matched.extend(list.items.into_iter().filter(|item| item.data_id.to_lowercase().contains(&filter)));
|
matched.extend(list.items.into_iter().filter(|item| item.data_id.to_lowercase().contains(&filter)));
|
||||||
|
|
||||||
@@ -459,12 +465,22 @@ impl NacosAdmin for NacosOpenApiAdmin {
|
|||||||
let search = data_id_filter.clone().unwrap_or_default();
|
let search = data_id_filter.clone().unwrap_or_default();
|
||||||
let group_filter = query.group.clone();
|
let group_filter = query.group.clone();
|
||||||
let group = group_filter.clone().unwrap_or_default();
|
let group = group_filter.clone().unwrap_or_default();
|
||||||
let value = self.get_config_list_value(&namespace, &search, &group, page_no, page_size).await?;
|
let app_name_filter = query.app_name.map(|value| value.trim().to_string()).filter(|value| !value.is_empty());
|
||||||
|
let app_name = app_name_filter.clone().unwrap_or_default();
|
||||||
|
let value = self.get_config_list_value(&namespace, &search, &group, &app_name, page_no, page_size).await?;
|
||||||
let parsed =
|
let parsed =
|
||||||
self.enrich_missing_config_formats(parse_config_list(value, namespace.clone(), page_no, page_size)).await;
|
self.enrich_missing_config_formats(parse_config_list(value, namespace.clone(), page_no, page_size)).await;
|
||||||
if data_id_filter.is_some() && parsed.items.is_empty() {
|
if data_id_filter.is_some() && parsed.items.is_empty() {
|
||||||
let fallback =
|
let fallback = self
|
||||||
self.list_configs_by_client_filter(namespace, group_filter, data_id_filter, page_no, page_size).await?;
|
.list_configs_by_client_filter(
|
||||||
|
namespace,
|
||||||
|
group_filter,
|
||||||
|
data_id_filter,
|
||||||
|
app_name_filter,
|
||||||
|
page_no,
|
||||||
|
page_size,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
if !fallback.items.is_empty() {
|
if !fallback.items.is_empty() {
|
||||||
return Ok(fallback);
|
return Ok(fallback);
|
||||||
}
|
}
|
||||||
@@ -1395,7 +1411,7 @@ mod tests {
|
|||||||
let parsed = parse_config_list(
|
let parsed = parse_config_list(
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"totalCount": 1,
|
"totalCount": 1,
|
||||||
"pageItems": [{ "dataId": "app.yaml", "group": "DEFAULT_GROUP", "type": "yaml" }]
|
"pageItems": [{ "dataId": "app.yaml", "group": "DEFAULT_GROUP", "type": "yaml", "appName": "portal" }]
|
||||||
}),
|
}),
|
||||||
"public".to_string(),
|
"public".to_string(),
|
||||||
1,
|
1,
|
||||||
@@ -1404,6 +1420,7 @@ mod tests {
|
|||||||
assert_eq!(parsed.total_count, 1);
|
assert_eq!(parsed.total_count, 1);
|
||||||
assert_eq!(parsed.items[0].data_id, "app.yaml");
|
assert_eq!(parsed.items[0].data_id, "app.yaml");
|
||||||
assert_eq!(parsed.items[0].namespace, "public");
|
assert_eq!(parsed.items[0].namespace, "public");
|
||||||
|
assert_eq!(parsed.items[0].app_name.as_deref(), Some("portal"));
|
||||||
assert_eq!(parsed.items[0].config_type.as_deref(), Some("yaml"));
|
assert_eq!(parsed.items[0].config_type.as_deref(), Some("yaml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1451,7 +1468,7 @@ mod tests {
|
|||||||
"data": {
|
"data": {
|
||||||
"totalCount": 1,
|
"totalCount": 1,
|
||||||
"pageItems": [
|
"pageItems": [
|
||||||
{ "dataId": "app.json", "groupName": "DEFAULT_GROUP", "namespaceId": "public" }
|
{ "dataId": "app.json", "groupName": "DEFAULT_GROUP", "namespaceId": "public", "appName": "console" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -1461,6 +1478,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(parsed.total_count, 1);
|
assert_eq!(parsed.total_count, 1);
|
||||||
assert_eq!(parsed.items[0].group, "DEFAULT_GROUP");
|
assert_eq!(parsed.items[0].group, "DEFAULT_GROUP");
|
||||||
|
assert_eq!(parsed.items[0].app_name.as_deref(), Some("console"));
|
||||||
assert_eq!(parsed.items[0].config_type.as_deref(), Some("json"));
|
assert_eq!(parsed.items[0].config_type.as_deref(), Some("json"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ pub struct NacosConfigQuery {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub data_id: Option<String>,
|
pub data_id: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub app_name: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
pub search: Option<String>,
|
pub search: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub page_no: Option<u32>,
|
pub page_no: Option<u32>,
|
||||||
|
|||||||
Reference in new issue
Block a user