mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Slugify: Replace gosimple/slug with a simple function (#59517)
This commit is contained in:
2
go.mod
2
go.mod
@@ -56,7 +56,6 @@ require (
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/google/wire v0.5.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/gosimple/slug v1.12.0
|
||||
github.com/grafana/cuetsy v0.1.1
|
||||
github.com/grafana/grafana-aws-sdk v0.11.0
|
||||
github.com/grafana/grafana-azure-sdk-go v1.3.1
|
||||
@@ -288,7 +287,6 @@ require (
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa // indirect
|
||||
github.com/googleapis/go-type-adapters v1.0.0 // indirect
|
||||
github.com/gosimple/unidecode v1.0.1 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/memberlist v0.4.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.1 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -1353,10 +1353,6 @@ github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gosimple/slug v1.12.0 h1:xzuhj7G7cGtd34NXnW/yF0l+AGNfWqwgh/IXgFy7dnc=
|
||||
github.com/gosimple/slug v1.12.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
|
||||
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
|
||||
github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
|
||||
github.com/grafana/codejen v0.0.3 h1:tAWxoTUuhgmEqxJPOLtJoxlPBbMULFwKFOcRsPRPXDw=
|
||||
github.com/grafana/codejen v0.0.3/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s=
|
||||
github.com/grafana/cuetsy v0.1.1 h1:+1jaDDYCpvKlcOWJgBRbkc5+VZIClCEn5mbI+4PLZqM=
|
||||
|
||||
370
pkg/infra/slugify/slugify.go
Normal file
370
pkg/infra/slugify/slugify.go
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* This file evolved from the MIT licensed: https://github.com/machiel/slugify
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Machiel Molenaar
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package slugify
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
)
|
||||
|
||||
var (
|
||||
simpleSlugger = &slugger{
|
||||
isValidCharacter: validCharacter,
|
||||
replaceCharacter: '-',
|
||||
replacementMap: getDefaultReplacements(),
|
||||
}
|
||||
)
|
||||
|
||||
// Slugify creates a URL safe latin slug for a given value
|
||||
func Slugify(value string) string {
|
||||
s := simpleSlugger.Slugify(value)
|
||||
if s == "" {
|
||||
s = base64.RawURLEncoding.EncodeToString([]byte(value))
|
||||
if len(s) > 50 || s == "" {
|
||||
s = uuid.NewV5(uuid.NamespaceOID, value).String()
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func validCharacter(c rune) bool {
|
||||
if c >= 'a' && c <= 'z' {
|
||||
return true
|
||||
}
|
||||
if c >= '0' && c <= '9' {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Slugifier based on settings
|
||||
type slugger struct {
|
||||
isValidCharacter func(c rune) bool
|
||||
replaceCharacter rune
|
||||
replacementMap map[rune]string
|
||||
}
|
||||
|
||||
// Slugify creates a slug for a string
|
||||
func (s slugger) Slugify(value string) string {
|
||||
value = strings.ToLower(value)
|
||||
var buffer bytes.Buffer
|
||||
lastCharacterWasInvalid := false
|
||||
|
||||
for len(value) > 0 {
|
||||
c, size := utf8.DecodeRuneInString(value)
|
||||
value = value[size:]
|
||||
|
||||
if newCharacter, ok := s.replacementMap[c]; ok {
|
||||
buffer.WriteString(newCharacter)
|
||||
lastCharacterWasInvalid = false
|
||||
continue
|
||||
}
|
||||
|
||||
if s.isValidCharacter(c) {
|
||||
buffer.WriteRune(c)
|
||||
lastCharacterWasInvalid = false
|
||||
} else if !lastCharacterWasInvalid {
|
||||
buffer.WriteRune(s.replaceCharacter)
|
||||
lastCharacterWasInvalid = true
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Trim(buffer.String(), string(s.replaceCharacter))
|
||||
}
|
||||
|
||||
func getDefaultReplacements() map[rune]string {
|
||||
return map[rune]string{
|
||||
'&': "and",
|
||||
'@': "at",
|
||||
'©': "c",
|
||||
'®': "r",
|
||||
'Æ': "ae",
|
||||
'ß': "ss",
|
||||
'à': "a",
|
||||
'á': "a",
|
||||
'â': "a",
|
||||
'ä': "a", // or "ae"
|
||||
'å': "a",
|
||||
'æ': "ae",
|
||||
'ç': "c",
|
||||
'è': "e",
|
||||
'é': "e",
|
||||
'ê': "e",
|
||||
'ë': "e",
|
||||
'ì': "i",
|
||||
'í': "i",
|
||||
'î': "i",
|
||||
'ï': "i",
|
||||
'ò': "o",
|
||||
'ó': "o",
|
||||
'ô': "o",
|
||||
'õ': "o",
|
||||
'ö': "o", // or "oe"?
|
||||
'ø': "o",
|
||||
'ù': "u",
|
||||
'ú': "u",
|
||||
'û': "u",
|
||||
'ü': "ue",
|
||||
'ý': "y",
|
||||
'þ': "p",
|
||||
'ÿ': "y",
|
||||
'ā': "a",
|
||||
'ă': "a",
|
||||
'Ą': "a",
|
||||
'ą': "a",
|
||||
'ć': "c",
|
||||
'ĉ': "c",
|
||||
'ċ': "c",
|
||||
'č': "c",
|
||||
'ď': "d",
|
||||
'đ': "d",
|
||||
'ē': "e",
|
||||
'ĕ': "e",
|
||||
'ė': "e",
|
||||
'ę': "e",
|
||||
'ě': "e",
|
||||
'ĝ': "g",
|
||||
'ğ': "g",
|
||||
'ġ': "g",
|
||||
'ģ': "g",
|
||||
'ĥ': "h",
|
||||
'ħ': "h",
|
||||
'ĩ': "i",
|
||||
'ī': "i",
|
||||
'ĭ': "i",
|
||||
'į': "i",
|
||||
'ı': "i",
|
||||
'ij': "ij",
|
||||
'ĵ': "j",
|
||||
'ķ': "k",
|
||||
'ĸ': "k",
|
||||
'Ĺ': "l",
|
||||
'ĺ': "l",
|
||||
'ļ': "l",
|
||||
'ľ': "l",
|
||||
'ŀ': "l",
|
||||
'ł': "l",
|
||||
'ń': "n",
|
||||
'ņ': "n",
|
||||
'ň': "n",
|
||||
'ʼn': "n",
|
||||
'ŋ': "n",
|
||||
'ō': "o",
|
||||
'ŏ': "o",
|
||||
'ő': "o",
|
||||
'Œ': "oe",
|
||||
'œ': "oe",
|
||||
'ŕ': "r",
|
||||
'ŗ': "r",
|
||||
'ř': "r",
|
||||
'ś': "s",
|
||||
'ŝ': "s",
|
||||
'ş': "s",
|
||||
'š': "s",
|
||||
'ţ': "t",
|
||||
'ť': "t",
|
||||
'ŧ': "t",
|
||||
'ũ': "u",
|
||||
'ū': "u",
|
||||
'ŭ': "u",
|
||||
'ů': "u",
|
||||
'ű': "u",
|
||||
'ų': "u",
|
||||
'ŵ': "w",
|
||||
'ŷ': "y",
|
||||
'ź': "z",
|
||||
'ż': "z",
|
||||
'ž': "z",
|
||||
'ſ': "z",
|
||||
'Ə': "e",
|
||||
'ƒ': "f",
|
||||
'Ơ': "o",
|
||||
'ơ': "o",
|
||||
'Ư': "u",
|
||||
'ư': "u",
|
||||
'ǎ': "a",
|
||||
'ǐ': "i",
|
||||
'ǒ': "o",
|
||||
'ǔ': "u",
|
||||
'ǖ': "u",
|
||||
'ǘ': "u",
|
||||
'ǚ': "u",
|
||||
'ǜ': "u",
|
||||
'ǻ': "a",
|
||||
'Ǽ': "ae",
|
||||
'ǽ': "ae",
|
||||
'Ǿ': "o",
|
||||
'ǿ': "o",
|
||||
'ə': "e",
|
||||
'Є': "e",
|
||||
'Б': "b",
|
||||
'Г': "g",
|
||||
'Д': "d",
|
||||
'Ж': "zh",
|
||||
'З': "z",
|
||||
'У': "u",
|
||||
'Ф': "f",
|
||||
'Х': "h",
|
||||
'Ц': "c",
|
||||
'Ч': "ch",
|
||||
'Ш': "sh",
|
||||
'Щ': "sch",
|
||||
'Ъ': "-",
|
||||
'Ы': "y",
|
||||
'Ь': "-",
|
||||
'Э': "je",
|
||||
'Ю': "ju",
|
||||
'Я': "ja",
|
||||
'а': "a",
|
||||
'б': "b",
|
||||
'в': "v",
|
||||
'г': "g",
|
||||
'д': "d",
|
||||
'е': "e",
|
||||
'ж': "zh",
|
||||
'з': "z",
|
||||
'и': "i",
|
||||
'й': "j",
|
||||
'к': "k",
|
||||
'л': "l",
|
||||
'м': "m",
|
||||
'н': "n",
|
||||
'о': "o",
|
||||
'п': "p",
|
||||
'р': "r",
|
||||
'с': "s",
|
||||
'т': "t",
|
||||
'у': "u",
|
||||
'ф': "f",
|
||||
'х': "h",
|
||||
'ц': "c",
|
||||
'ч': "ch",
|
||||
'ш': "sh",
|
||||
'щ': "sch",
|
||||
'ъ': "-",
|
||||
'ы': "y",
|
||||
'ь': "-",
|
||||
'э': "je",
|
||||
'ю': "ju",
|
||||
'я': "ja",
|
||||
'ё': "jo",
|
||||
'є': "e",
|
||||
'і': "i",
|
||||
'ї': "i",
|
||||
'Ґ': "g",
|
||||
'ґ': "g",
|
||||
'א': "a",
|
||||
'ב': "b",
|
||||
'ג': "g",
|
||||
'ד': "d",
|
||||
'ה': "h",
|
||||
'ו': "v",
|
||||
'ז': "z",
|
||||
'ח': "h",
|
||||
'ט': "t",
|
||||
'י': "i",
|
||||
'ך': "k",
|
||||
'כ': "k",
|
||||
'ל': "l",
|
||||
'ם': "m",
|
||||
'מ': "m",
|
||||
'ן': "n",
|
||||
'נ': "n",
|
||||
'ס': "s",
|
||||
'ע': "e",
|
||||
'ף': "p",
|
||||
'פ': "p",
|
||||
'ץ': "C",
|
||||
'צ': "c",
|
||||
'ק': "q",
|
||||
'ר': "r",
|
||||
'ש': "w",
|
||||
'ת': "t",
|
||||
'™': "tm",
|
||||
'ả': "a",
|
||||
'ã': "a",
|
||||
'ạ': "a",
|
||||
|
||||
'ắ': "a",
|
||||
'ằ': "a",
|
||||
'ẳ': "a",
|
||||
'ẵ': "a",
|
||||
'ặ': "a",
|
||||
|
||||
'ấ': "a",
|
||||
'ầ': "a",
|
||||
'ẩ': "a",
|
||||
'ẫ': "a",
|
||||
'ậ': "a",
|
||||
|
||||
'ẻ': "e",
|
||||
'ẽ': "e",
|
||||
'ẹ': "e",
|
||||
'ế': "e",
|
||||
'ề': "e",
|
||||
'ể': "e",
|
||||
'ễ': "e",
|
||||
'ệ': "e",
|
||||
|
||||
'ỉ': "i",
|
||||
'ị': "i",
|
||||
|
||||
'ỏ': "o",
|
||||
'ọ': "o",
|
||||
'ố': "o",
|
||||
'ồ': "o",
|
||||
'ổ': "o",
|
||||
'ỗ': "o",
|
||||
'ộ': "o",
|
||||
'ớ': "o",
|
||||
'ờ': "o",
|
||||
'ở': "o",
|
||||
'ỡ': "o",
|
||||
'ợ': "o",
|
||||
|
||||
'ủ': "u",
|
||||
'ụ': "u",
|
||||
'ứ': "u",
|
||||
'ừ': "u",
|
||||
'ử': "u",
|
||||
'ữ': "u",
|
||||
'ự': "u",
|
||||
|
||||
'ỳ': "y",
|
||||
'ỷ': "y",
|
||||
'ỹ': "y",
|
||||
'ỵ': "y",
|
||||
}
|
||||
}
|
||||
54
pkg/infra/slugify/slugify_test.go
Normal file
54
pkg/infra/slugify/slugify_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package slugify
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSlugify(t *testing.T) {
|
||||
results := make(map[string]string)
|
||||
results["hello-playground"] = "Hello, playground"
|
||||
results["hello-it-s-paradise"] = "😢 😣 😤 😥 😦 😧 😨 😩 😪 😫 😬 Hello, it's paradise"
|
||||
results["61db60b5-f1e7-5853-9b81-0f074fc268ea"] = "😢 😣 😤 😥 😦 😧 😨 😩 😪 😫 😬"
|
||||
results["8J-YoiAt"] = "😢 -"
|
||||
results["a"] = "?,a . \n "
|
||||
results["0a68eb57-c88a-5f34-9e9d-27f85e68af4f"] = "" // empty input has a slug!
|
||||
results["hi-this-is-a-test"] = "方向盤後面 hi this is a test خلف المقو"
|
||||
results["cong-hoa-xa-hoi-chu-nghia-viet-nam"] = "Cộng hòa xã hội chủ nghĩa Việt Nam"
|
||||
results["noi-nang-canh-canh-ben-long-bieng-khuay"] = "Nỗi nàng canh cánh bên lòng biếng khuây" // This line in a poem called Truyen Kieu
|
||||
|
||||
for slug, original := range results {
|
||||
actual := Slugify(original)
|
||||
|
||||
if actual != slug {
|
||||
t.Errorf("Expected '%s', got: %s", slug, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSlugify(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Slugify("Hello, world!")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSlugifyLongString(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Slugify(`
|
||||
😢 😣 😤 😥 😦 😧 😨 😩 😪 😫 😬 Hello, it's paradise
|
||||
😢 😣 😤 😥 😦 😧 😨 😩 😪 😫 😬 Hello, it's paradise
|
||||
😢 😣 😤 😥 😦 😧 😨 😩 😪 😫 😬 Hello, it's paradise
|
||||
😢 😣 😤 😥 😦 😧 😨 😩 😪 😫 😬 Hello, it's paradise
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Aliquam sapien nisl, laoreet quis vestibulum ut, cursus
|
||||
in turpis. Sed magna mi, blandit id nisi vel, imperdiet
|
||||
mollis turpis. Fusce vel fringilla mauris. Donec cursus
|
||||
rhoncus bibendum. Aliquam erat volutpat. Maecenas
|
||||
faucibus turpis ex, quis lacinia ligula ultrices non.
|
||||
Sed gravida justo augue. Nulla bibendum dignissim tellus
|
||||
vitae lobortis. Suspendisse fermentum vel purus in pulvinar.
|
||||
Vivamus eu fermentum purus, sit amet tempor orci.
|
||||
Praesent congue convallis turpis, ac ullamcorper lorem
|
||||
semper id.
|
||||
`)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,11 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gosimple/slug"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@@ -147,22 +144,7 @@ func (cmd *SaveDashboardCommand) GetDashboardModel() *Dashboard {
|
||||
// UpdateSlug updates the slug
|
||||
func (d *Dashboard) UpdateSlug() {
|
||||
title := d.Data.Get("title").MustString()
|
||||
d.Slug = SlugifyTitle(title)
|
||||
}
|
||||
|
||||
func SlugifyTitle(title string) string {
|
||||
s := slug.Make(strings.ToLower(title))
|
||||
if s == "" {
|
||||
// If the dashboard name is only characters outside of the
|
||||
// sluggable characters, the slug creation will return an
|
||||
// empty string which will mess up URLs. This failsafe picks
|
||||
// that up and creates the slug as a base64 identifier instead.
|
||||
s = base64.RawURLEncoding.EncodeToString([]byte(title))
|
||||
if slug.MaxLength != 0 && len(s) > slug.MaxLength {
|
||||
s = s[:slug.MaxLength]
|
||||
}
|
||||
}
|
||||
return s
|
||||
d.Slug = slugify.Slugify(title)
|
||||
}
|
||||
|
||||
// GetUrl return the html url for a folder if it's folder, otherwise for a dashboard
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -72,14 +73,14 @@ func TestSlugifyTitle(t *testing.T) {
|
||||
testCases := map[string]string{
|
||||
"Grafana Play Home": "grafana-play-home",
|
||||
"snöräv-över-ån": "snorav-over-an",
|
||||
"漢字": "han-zi", // Hanzi for hanzi
|
||||
"漢字": "5ryi5a2X", // "han-zi", // Hanzi for hanzi
|
||||
"🇦🇶": "8J-HpvCfh7Y", // flag of Antarctica-emoji, using fallback
|
||||
"𒆠": "8JKGoA", // cuneiform Ki, using fallback
|
||||
}
|
||||
|
||||
for input, expected := range testCases {
|
||||
t.Run(input, func(t *testing.T) {
|
||||
slug := SlugifyTitle(input)
|
||||
slug := slugify.Slugify(input)
|
||||
assert.Equal(t, expected, slug)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,11 +12,10 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/gosimple/slug"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/fs"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
@@ -343,7 +342,7 @@ func setDefaultNavURL(p *plugins.Plugin) {
|
||||
// slugify pages
|
||||
for _, include := range p.Includes {
|
||||
if include.Slug == "" {
|
||||
include.Slug = slug.Make(include.Name)
|
||||
include.Slug = slugify.Slugify(include.Name)
|
||||
}
|
||||
|
||||
if !include.DefaultNav {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
@@ -170,7 +171,7 @@ func (ss *sqlStore) Get(ctx context.Context, q folder.GetFolderQuery) (*folder.F
|
||||
}
|
||||
return nil
|
||||
})
|
||||
foldr.Url = models.GetFolderUrl(foldr.UID, models.SlugifyTitle(foldr.Title))
|
||||
foldr.Url = models.GetFolderUrl(foldr.UID, slugify.Slugify(foldr.Title))
|
||||
return foldr, err
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package folder
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
@@ -141,7 +142,7 @@ func (f *Folder) ToLegacyModel() *models.Folder {
|
||||
Id: f.ID,
|
||||
Uid: f.UID,
|
||||
Title: f.Title,
|
||||
Url: models.GetFolderUrl(f.UID, models.SlugifyTitle(f.Title)),
|
||||
Url: models.GetFolderUrl(f.UID, slugify.Slugify(f.Title)),
|
||||
Version: 0,
|
||||
Created: f.Created,
|
||||
Updated: f.Updated,
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
alert_models "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
@@ -99,7 +100,7 @@ func (prov *defaultAlertRuleProvisioner) provisionRule(
|
||||
func (prov *defaultAlertRuleProvisioner) getOrCreateFolderUID(
|
||||
ctx context.Context, folderName string, orgID int64) (string, error) {
|
||||
cmd := &models.GetDashboardQuery{
|
||||
Slug: models.SlugifyTitle(folderName),
|
||||
Slug: slugify.Slugify(folderName),
|
||||
OrgId: orgID,
|
||||
}
|
||||
err := prov.dashboardService.GetDashboard(ctx, cmd)
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
@@ -299,7 +300,7 @@ func (fr *FileReader) getOrCreateFolderID(ctx context.Context, cfg *config, serv
|
||||
return 0, ErrFolderNameMissing
|
||||
}
|
||||
|
||||
cmd := &models.GetDashboardQuery{Slug: models.SlugifyTitle(folderName), OrgId: cfg.OrgID}
|
||||
cmd := &models.GetDashboardQuery{Slug: slugify.Slugify(folderName), OrgId: cfg.OrgID}
|
||||
err := fr.dashboardStore.GetDashboard(ctx, cmd)
|
||||
|
||||
if err != nil && !errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package ualert
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
|
||||
"github.com/gosimple/slug"
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
)
|
||||
|
||||
type dashboard struct {
|
||||
@@ -45,22 +42,7 @@ func (d *dashboard) setVersion(version int) {
|
||||
// UpdateSlug updates the slug
|
||||
func (d *dashboard) updateSlug() {
|
||||
title := d.Data.Get("title").MustString()
|
||||
d.Slug = slugifyTitle(title)
|
||||
}
|
||||
|
||||
func slugifyTitle(title string) string {
|
||||
s := slug.Make(strings.ToLower(title))
|
||||
if s == "" {
|
||||
// If the dashboard name is only characters outside of the
|
||||
// sluggable characters, the slug creation will return an
|
||||
// empty string which will mess up URLs. This failsafe picks
|
||||
// that up and creates the slug as a base64 identifier instead.
|
||||
s = base64.RawURLEncoding.EncodeToString([]byte(title))
|
||||
if slug.MaxLength != 0 && len(s) > slug.MaxLength {
|
||||
s = s[:slug.MaxLength]
|
||||
}
|
||||
}
|
||||
return s
|
||||
d.Slug = slugify.Slugify(title)
|
||||
}
|
||||
|
||||
func newDashboardFromJson(data *simplejson.Json) *dashboard {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/slugify"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
)
|
||||
@@ -57,7 +58,7 @@ func NewStaticDashboardSummaryBuilder(lookup DatasourceLookup, sanitize bool) mo
|
||||
}
|
||||
|
||||
dashboardRefs := NewReferenceAccumulator()
|
||||
url := fmt.Sprintf("/d/%s/%s", uid, models.SlugifyTitle(dash.Title))
|
||||
url := fmt.Sprintf("/d/%s/%s", uid, slugify.Slugify(dash.Title))
|
||||
summary.Name = dash.Title
|
||||
summary.Description = dash.Description
|
||||
summary.URL = url
|
||||
|
||||
Reference in New Issue
Block a user