feat: sync httpdns sdk/platform updates without large binaries
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "1.4.8" //1.3.8.2
|
||||
Version = "1.4.9" //1.3.8.2
|
||||
|
||||
ProductName = "Edge User"
|
||||
ProcessName = "edge-user"
|
||||
|
||||
@@ -28,19 +28,20 @@ func (this *SdkCheckAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
version := strings.TrimSpace(params.Version)
|
||||
t := strings.ToLower(strings.TrimSpace(params.Type))
|
||||
if t == "doc" {
|
||||
docPath := findUploadedSDKDocPath(platform, params.Version)
|
||||
docPath := findUploadedSDKDocPath(platform, version)
|
||||
if len(docPath) == 0 {
|
||||
this.Data["exists"] = false
|
||||
this.Data["message"] = "Documentation is unavailable, please contact admin"
|
||||
this.Data["message"] = "当前平台/版本尚未上传集成文档"
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
downloadURL := "/httpdns/apps/sdk/doc?platform=" + url.QueryEscape(platform)
|
||||
if len(strings.TrimSpace(params.Version)) > 0 {
|
||||
downloadURL += "&version=" + url.QueryEscape(strings.TrimSpace(params.Version))
|
||||
if len(version) > 0 {
|
||||
downloadURL += "&version=" + url.QueryEscape(version)
|
||||
}
|
||||
this.Data["exists"] = true
|
||||
this.Data["url"] = downloadURL
|
||||
@@ -48,17 +49,17 @@ func (this *SdkCheckAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
archivePath := findSDKArchivePath(filename, params.Version)
|
||||
archivePath := findSDKArchivePath(filename, version)
|
||||
if len(archivePath) == 0 {
|
||||
this.Data["exists"] = false
|
||||
this.Data["message"] = "SDK package is unavailable, please contact admin"
|
||||
this.Data["message"] = "当前平台/版本尚未上传 SDK 安装包"
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
downloadURL := "/httpdns/apps/sdk/download?platform=" + url.QueryEscape(platform)
|
||||
if len(strings.TrimSpace(params.Version)) > 0 {
|
||||
downloadURL += "&version=" + url.QueryEscape(strings.TrimSpace(params.Version))
|
||||
if len(version) > 0 {
|
||||
downloadURL += "&version=" + url.QueryEscape(version)
|
||||
}
|
||||
downloadURL += "&raw=1"
|
||||
this.Data["exists"] = true
|
||||
|
||||
@@ -3,7 +3,6 @@ package apps
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/TeaOSLab/EdgeUser/internal/web/actions/actionutils"
|
||||
)
|
||||
@@ -20,7 +19,7 @@ func (this *SdkDocAction) RunGet(params struct {
|
||||
Platform string
|
||||
Version string
|
||||
}) {
|
||||
platform, _, readmeRelativePath, _, err := resolveSDKPlatform(params.Platform)
|
||||
platform, _, _, _, err := resolveSDKPlatform(params.Platform)
|
||||
if err != nil {
|
||||
this.Data["exists"] = false
|
||||
this.Data["message"] = err.Error()
|
||||
@@ -28,35 +27,25 @@ func (this *SdkDocAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
var data []byte
|
||||
uploadedDocPath := findUploadedSDKDocPath(platform, params.Version)
|
||||
if len(uploadedDocPath) > 0 {
|
||||
data, err = os.ReadFile(uploadedDocPath)
|
||||
}
|
||||
|
||||
sdkRoot, sdkRootErr := findSDKRoot()
|
||||
if len(data) == 0 && sdkRootErr == nil {
|
||||
readmePath := filepath.Join(sdkRoot, readmeRelativePath)
|
||||
data, err = os.ReadFile(readmePath)
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
localDocPath := findLocalSDKDocPath(platform)
|
||||
if len(localDocPath) > 0 {
|
||||
data, err = os.ReadFile(localDocPath)
|
||||
}
|
||||
}
|
||||
|
||||
if len(data) == 0 || err != nil {
|
||||
docPath := findUploadedSDKDocPath(platform, params.Version)
|
||||
if len(docPath) == 0 {
|
||||
this.Data["exists"] = false
|
||||
this.Data["message"] = "SDK documentation is unavailable for current platform, please contact admin"
|
||||
this.Data["message"] = "当前平台/版本尚未上传集成文档"
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
downloadName := filepath.Base(uploadedDocPath)
|
||||
data, err := os.ReadFile(docPath)
|
||||
if err != nil || len(data) == 0 {
|
||||
this.Data["exists"] = false
|
||||
this.Data["message"] = "读取集成文档失败"
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
downloadName := filepath.Base(docPath)
|
||||
if len(downloadName) == 0 || downloadName == "." || downloadName == string(filepath.Separator) {
|
||||
downloadName = "httpdns-sdk-" + strings.ToLower(platform) + ".md"
|
||||
downloadName = "sdk-doc.md"
|
||||
}
|
||||
|
||||
this.AddHeader("Content-Type", "text/markdown; charset=utf-8")
|
||||
|
||||
@@ -32,7 +32,7 @@ func (this *SdkDownloadAction) RunGet(params struct {
|
||||
archivePath := findSDKArchivePath(filename, params.Version)
|
||||
if len(archivePath) == 0 {
|
||||
this.Data["exists"] = false
|
||||
this.Data["message"] = "SDK archive is unavailable for current platform, please contact admin: " + filename
|
||||
this.Data["message"] = "当前平台/版本尚未上传 SDK 安装包"
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
@@ -40,7 +40,7 @@ func (this *SdkDownloadAction) RunGet(params struct {
|
||||
fp, err := os.Open(archivePath)
|
||||
if err != nil {
|
||||
this.Data["exists"] = false
|
||||
this.Data["message"] = "failed to open SDK archive: " + err.Error()
|
||||
this.Data["message"] = "打开 SDK 安装包失败: " + err.Error()
|
||||
this.Success()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,16 +1,183 @@
|
||||
package apps
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
)
|
||||
|
||||
type sdkUploadMeta struct {
|
||||
Platform string `json:"platform"`
|
||||
Version string `json:"version"`
|
||||
FileType string `json:"fileType"` // sdk | doc
|
||||
Filename string `json:"filename"`
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type sdkUploadMetaRecord struct {
|
||||
Meta sdkUploadMeta
|
||||
Dir string
|
||||
FilePath string
|
||||
}
|
||||
|
||||
func sdkUploadMetaFilename(platform string, version string, fileType string) string {
|
||||
platform = strings.ToLower(strings.TrimSpace(platform))
|
||||
version = strings.TrimSpace(version)
|
||||
fileType = strings.ToLower(strings.TrimSpace(fileType))
|
||||
return ".httpdns-sdk-meta-" + platform + "-v" + version + "-" + fileType + ".json"
|
||||
}
|
||||
|
||||
func isSDKUploadMetaFile(name string) bool {
|
||||
name = strings.ToLower(strings.TrimSpace(name))
|
||||
return strings.HasPrefix(name, ".httpdns-sdk-meta-") && strings.HasSuffix(name, ".json")
|
||||
}
|
||||
|
||||
func parseSDKPlatformFromDownloadFilename(downloadFilename string) string {
|
||||
name := strings.ToLower(strings.TrimSpace(downloadFilename))
|
||||
if !strings.HasPrefix(name, "httpdns-sdk-") || !strings.HasSuffix(name, ".zip") {
|
||||
return ""
|
||||
}
|
||||
|
||||
platform := strings.TrimSuffix(strings.TrimPrefix(name, "httpdns-sdk-"), ".zip")
|
||||
switch platform {
|
||||
case "android", "ios", "flutter":
|
||||
return platform
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func listSDKUploadMetaRecords() []sdkUploadMetaRecord {
|
||||
type wrapped struct {
|
||||
record sdkUploadMetaRecord
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
byKey := map[string]wrapped{}
|
||||
for _, dir := range sdkUploadSearchDirs() {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
name := entry.Name()
|
||||
if !isSDKUploadMetaFile(name) {
|
||||
continue
|
||||
}
|
||||
|
||||
metaPath := filepath.Join(dir, name)
|
||||
data, err := os.ReadFile(metaPath)
|
||||
if err != nil || len(data) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var meta sdkUploadMeta
|
||||
if err = json.Unmarshal(data, &meta); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
meta.Platform = strings.ToLower(strings.TrimSpace(meta.Platform))
|
||||
meta.Version = strings.TrimSpace(meta.Version)
|
||||
meta.FileType = strings.ToLower(strings.TrimSpace(meta.FileType))
|
||||
meta.Filename = filepath.Base(strings.TrimSpace(meta.Filename))
|
||||
if len(meta.Platform) == 0 || len(meta.Version) == 0 || len(meta.Filename) == 0 {
|
||||
continue
|
||||
}
|
||||
if meta.FileType != "sdk" && meta.FileType != "doc" {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(meta.Filename, "..") || strings.Contains(meta.Filename, "/") || strings.Contains(meta.Filename, "\\") {
|
||||
continue
|
||||
}
|
||||
|
||||
filePath := filepath.Join(dir, meta.Filename)
|
||||
fileStat, err := os.Stat(filePath)
|
||||
if err != nil || fileStat.IsDir() || fileStat.Size() <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
metaStat, err := os.Stat(metaPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if meta.UpdatedAt <= 0 {
|
||||
meta.UpdatedAt = metaStat.ModTime().Unix()
|
||||
}
|
||||
|
||||
key := meta.Platform + "|" + meta.Version + "|" + meta.FileType
|
||||
current := wrapped{
|
||||
record: sdkUploadMetaRecord{
|
||||
Meta: meta,
|
||||
Dir: dir,
|
||||
FilePath: filePath,
|
||||
},
|
||||
modTime: metaStat.ModTime(),
|
||||
}
|
||||
old, ok := byKey[key]
|
||||
if !ok ||
|
||||
current.record.Meta.UpdatedAt > old.record.Meta.UpdatedAt ||
|
||||
(current.record.Meta.UpdatedAt == old.record.Meta.UpdatedAt && current.modTime.After(old.modTime)) ||
|
||||
(current.record.Meta.UpdatedAt == old.record.Meta.UpdatedAt && current.modTime.Equal(old.modTime) && current.record.FilePath > old.record.FilePath) {
|
||||
byKey[key] = current
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result := make([]sdkUploadMetaRecord, 0, len(byKey))
|
||||
for _, item := range byKey {
|
||||
result = append(result, item.record)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func findSDKUploadFileByMeta(platform string, version string, fileType string) string {
|
||||
platform = strings.ToLower(strings.TrimSpace(platform))
|
||||
version = strings.TrimSpace(version)
|
||||
fileType = strings.ToLower(strings.TrimSpace(fileType))
|
||||
if len(platform) == 0 || len(version) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, record := range listSDKUploadMetaRecords() {
|
||||
if record.Meta.Platform == platform && record.Meta.Version == version && record.Meta.FileType == fileType {
|
||||
return record.FilePath
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func findNewestSDKUploadFileByMeta(platform string, fileType string) string {
|
||||
platform = strings.ToLower(strings.TrimSpace(platform))
|
||||
fileType = strings.ToLower(strings.TrimSpace(fileType))
|
||||
if len(platform) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var foundPath string
|
||||
var foundUpdatedAt int64
|
||||
for _, record := range listSDKUploadMetaRecords() {
|
||||
if record.Meta.Platform != platform || record.Meta.FileType != fileType {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(foundPath) == 0 || record.Meta.UpdatedAt > foundUpdatedAt || (record.Meta.UpdatedAt == foundUpdatedAt && record.FilePath > foundPath) {
|
||||
foundPath = record.FilePath
|
||||
foundUpdatedAt = record.Meta.UpdatedAt
|
||||
}
|
||||
}
|
||||
return foundPath
|
||||
}
|
||||
|
||||
func sdkUploadDir() string {
|
||||
dirs := sdkUploadDirs()
|
||||
if len(dirs) > 0 {
|
||||
@@ -27,6 +194,7 @@ func sdkUploadDirs() []string {
|
||||
filepath.Clean(Tea.Root + "/../edge-user/data/httpdns/sdk"),
|
||||
filepath.Clean(Tea.Root + "/../../data/httpdns/sdk"),
|
||||
}
|
||||
|
||||
results := make([]string, 0, len(candidates))
|
||||
seen := map[string]bool{}
|
||||
for _, dir := range candidates {
|
||||
@@ -54,67 +222,6 @@ func sdkUploadSearchDirs() []string {
|
||||
return results
|
||||
}
|
||||
|
||||
func findFirstExistingDir(paths []string) string {
|
||||
for _, path := range paths {
|
||||
stat, err := os.Stat(path)
|
||||
if err == nil && stat.IsDir() {
|
||||
return path
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func findFirstExistingFile(paths []string) string {
|
||||
for _, path := range paths {
|
||||
stat, err := os.Stat(path)
|
||||
if err == nil && !stat.IsDir() && stat.Size() > 0 {
|
||||
return path
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func findNewestExistingFile(paths []string) string {
|
||||
type fileInfo struct {
|
||||
path string
|
||||
modTime time.Time
|
||||
}
|
||||
result := fileInfo{}
|
||||
for _, path := range paths {
|
||||
stat, err := os.Stat(path)
|
||||
if err != nil || stat.IsDir() {
|
||||
continue
|
||||
}
|
||||
if stat.Size() <= 0 {
|
||||
continue
|
||||
}
|
||||
if len(result.path) == 0 || stat.ModTime().After(result.modTime) || (stat.ModTime().Equal(result.modTime) && path > result.path) {
|
||||
result.path = path
|
||||
result.modTime = stat.ModTime()
|
||||
}
|
||||
}
|
||||
return result.path
|
||||
}
|
||||
|
||||
func findSDKRoot() (string, error) {
|
||||
candidates := []string{
|
||||
filepath.Clean(Tea.Root + "/EdgeHttpDNS/sdk"),
|
||||
filepath.Clean(Tea.Root + "/edge-httpdns/sdk"),
|
||||
filepath.Clean(Tea.Root + "/edge-httpdns/edge-httpdns/sdk"),
|
||||
filepath.Clean(Tea.Root + "/../EdgeHttpDNS/sdk"),
|
||||
filepath.Clean(Tea.Root + "/../../EdgeHttpDNS/sdk"),
|
||||
filepath.Clean(Tea.Root + "/../edge-httpdns/sdk"),
|
||||
filepath.Clean(Tea.Root + "/../../edge-httpdns/sdk"),
|
||||
}
|
||||
|
||||
dir := findFirstExistingDir(candidates)
|
||||
if len(dir) > 0 {
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
return "", errors.New("SDK files are not found on current server")
|
||||
}
|
||||
|
||||
func resolveSDKPlatform(platform string) (key string, relativeDir string, readmeRelativePath string, downloadFilename string, err error) {
|
||||
switch strings.ToLower(strings.TrimSpace(platform)) {
|
||||
case "android":
|
||||
@@ -122,52 +229,23 @@ func resolveSDKPlatform(platform string) (key string, relativeDir string, readme
|
||||
case "ios":
|
||||
return "ios", "ios", "ios/README.md", "httpdns-sdk-ios.zip", nil
|
||||
case "flutter":
|
||||
return "flutter", "flutter/aliyun_httpdns", "flutter/aliyun_httpdns/README.md", "httpdns-sdk-flutter.zip", nil
|
||||
return "flutter", "flutter/new_httpdns", "flutter/new_httpdns/README.md", "httpdns-sdk-flutter.zip", nil
|
||||
default:
|
||||
return "", "", "", "", errors.New("invalid platform, expected one of: android, ios, flutter")
|
||||
return "", "", "", "", errors.New("不支持的平台,可选值:android、ios、flutter")
|
||||
}
|
||||
}
|
||||
|
||||
func findSDKArchivePath(downloadFilename string, version string) string {
|
||||
searchDirs := sdkUploadSearchDirs()
|
||||
|
||||
normalizedVersion := strings.TrimSpace(version)
|
||||
base := strings.TrimSuffix(downloadFilename, ".zip")
|
||||
if len(normalizedVersion) > 0 {
|
||||
versionFiles := []string{}
|
||||
for _, dir := range searchDirs {
|
||||
versionFiles = append(versionFiles, filepath.Join(dir, base+"-v"+normalizedVersion+".zip"))
|
||||
}
|
||||
if path := findFirstExistingFile(versionFiles); len(path) > 0 {
|
||||
return path
|
||||
}
|
||||
platform := parseSDKPlatformFromDownloadFilename(downloadFilename)
|
||||
if len(platform) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
patternName := base + "-v*.zip"
|
||||
matches := []string{}
|
||||
for _, dir := range searchDirs {
|
||||
found, _ := filepath.Glob(filepath.Join(dir, patternName))
|
||||
for _, file := range found {
|
||||
stat, err := os.Stat(file)
|
||||
if err == nil && !stat.IsDir() {
|
||||
matches = append(matches, file)
|
||||
}
|
||||
}
|
||||
normalizedVersion := strings.TrimSpace(version)
|
||||
if len(normalizedVersion) > 0 {
|
||||
return findSDKUploadFileByMeta(platform, normalizedVersion, "sdk")
|
||||
}
|
||||
if len(matches) > 0 {
|
||||
return findNewestExistingFile(matches)
|
||||
}
|
||||
|
||||
exactFiles := []string{}
|
||||
for _, dir := range searchDirs {
|
||||
exactFiles = append(exactFiles, filepath.Join(dir, downloadFilename))
|
||||
}
|
||||
if path := findFirstExistingFile(exactFiles); len(path) > 0 {
|
||||
return path
|
||||
}
|
||||
|
||||
return ""
|
||||
return findNewestSDKUploadFileByMeta(platform, "sdk")
|
||||
}
|
||||
|
||||
func findUploadedSDKDocPath(platform string, version string) string {
|
||||
@@ -176,43 +254,9 @@ func findUploadedSDKDocPath(platform string, version string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
searchDirs := sdkUploadSearchDirs()
|
||||
normalizedVersion := strings.TrimSpace(version)
|
||||
if len(normalizedVersion) > 0 {
|
||||
exactVersion := []string{}
|
||||
for _, dir := range searchDirs {
|
||||
exactVersion = append(exactVersion, filepath.Join(dir, "httpdns-sdk-"+platform+"-v"+normalizedVersion+".md"))
|
||||
}
|
||||
if file := findFirstExistingFile(exactVersion); len(file) > 0 {
|
||||
return file
|
||||
}
|
||||
return ""
|
||||
return findSDKUploadFileByMeta(platform, normalizedVersion, "doc")
|
||||
}
|
||||
|
||||
matches := []string{}
|
||||
for _, dir := range searchDirs {
|
||||
pattern := filepath.Join(dir, "httpdns-sdk-"+platform+"-v*.md")
|
||||
found, _ := filepath.Glob(pattern)
|
||||
matches = append(matches, found...)
|
||||
}
|
||||
if len(matches) > 0 {
|
||||
sort.Strings(matches)
|
||||
return findNewestExistingFile(matches)
|
||||
}
|
||||
|
||||
exact := []string{}
|
||||
for _, dir := range searchDirs {
|
||||
exact = append(exact, filepath.Join(dir, "httpdns-sdk-"+platform+".md"))
|
||||
}
|
||||
return findFirstExistingFile(exact)
|
||||
}
|
||||
|
||||
func findLocalSDKDocPath(platform string) string {
|
||||
filename := strings.ToLower(strings.TrimSpace(platform)) + ".md"
|
||||
candidates := []string{
|
||||
filepath.Clean(Tea.Root + "/edge-admin/web/views/@default/httpdns/apps/docs/" + filename),
|
||||
filepath.Clean(Tea.Root + "/EdgeUser/web/views/@default/httpdns/apps/docs/" + filename),
|
||||
filepath.Clean(Tea.Root + "/EdgeAdmin/web/views/@default/httpdns/apps/docs/" + filename),
|
||||
}
|
||||
return findFirstExistingFile(candidates)
|
||||
return findNewestSDKUploadFileByMeta(platform, "doc")
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,57 +3,72 @@
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
a.disabled,
|
||||
a.disabled:hover,
|
||||
a.disabled:active,
|
||||
span.disabled {
|
||||
color: #ccc !important;
|
||||
}
|
||||
|
||||
a.enabled,
|
||||
span.enabled,
|
||||
span.green {
|
||||
color: #21ba45;
|
||||
}
|
||||
|
||||
span.grey,
|
||||
label.grey,
|
||||
p.grey {
|
||||
color: grey !important;
|
||||
}
|
||||
|
||||
p.grey {
|
||||
margin-top: 0.8em;
|
||||
}
|
||||
|
||||
span.red,
|
||||
pre.red {
|
||||
color: #db2828;
|
||||
}
|
||||
|
||||
pre:not(.CodeMirror-line) {
|
||||
font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
|
||||
}
|
||||
|
||||
tbody {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.table.width30 {
|
||||
width: 30em !important;
|
||||
}
|
||||
|
||||
.table.width35 {
|
||||
width: 35em !important;
|
||||
}
|
||||
|
||||
.table.width40 {
|
||||
width: 40em !important;
|
||||
}
|
||||
|
||||
.table th,
|
||||
.table td {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
p.comment,
|
||||
div.comment {
|
||||
color: #959da6;
|
||||
@@ -62,37 +77,46 @@ div.comment {
|
||||
word-break: break-all;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
p.comment em,
|
||||
div.comment em {
|
||||
font-style: italic !important;
|
||||
}
|
||||
|
||||
.truncate {
|
||||
white-space: nowrap;
|
||||
-ms-text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
div.margin,
|
||||
p.margin {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
/** 操作按钮容器 **/
|
||||
.op.one {
|
||||
width: 4em;
|
||||
}
|
||||
|
||||
.op.two {
|
||||
width: 7.4em;
|
||||
}
|
||||
|
||||
.op.three {
|
||||
width: 9em;
|
||||
}
|
||||
|
||||
.op.four {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
/** 扩展UI **/
|
||||
.field.text {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
/** 右侧主操作区 **/
|
||||
.main {
|
||||
position: absolute;
|
||||
@@ -102,169 +126,214 @@ p.margin {
|
||||
padding-right: 1em;
|
||||
right: 1em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.main {
|
||||
left: 4em;
|
||||
}
|
||||
}
|
||||
|
||||
.main.without-menu {
|
||||
left: 9em;
|
||||
}
|
||||
|
||||
.main.without-secondary-menu {
|
||||
top: 2.9em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.main.without-menu {
|
||||
left: 4em;
|
||||
}
|
||||
}
|
||||
|
||||
.main table td.title {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
.main table td.middle-title {
|
||||
width: 14em;
|
||||
}
|
||||
|
||||
.main table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.main table td.color-border {
|
||||
border-left: 1px #276ac6 solid !important;
|
||||
}
|
||||
|
||||
.main table td.vertical-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.main table td.vertical-middle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.main table td[colspan="2"] a {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.main table td em {
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.main h3 {
|
||||
font-weight: normal;
|
||||
margin-top: 0.5em !important;
|
||||
}
|
||||
|
||||
.main h3 span {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.main h3 span.label {
|
||||
color: #6435c9;
|
||||
}
|
||||
|
||||
.main h3 a {
|
||||
margin-left: 1em;
|
||||
font-size: 14px !important;
|
||||
right: 1em;
|
||||
}
|
||||
|
||||
.main h3 a::before {
|
||||
content: "[";
|
||||
}
|
||||
|
||||
.main h3 a::after {
|
||||
content: "]";
|
||||
}
|
||||
|
||||
.main h4 {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.main td span.small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.main .button.mini {
|
||||
font-size: 0.8em;
|
||||
padding: 0.2em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
/** 右侧文本子菜单 **/
|
||||
.text.menu {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.text.menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
/** Vue **/
|
||||
[v-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/** auto complete **/
|
||||
.autocomplete-box .menu {
|
||||
background: #eee !important;
|
||||
}
|
||||
|
||||
.autocomplete-box .menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.autocomplete-box .menu .item {
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
select.auto-width {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
/** column **/
|
||||
@media screen and (max-width: 512px) {
|
||||
.column:not(.one) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
/** label **/
|
||||
label[for] {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
label.blue {
|
||||
color: #2185d0 !important;
|
||||
}
|
||||
|
||||
span.blue {
|
||||
color: #4183c4;
|
||||
}
|
||||
|
||||
/** Menu **/
|
||||
.first-menu .menu.text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.first-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.second-menu .menu.text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.second-menu .menu.text em {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.second-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.menu a {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/** var **/
|
||||
span.olive,
|
||||
var.olive {
|
||||
color: #b5cc18 !important;
|
||||
}
|
||||
|
||||
span.dash {
|
||||
border-bottom: 1px dashed grey;
|
||||
}
|
||||
|
||||
span.hover:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
/** Message **/
|
||||
.message .gopher {
|
||||
width: 30px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/** checkbox **/
|
||||
.checkbox label a,
|
||||
.checkbox label {
|
||||
font-size: 0.8em !important;
|
||||
}
|
||||
|
||||
/** page **/
|
||||
.page {
|
||||
margin-top: 1em;
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.page a {
|
||||
display: inline-block;
|
||||
background: #fafafa;
|
||||
@@ -275,30 +344,37 @@ span.hover:hover {
|
||||
border: 1px solid #ddd;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.page a.active {
|
||||
background: #2185d0 !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.page a:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
/** popup **/
|
||||
.swal2-html-container {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.swal2-confirm:focus,
|
||||
.swal2-cancel:focus,
|
||||
.swal2-close:focus {
|
||||
border: 3px #ddd solid !important;
|
||||
}
|
||||
|
||||
.swal2-confirm,
|
||||
.swal2-cancel,
|
||||
.swal2-close {
|
||||
border: 3px #fff solid !important;
|
||||
}
|
||||
|
||||
.swal2-cancel {
|
||||
margin-left: 2em !important;
|
||||
}
|
||||
|
||||
.combo-box .menu {
|
||||
max-height: 17em;
|
||||
overflow-y: auto;
|
||||
@@ -307,9 +383,11 @@ span.hover:hover {
|
||||
border-top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.combo-box .menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
code-label {
|
||||
background: #fff;
|
||||
border: 1px solid rgba(34, 36, 38, 0.15);
|
||||
@@ -323,4 +401,62 @@ code-label {
|
||||
font-weight: 700;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/*# sourceMappingURL=@layout_popup.css.map */
|
||||
|
||||
/*# sourceMappingURL=@layout_popup.css.map */
|
||||
/* Override Primary Button Color for WAF Platform */
|
||||
.ui.primary.button,
|
||||
.ui.primary.buttons .button {
|
||||
background-color: #0f2c54 !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.ui.primary.button:hover,
|
||||
.ui.primary.buttons .button:hover {
|
||||
background-color: #0a1f3a !important;
|
||||
}
|
||||
|
||||
.ui.primary.button:focus,
|
||||
.ui.primary.buttons .button:focus {
|
||||
background-color: #08192e !important;
|
||||
}
|
||||
|
||||
.ui.primary.button:active,
|
||||
.ui.primary.buttons .button:active,
|
||||
.ui.primary.active.button {
|
||||
background-color: #050d18 !important;
|
||||
}
|
||||
|
||||
.text-primary,
|
||||
.blue {
|
||||
color: #0f2c54 !important;
|
||||
}
|
||||
|
||||
/* Override Semantic UI Default Blue */
|
||||
.ui.blue.button,
|
||||
.ui.blue.buttons .button {
|
||||
background-color: #0f2c54 !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
.ui.blue.button:hover,
|
||||
.ui.blue.buttons .button:hover {
|
||||
background-color: #0a1f3a !important;
|
||||
}
|
||||
|
||||
.ui.basic.blue.button,
|
||||
.ui.basic.blue.buttons .button {
|
||||
box-shadow: 0 0 0 1px #0f2c54 inset !important;
|
||||
color: #0f2c54 !important;
|
||||
}
|
||||
|
||||
.ui.basic.blue.button:hover,
|
||||
.ui.basic.blue.buttons .button:hover {
|
||||
background: transparent !important;
|
||||
box-shadow: 0 0 0 1px #0a1f3a inset !important;
|
||||
color: #0a1f3a !important;
|
||||
}
|
||||
|
||||
.ui.menu .active.item {
|
||||
border-color: #2185d0 !important;
|
||||
color: #2185d0 !important;
|
||||
}
|
||||
Reference in New Issue
Block a user