fix: real K8s replicas in list API, full Helm values in modify YAML editor
- Add Replicas field to entity.Instance - Add EnrichReplicas to InstanceService (batch K8s deployment query) - convertInstanceResponse uses instance.Replicas instead of hardcoded 0 - ModifyModal: load full Helm values from values-diff API (Current deployed) - Remove stale loadValuesDiff, use single useEffect for all data loading - Fix YAML lineWidth:0 for no line wrapping
This commit is contained in:
@ -139,6 +139,9 @@ func (h *InstanceHandler) ListInstances(w http.ResponseWriter, r *http.Request)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enrich with running replicas from K8s
|
||||||
|
instances = h.instanceService.EnrichReplicas(r.Context(), clusterID, instances)
|
||||||
|
|
||||||
responses := make([]*dto.InstanceResponse, 0, len(instances))
|
responses := make([]*dto.InstanceResponse, 0, len(instances))
|
||||||
for _, instance := range instances {
|
for _, instance := range instances {
|
||||||
responses = append(responses, convertInstanceResponse(instance, false))
|
responses = append(responses, convertInstanceResponse(instance, false))
|
||||||
@ -586,7 +589,7 @@ func convertInstanceResponse(instance *entity.Instance, includeValues bool) *dto
|
|||||||
LastOperation: string(instance.LastOperation),
|
LastOperation: string(instance.LastOperation),
|
||||||
LastError: instance.LastError,
|
LastError: instance.LastError,
|
||||||
Revision: instance.Revision,
|
Revision: instance.Revision,
|
||||||
Replicas: 0,
|
Replicas: instance.Replicas,
|
||||||
AllowedActions: []string{"view", "update", "delete"},
|
AllowedActions: []string{"view", "update", "delete"},
|
||||||
CreatedAt: instance.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
CreatedAt: instance.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
||||||
UpdatedAt: instance.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
UpdatedAt: instance.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
||||||
|
|||||||
@ -53,6 +53,7 @@ type Instance struct {
|
|||||||
Revision int // Helm Release Revision
|
Revision int // Helm Release Revision
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
|
Replicas int // Running K8s replicas (enriched, not persisted)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInstance 创建新实例
|
// NewInstance 创建新实例
|
||||||
|
|||||||
@ -473,6 +473,24 @@ func (s *InstanceService) ScaleInstance(ctx context.Context, clusterID, instance
|
|||||||
return instance, nil
|
return instance, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnrichReplicas 批量获取实例的 K8s 实际副本数并设置到 entity 上
|
||||||
|
func (s *InstanceService) EnrichReplicas(ctx context.Context, clusterID string, instances []*entity.Instance) []*entity.Instance {
|
||||||
|
if s.scaleClient == nil || len(instances) == 0 {
|
||||||
|
return instances
|
||||||
|
}
|
||||||
|
cluster, err := s.clusterRepo.GetByID(ctx, clusterID)
|
||||||
|
if err != nil {
|
||||||
|
return instances
|
||||||
|
}
|
||||||
|
for _, inst := range instances {
|
||||||
|
r, err := s.scaleClient.GetDeploymentReplicas(ctx, cluster, inst.Namespace, inst.Name)
|
||||||
|
if err == nil {
|
||||||
|
inst.Replicas = int(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instances
|
||||||
|
}
|
||||||
|
|
||||||
// GetRunningReplicas returns the actual K8s deployment replicas count.
|
// GetRunningReplicas returns the actual K8s deployment replicas count.
|
||||||
func (s *InstanceService) GetRunningReplicas(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) int {
|
func (s *InstanceService) GetRunningReplicas(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) int {
|
||||||
if s.scaleClient == nil {
|
if s.scaleClient == nil {
|
||||||
|
|||||||
@ -40,37 +40,47 @@ export const ModifyModal: React.FC<ModifyModalProps> = ({
|
|||||||
|
|
||||||
// Values Diff support
|
// Values Diff support
|
||||||
const [showDiff, setShowDiff] = useState(false);
|
const [showDiff, setShowDiff] = useState(false);
|
||||||
const [loadingDiff, setLoadingDiff] = useState(false);
|
const [loadingDiff] = useState(false);
|
||||||
const [diffData, setDiffData] = useState<{
|
const [diffData, setDiffData] = useState<{
|
||||||
current: Record<string, any>;
|
current: Record<string, any>;
|
||||||
defaults: Record<string, any>;
|
defaults: Record<string, any>;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
const [diffError, setDiffError] = useState<string | null>(null);
|
const [diffError] = useState<string | null>(null);
|
||||||
|
|
||||||
// Fetch full instance detail (list excludes values) and load diff
|
// Fetch full Helm values (via values-diff API) and instance detail
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTag(instance.version || "");
|
setTag(instance.version || "");
|
||||||
setDescription("");
|
setDescription("");
|
||||||
|
|
||||||
const loadFullInstance = async () => {
|
const loadData = async () => {
|
||||||
if (instance.clusterId && instance.id) {
|
if (instance.clusterId && instance.id) {
|
||||||
|
// Load values diff first — gives us the full current Helm values
|
||||||
try {
|
try {
|
||||||
const detail = await getInstance(
|
const data = await getInstanceValuesDiff(instance.clusterId, instance.id);
|
||||||
{ clusterId: instance.clusterId, instanceId: instance.id },
|
if (data?.current && Object.keys(data.current).length > 0) {
|
||||||
);
|
const currentYaml = stringifyYaml(data.current, { lineWidth: 0 });
|
||||||
if (detail.values && Object.keys(detail.values).length > 0) {
|
|
||||||
const currentYaml = stringifyYaml(detail.values, { lineWidth: 0 });
|
|
||||||
setValuesYaml(currentYaml);
|
setValuesYaml(currentYaml);
|
||||||
setOriginalValuesYaml(currentYaml);
|
setOriginalValuesYaml(currentYaml);
|
||||||
|
setDiffData({ current: data.current, defaults: data.defaults ?? {} });
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[ModifyModal] Failed to fetch instance detail:', err);
|
console.error('[ModifyModal] Failed to load values diff:', err);
|
||||||
|
// Fallback: try instance detail
|
||||||
|
try {
|
||||||
|
const detail = await getInstance({ clusterId: instance.clusterId, instanceId: instance.id });
|
||||||
|
if (detail.values && Object.keys(detail.values).length > 0) {
|
||||||
|
const y = stringifyYaml(detail.values, { lineWidth: 0 });
|
||||||
|
setValuesYaml(y);
|
||||||
|
setOriginalValuesYaml(y);
|
||||||
|
}
|
||||||
|
} catch (err2) {
|
||||||
|
console.error('[ModifyModal] Failed to load instance detail:', err2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadValuesDiff();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
loadFullInstance();
|
loadData();
|
||||||
}, [instance]);
|
}, [instance]);
|
||||||
|
|
||||||
// Recompute modified keys when valuesYaml or diffData changes
|
// Recompute modified keys when valuesYaml or diffData changes
|
||||||
@ -98,24 +108,6 @@ export const ModifyModal: React.FC<ModifyModalProps> = ({
|
|||||||
} catch { /* ignore parse errors */ }
|
} catch { /* ignore parse errors */ }
|
||||||
}, [valuesYaml, diffData]);
|
}, [valuesYaml, diffData]);
|
||||||
|
|
||||||
const loadValuesDiff = async () => {
|
|
||||||
if (!instance.clusterId || !instance.id) return;
|
|
||||||
|
|
||||||
setLoadingDiff(true);
|
|
||||||
setDiffError(null);
|
|
||||||
setDiffData(null);
|
|
||||||
try {
|
|
||||||
const data = await getInstanceValuesDiff(instance.clusterId, instance.id);
|
|
||||||
if (data && data.current && data.defaults) {
|
|
||||||
setDiffData({ current: data.current, defaults: data.defaults });
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error("[ModifyModal] Failed to load values diff:", err);
|
|
||||||
setDiffError("Failed to load values diff");
|
|
||||||
} finally {
|
|
||||||
setLoadingDiff(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const applyDefaults = () => {
|
const applyDefaults = () => {
|
||||||
if (!diffData?.defaults) return;
|
if (!diffData?.defaults) return;
|
||||||
@ -303,9 +295,6 @@ export const ModifyModal: React.FC<ModifyModalProps> = ({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!showDiff && !diffData) {
|
|
||||||
loadValuesDiff();
|
|
||||||
}
|
|
||||||
setShowDiff(!showDiff);
|
setShowDiff(!showDiff);
|
||||||
}}
|
}}
|
||||||
className="flex items-center gap-2 text-sm font-medium text-indigo-600 hover:text-indigo-700 transition-colors"
|
className="flex items-center gap-2 text-sm font-medium text-indigo-600 hover:text-indigo-700 transition-colors"
|
||||||
|
|||||||
Reference in New Issue
Block a user