mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-14 00:48:26 +08:00
Go:cli move _order _columns sort group (#16615)
### Summary 1. Move common functions to format.go 2. modify show name spaces to _ 3. move _order _columns column sort group; 4. add dao empty enterprise file
This commit is contained in:
@@ -128,18 +128,11 @@ func (r *CommonDataResponse) SetOutputFormat(format OutputFormat) {
|
||||
|
||||
func (r *CommonDataResponse) orderedMetricTable() []map[string]interface{} {
|
||||
table := make([]map[string]interface{}, 0)
|
||||
if orderRaw, ok := r.Data["_order"]; ok {
|
||||
if orderSlice, ok := orderRaw.([]interface{}); ok {
|
||||
for _, keyRaw := range orderSlice {
|
||||
key := fmt.Sprintf("%v", keyRaw)
|
||||
if value, exists := r.Data[key]; exists {
|
||||
table = append(table, map[string]interface{}{
|
||||
"Metric": key,
|
||||
"Value": value,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
for key, value := range r.Data {
|
||||
table = append(table, map[string]interface{}{
|
||||
"Metric": key,
|
||||
"Value": value,
|
||||
})
|
||||
}
|
||||
return table
|
||||
}
|
||||
@@ -1015,22 +1008,13 @@ func (r *UserIndexResponse) PrintOut() {
|
||||
}
|
||||
|
||||
summaryTable := r.orderedMetricTable()
|
||||
indexColumns := []string{"index", "health", "status", "docs.count", "dataset.size", "store.size"}
|
||||
indexTable := make([]map[string]interface{}, 0)
|
||||
indicesRaw, hasIndices := r.Data["indices"]
|
||||
if hasIndices {
|
||||
if indices, ok := indicesRaw.([]interface{}); ok {
|
||||
for _, idx := range indices {
|
||||
if m, ok := idx.(map[string]interface{}); ok {
|
||||
orderedRow := make(map[string]interface{})
|
||||
for _, col := range indexColumns {
|
||||
if v, exists := m[col]; exists {
|
||||
orderedRow[col] = v
|
||||
} else {
|
||||
orderedRow[col] = ""
|
||||
}
|
||||
}
|
||||
indexTable = append(indexTable, orderedRow)
|
||||
indexTable = append(indexTable, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1060,7 +1044,7 @@ func (r *UserIndexResponse) PrintOut() {
|
||||
if len(indexTable) > 0 {
|
||||
fmt.Println()
|
||||
fmt.Println("Index Details:")
|
||||
PrintTableSimpleByFormatWithOrder(indexTable, indexColumns, r.OutputFormat)
|
||||
PrintTableSimpleByFormat(indexTable, r.OutputFormat)
|
||||
} else if hasIndices {
|
||||
fmt.Println()
|
||||
fmt.Println("No indices found for this user.")
|
||||
@@ -1083,22 +1067,13 @@ func (r *UserStorageResponse) PrintOut() {
|
||||
}
|
||||
|
||||
summaryTable := r.orderedMetricTable()
|
||||
fileColumns := []string{"name", "size"}
|
||||
fileTable := make([]map[string]interface{}, 0)
|
||||
filesRaw, hasFiles := r.Data["files"]
|
||||
if hasFiles {
|
||||
if files, ok := filesRaw.([]interface{}); ok {
|
||||
for _, f := range files {
|
||||
if m, ok := f.(map[string]interface{}); ok {
|
||||
orderedRow := make(map[string]interface{})
|
||||
for _, col := range fileColumns {
|
||||
if v, exists := m[col]; exists {
|
||||
orderedRow[col] = v
|
||||
} else {
|
||||
orderedRow[col] = ""
|
||||
}
|
||||
}
|
||||
fileTable = append(fileTable, orderedRow)
|
||||
fileTable = append(fileTable, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1128,7 +1103,7 @@ func (r *UserStorageResponse) PrintOut() {
|
||||
if len(fileTable) > 0 {
|
||||
fmt.Println()
|
||||
fmt.Println("Files(Top 10):")
|
||||
PrintTableSimpleByFormatWithOrder(fileTable, fileColumns, r.OutputFormat)
|
||||
PrintTableSimpleByFormat(fileTable, r.OutputFormat)
|
||||
} else if hasFiles {
|
||||
fmt.Println()
|
||||
fmt.Println("No files found for this user.")
|
||||
@@ -1170,7 +1145,7 @@ func (r *UserQuotaResponse) PrintOut() {
|
||||
}
|
||||
}
|
||||
if len(summaryTable) > 0 {
|
||||
PrintTableSimpleByFormatWithOrder(summaryTable, []string{"Metric", "Used", "Limit"}, r.OutputFormat)
|
||||
PrintTableSimpleByFormat(summaryTable, r.OutputFormat)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1180,11 +1155,7 @@ type OrderedCommonResponse struct {
|
||||
|
||||
func (r *OrderedCommonResponse) PrintOut() {
|
||||
if r.Code == 0 {
|
||||
if colNames, cleanData, ok := ExtractColumnsAndCleanData(r.Data); ok {
|
||||
PrintTableSimpleByFormatWithOrder(cleanData, colNames, r.OutputFormat)
|
||||
} else {
|
||||
PrintTableSimpleByFormat(r.Data, r.OutputFormat)
|
||||
}
|
||||
PrintTableSimpleByFormat(r.Data, r.OutputFormat)
|
||||
} else {
|
||||
fmt.Println("ERROR")
|
||||
fmt.Printf("%d, %s\n", r.Code, r.Message)
|
||||
@@ -1197,17 +1168,8 @@ type OrderedCommonDataResponse struct {
|
||||
|
||||
func (r *OrderedCommonDataResponse) PrintOut() {
|
||||
if r.Code == 0 {
|
||||
if table := r.orderedMetricTable(); len(table) > 0 {
|
||||
PrintTableSimpleByFormat(table, r.OutputFormat)
|
||||
} else {
|
||||
table := make([]map[string]interface{}, 0)
|
||||
for key, value := range r.Data {
|
||||
elem := map[string]interface{}{
|
||||
"field": key,
|
||||
"value": value,
|
||||
}
|
||||
table = append(table, elem)
|
||||
}
|
||||
table := r.orderedMetricTable()
|
||||
if len(table) > 0 {
|
||||
PrintTableSimpleByFormat(table, r.OutputFormat)
|
||||
}
|
||||
} else {
|
||||
@@ -1239,23 +1201,14 @@ func (r *QuotaSummaryResponse) PrintOut() {
|
||||
return
|
||||
}
|
||||
|
||||
sections := []struct {
|
||||
key string
|
||||
title string
|
||||
columns []string
|
||||
}{
|
||||
{"storage", "Storage", []string{"Plan", "Users", "Avg Used", "Limit", "Avg Usage"}},
|
||||
{"apps", "Apps", []string{"Plan", "Avg Used", "Limit", "Avg Usage"}},
|
||||
{"api", "API Requests", []string{"Plan", "Tokens", "Limit/min"}},
|
||||
}
|
||||
sections := []string{"storage", "apps", "api"}
|
||||
|
||||
for i, section := range sections {
|
||||
for i, key := range sections {
|
||||
if i > 0 {
|
||||
fmt.Println()
|
||||
}
|
||||
fmt.Printf("--- %s ---\n", section.title)
|
||||
|
||||
rowsRaw, ok := r.Data[section.key]
|
||||
rowsRaw, ok := r.Data[key]
|
||||
if !ok {
|
||||
fmt.Println("No data")
|
||||
continue
|
||||
@@ -1270,19 +1223,11 @@ func (r *QuotaSummaryResponse) PrintOut() {
|
||||
table := make([]map[string]interface{}, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
if m, ok := row.(map[string]interface{}); ok {
|
||||
orderedRow := make(map[string]interface{})
|
||||
for _, col := range section.columns {
|
||||
if v, exists := m[col]; exists {
|
||||
orderedRow[col] = v
|
||||
} else {
|
||||
orderedRow[col] = ""
|
||||
}
|
||||
}
|
||||
table = append(table, orderedRow)
|
||||
table = append(table, m)
|
||||
}
|
||||
}
|
||||
|
||||
PrintTableSimpleByFormatWithOrder(table, section.columns, r.OutputFormat)
|
||||
PrintTableSimpleByFormat(table, r.OutputFormat)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -197,118 +197,6 @@ func PrintTableSimpleByFormat(data []map[string]interface{}, format OutputFormat
|
||||
}
|
||||
}
|
||||
|
||||
// PrintTableSimpleByFormatWithOrder prints data with columns in the specified order
|
||||
func PrintTableSimpleByFormatWithOrder(data []map[string]interface{}, columns []string, format OutputFormat) {
|
||||
if len(data) == 0 {
|
||||
if format == OutputFormatJSON {
|
||||
fmt.Println("[]")
|
||||
} else if format == OutputFormatPlain {
|
||||
fmt.Println("(empty)")
|
||||
} else {
|
||||
fmt.Println("No data to print")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if format == OutputFormatJSON {
|
||||
jsonData, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
fmt.Printf("Error marshaling JSON: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(jsonData))
|
||||
return
|
||||
}
|
||||
|
||||
colIsNumeric := make(map[string]bool)
|
||||
for _, col := range columns {
|
||||
isNumeric := true
|
||||
for _, item := range data {
|
||||
if val, ok := item[col]; ok {
|
||||
if !isNumericValue(val) {
|
||||
isNumeric = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
colIsNumeric[col] = isNumeric
|
||||
}
|
||||
|
||||
colWidths := make(map[string]int)
|
||||
for _, col := range columns {
|
||||
maxWidth := getStringWidth(strings.ToLower(col))
|
||||
for _, item := range data {
|
||||
value := formatValue(item[col])
|
||||
valueWidth := getStringWidth(value)
|
||||
if valueWidth > maxWidth {
|
||||
maxWidth = valueWidth
|
||||
}
|
||||
}
|
||||
if maxWidth > maxColWidth {
|
||||
maxWidth = maxColWidth
|
||||
}
|
||||
if maxWidth < 2 {
|
||||
maxWidth = 2
|
||||
}
|
||||
colWidths[col] = maxWidth
|
||||
}
|
||||
|
||||
if format == OutputFormatPlain {
|
||||
headerParts := make([]string, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
headerParts = append(headerParts, padCell(strings.ToLower(col), colWidths[col], colIsNumeric[col]))
|
||||
}
|
||||
fmt.Println(strings.Join(headerParts, " "))
|
||||
|
||||
for _, item := range data {
|
||||
rowParts := make([]string, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
value := formatValue(item[col])
|
||||
valueWidth := getStringWidth(value)
|
||||
if valueWidth > colWidths[col] {
|
||||
runes := []rune(value)
|
||||
value = truncateStringByWidth(runes, colWidths[col])
|
||||
valueWidth = getStringWidth(value)
|
||||
}
|
||||
rowParts = append(rowParts, padCell(value, colWidths[col], colIsNumeric[col]))
|
||||
}
|
||||
fmt.Println(strings.Join(rowParts, " "))
|
||||
}
|
||||
} else {
|
||||
separatorParts := make([]string, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
separatorParts = append(separatorParts, strings.Repeat("-", colWidths[col]+2))
|
||||
}
|
||||
separator := "+" + strings.Join(separatorParts, "+") + "+"
|
||||
|
||||
fmt.Println(separator)
|
||||
headerParts := make([]string, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
headerParts = append(headerParts, fmt.Sprintf(" %-*s ", colWidths[col], col))
|
||||
}
|
||||
fmt.Println("|" + strings.Join(headerParts, "|") + "|")
|
||||
fmt.Println(separator)
|
||||
|
||||
for _, item := range data {
|
||||
rowParts := make([]string, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
value := formatValue(item[col])
|
||||
valueWidth := getStringWidth(value)
|
||||
if valueWidth > colWidths[col] {
|
||||
runes := []rune(value)
|
||||
value = truncateStringByWidth(runes, colWidths[col])
|
||||
valueWidth = getStringWidth(value)
|
||||
}
|
||||
rowParts = append(rowParts, fmt.Sprintf(" %s ", padCell(value, colWidths[col], false)))
|
||||
|
||||
}
|
||||
fmt.Println("|" + strings.Join(rowParts, "|") + "|")
|
||||
}
|
||||
|
||||
fmt.Println(separator)
|
||||
}
|
||||
}
|
||||
|
||||
// formatValue formats a value for display
|
||||
func formatValue(v interface{}) string {
|
||||
if v == nil {
|
||||
@@ -404,32 +292,3 @@ func isHalfWidth(r rune) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ExtractColumnsAndCleanData(data []map[string]interface{}) ([]string, []map[string]interface{}, bool) {
|
||||
if len(data) == 0 {
|
||||
return nil, nil, false
|
||||
}
|
||||
columnsRaw, ok := data[0]["_columns"]
|
||||
if !ok {
|
||||
return nil, nil, false
|
||||
}
|
||||
columns, ok := columnsRaw.([]interface{})
|
||||
if !ok {
|
||||
return nil, nil, false
|
||||
}
|
||||
colNames := make([]string, 0, len(columns))
|
||||
for _, c := range columns {
|
||||
colNames = append(colNames, fmt.Sprintf("%v", c))
|
||||
}
|
||||
cleanData := make([]map[string]interface{}, 0, len(data))
|
||||
for _, row := range data {
|
||||
cleanRow := make(map[string]interface{}, len(row))
|
||||
for k, v := range row {
|
||||
if k != "_columns" {
|
||||
cleanRow[k] = v
|
||||
}
|
||||
}
|
||||
cleanData = append(cleanData, cleanRow)
|
||||
}
|
||||
return colNames, cleanData, true
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PtrString formats a pointer value as a string for debug/log output.
|
||||
@@ -86,6 +88,79 @@ func DecodeFromBase64(encoded string) (string, error) {
|
||||
return string(decoded), nil
|
||||
}
|
||||
|
||||
func FormatBytes(bytes int64) string {
|
||||
const (
|
||||
KB = 1024
|
||||
MB = KB * 1024
|
||||
GB = MB * 1024
|
||||
TB = GB * 1024
|
||||
)
|
||||
switch {
|
||||
case bytes >= TB:
|
||||
return fmt.Sprintf("%.1f TB", float64(bytes)/float64(TB))
|
||||
case bytes >= GB:
|
||||
return fmt.Sprintf("%.1f GB", float64(bytes)/float64(GB))
|
||||
case bytes >= MB:
|
||||
return fmt.Sprintf("%.1f MB", float64(bytes)/float64(MB))
|
||||
case bytes >= KB:
|
||||
return fmt.Sprintf("%.1f KB", float64(bytes)/float64(KB))
|
||||
default:
|
||||
return fmt.Sprintf("%d B", bytes)
|
||||
}
|
||||
}
|
||||
|
||||
func FormatNumber(n int64) string {
|
||||
s := fmt.Sprintf("%d", n)
|
||||
parts := []string{}
|
||||
for i := len(s); i > 0; i -= 3 {
|
||||
start := i - 3
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
parts = append([]string{s[start:i]}, parts...)
|
||||
}
|
||||
return strings.Join(parts, ",")
|
||||
}
|
||||
|
||||
func ParseBytesString(s string) int64 {
|
||||
s = strings.TrimSpace(strings.ToLower(s))
|
||||
if s == "" || s == "-" || s == "0" {
|
||||
return 0
|
||||
}
|
||||
|
||||
var multiplier int64 = 1
|
||||
switch {
|
||||
case strings.HasSuffix(s, "tb"):
|
||||
multiplier = 1024 * 1024 * 1024 * 1024
|
||||
s = strings.TrimSuffix(s, "tb")
|
||||
case strings.HasSuffix(s, "gb"):
|
||||
multiplier = 1024 * 1024 * 1024
|
||||
s = strings.TrimSuffix(s, "gb")
|
||||
case strings.HasSuffix(s, "mb"):
|
||||
multiplier = 1024 * 1024
|
||||
s = strings.TrimSuffix(s, "mb")
|
||||
case strings.HasSuffix(s, "kb"):
|
||||
multiplier = 1024
|
||||
s = strings.TrimSuffix(s, "kb")
|
||||
case strings.HasSuffix(s, "b"):
|
||||
s = strings.TrimSuffix(s, "b")
|
||||
}
|
||||
|
||||
s = strings.TrimSpace(s)
|
||||
val, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return int64(val * float64(multiplier))
|
||||
}
|
||||
|
||||
func FormatTime(t *int64) string {
|
||||
if t == nil {
|
||||
return "N/A"
|
||||
}
|
||||
return time.UnixMilli(*t).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func IsValidString(v interface{}) bool {
|
||||
str, ok := v.(string)
|
||||
return ok && str != ""
|
||||
|
||||
17
internal/dao/enterprise_data.go
Normal file
17
internal/dao/enterprise_data.go
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package dao
|
||||
17
internal/dao/enterprise_tasks.go
Normal file
17
internal/dao/enterprise_tasks.go
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package dao
|
||||
17
internal/dao/enterprise_user.go
Normal file
17
internal/dao/enterprise_user.go
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package dao
|
||||
Reference in New Issue
Block a user