Compare commits
32 Commits
Author | SHA1 | Date | |
---|---|---|---|
015040cc1d | |||
c8869e67c7 | |||
a9ae7d2e96 | |||
db9034ccf9 | |||
4d1705dca5 | |||
3225e7c47b | |||
328397612c | |||
c846cde5b4 | |||
5c2cb99866 | |||
742c7da2eb | |||
88b247410f | |||
01417943fb | |||
09f7c33135 | |||
fe3b78f844 | |||
0fd54426e6 | |||
690e14e4ed | |||
7795b17fd1 | |||
c7dd4dc3eb | |||
6ee6a5166e | |||
8c753e9557 | |||
6126701025 | |||
8ef7d5f0d0 | |||
fa8d2f6639 | |||
8cd976791e | |||
010271c668 | |||
383d4f27f0 | |||
cb9786ef7c | |||
e936bb6f15 | |||
60c440ae10 | |||
fc8808ce04 | |||
e88327f2a3 | |||
159dfc9446 |
10
.github/workflows/extension-test.yml
vendored
@ -15,9 +15,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: bufbuild/buf-setup-action@v1
|
|
||||||
- run: buf generate
|
|
||||||
working-directory: proto
|
|
||||||
- uses: pnpm/action-setup@v2.2.4
|
- uses: pnpm/action-setup@v2.2.4
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 8
|
||||||
@ -28,6 +25,8 @@ jobs:
|
|||||||
cache-dependency-path: "frontend/extension/pnpm-lock.yaml"
|
cache-dependency-path: "frontend/extension/pnpm-lock.yaml"
|
||||||
- run: pnpm install
|
- run: pnpm install
|
||||||
working-directory: frontend/extension
|
working-directory: frontend/extension
|
||||||
|
- run: pnpm type-gen
|
||||||
|
working-directory: frontend/extension
|
||||||
- name: Run eslint check
|
- name: Run eslint check
|
||||||
run: pnpm lint
|
run: pnpm lint
|
||||||
working-directory: frontend/extension
|
working-directory: frontend/extension
|
||||||
@ -36,9 +35,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: bufbuild/buf-setup-action@v1
|
|
||||||
- run: buf generate
|
|
||||||
working-directory: proto
|
|
||||||
- uses: pnpm/action-setup@v2.2.4
|
- uses: pnpm/action-setup@v2.2.4
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 8
|
||||||
@ -49,6 +45,8 @@ jobs:
|
|||||||
cache-dependency-path: "frontend/extension/pnpm-lock.yaml"
|
cache-dependency-path: "frontend/extension/pnpm-lock.yaml"
|
||||||
- run: pnpm install
|
- run: pnpm install
|
||||||
working-directory: frontend/extension
|
working-directory: frontend/extension
|
||||||
|
- run: pnpm type-gen
|
||||||
|
working-directory: frontend/extension
|
||||||
- name: Run extension build
|
- name: Run extension build
|
||||||
run: pnpm build
|
run: pnpm build
|
||||||
working-directory: frontend/extension
|
working-directory: frontend/extension
|
||||||
|
10
.github/workflows/frontend-test.yml
vendored
@ -15,9 +15,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: bufbuild/buf-setup-action@v1
|
|
||||||
- run: buf generate
|
|
||||||
working-directory: proto
|
|
||||||
- uses: pnpm/action-setup@v2.2.4
|
- uses: pnpm/action-setup@v2.2.4
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 8
|
||||||
@ -28,6 +25,8 @@ jobs:
|
|||||||
cache-dependency-path: "frontend/web/pnpm-lock.yaml"
|
cache-dependency-path: "frontend/web/pnpm-lock.yaml"
|
||||||
- run: pnpm install
|
- run: pnpm install
|
||||||
working-directory: frontend/web
|
working-directory: frontend/web
|
||||||
|
- run: pnpm type-gen
|
||||||
|
working-directory: frontend/web
|
||||||
- name: Run eslint check
|
- name: Run eslint check
|
||||||
run: pnpm lint
|
run: pnpm lint
|
||||||
working-directory: frontend/web
|
working-directory: frontend/web
|
||||||
@ -36,9 +35,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: bufbuild/buf-setup-action@v1
|
|
||||||
- run: buf generate
|
|
||||||
working-directory: proto
|
|
||||||
- uses: pnpm/action-setup@v2.2.4
|
- uses: pnpm/action-setup@v2.2.4
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 8
|
||||||
@ -49,6 +45,8 @@ jobs:
|
|||||||
cache-dependency-path: "frontend/web/pnpm-lock.yaml"
|
cache-dependency-path: "frontend/web/pnpm-lock.yaml"
|
||||||
- run: pnpm install
|
- run: pnpm install
|
||||||
working-directory: frontend/web
|
working-directory: frontend/web
|
||||||
|
- run: pnpm type-gen
|
||||||
|
working-directory: frontend/web
|
||||||
- name: Run frontend build
|
- name: Run frontend build
|
||||||
run: pnpm build
|
run: pnpm build
|
||||||
working-directory: frontend/web
|
working-directory: frontend/web
|
||||||
|
24
Dockerfile
@ -1,26 +1,12 @@
|
|||||||
# Build protobuf.
|
|
||||||
FROM golang:1.21-alpine AS protobuf
|
|
||||||
WORKDIR /protobuf-generate
|
|
||||||
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
RUN GO111MODULE=on GOBIN=/usr/local/bin go install github.com/bufbuild/buf/cmd/buf@v1.26.1
|
|
||||||
|
|
||||||
WORKDIR /protobuf-generate/proto
|
|
||||||
|
|
||||||
RUN buf generate
|
|
||||||
|
|
||||||
# Build frontend dist.
|
# Build frontend dist.
|
||||||
FROM node:18-alpine AS frontend
|
FROM node:18-alpine AS frontend
|
||||||
WORKDIR /frontend-build
|
WORKDIR /frontend-build
|
||||||
|
|
||||||
COPY ./frontend .
|
COPY . .
|
||||||
|
|
||||||
COPY --from=protobuf /protobuf-generate/frontend/web/src/types/proto ./web/src/types/proto
|
WORKDIR /frontend-build/frontend/web
|
||||||
|
|
||||||
WORKDIR /frontend-build/web
|
RUN corepack enable && pnpm i --frozen-lockfile && pnpm type-gen
|
||||||
|
|
||||||
RUN corepack enable && pnpm i --frozen-lockfile
|
|
||||||
|
|
||||||
RUN pnpm build
|
RUN pnpm build
|
||||||
|
|
||||||
@ -29,9 +15,9 @@ FROM golang:1.21-alpine AS backend
|
|||||||
WORKDIR /backend-build
|
WORKDIR /backend-build
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
COPY --from=frontend /frontend-build/web/dist ./server/dist
|
COPY --from=frontend /frontend-build/frontend/web/dist ./server/dist
|
||||||
|
|
||||||
RUN CGO_ENABLED=0 go build -o slash ./cmd/slash/main.go
|
RUN CGO_ENABLED=0 go build -o slash ./bin/slash/main.go
|
||||||
|
|
||||||
# Make workspace with above generated files.
|
# Make workspace with above generated files.
|
||||||
FROM alpine:latest AS monolithic
|
FROM alpine:latest AS monolithic
|
||||||
|
11
README.md
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
**Slash** is an open source, self-hosted bookmarks and link sharing platform. It allows you to organize your links with tags, and share them using custom shortened URLs. Slash also supports team sharing of link libraries for easy collaboration.
|
**Slash** is an open source, self-hosted bookmarks and link sharing platform. It allows you to organize your links with tags, and share them using custom shortened URLs. Slash also supports team sharing of link libraries for easy collaboration.
|
||||||
|
|
||||||
|
🧩 Browser extension(v1.0.0) now available! - [Chrome Web Store](https://chrome.google.com/webstore/detail/slash/ebaiehmkammnacjadffpicipfckgeobg), [Firefox Add-on](https://addons.mozilla.org/firefox/addon/your-slash/)
|
||||||
|
|
||||||
<a href="https://demo.slash.yourselfhosted.com">Live Demo</a> • <a href="https://discord.gg/QZqUuUAhDV">Discord</a>
|
<a href="https://demo.slash.yourselfhosted.com">Live Demo</a> • <a href="https://discord.gg/QZqUuUAhDV">Discord</a>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -11,9 +13,6 @@
|
|||||||
<a href="https://github.com/boojack/slash/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/boojack/slash?logo=github"/></a>
|
<a href="https://github.com/boojack/slash/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/boojack/slash?logo=github"/></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://chrome.google.com/webstore/detail/slash/ebaiehmkammnacjadffpicipfckgeobg"><b>🧩 Browser extension now available!</b></a></p>
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@ -38,8 +37,12 @@ Slash provides a browser extension to help you use your shortcuts in the search
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
Learn more in [The Browser Extension of Slash](https://github.com/boojack/slash/blob/main/docs/install-browser-extension.md).
|
||||||
|
|
||||||
### Chromium based browsers
|
### Chromium based browsers
|
||||||
|
|
||||||
For Chromium based browsers(Chrome, Edge, Arc, ...), you can install the extension from the [Chrome Web Store](https://chrome.google.com/webstore/detail/slash/ebaiehmkammnacjadffpicipfckgeobg).
|
For Chromium based browsers(Chrome, Edge, Arc, ...), you can install the extension from the [Chrome Web Store](https://chrome.google.com/webstore/detail/slash/ebaiehmkammnacjadffpicipfckgeobg).
|
||||||
|
|
||||||
Learn more in [The Browser Extension of Slash](https://github.com/boojack/slash/blob/main/docs/install-browser-extension.md).
|
### Firefox
|
||||||
|
|
||||||
|
For Firefox, you can install the extension from the [Firefox Add-ons](https://addons.mozilla.org/firefox/addon/your-slash/).
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/mssola/useragent"
|
"github.com/mssola/useragent"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
|
|
||||||
|
"github.com/boojack/slash/server/metric"
|
||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -78,6 +79,7 @@ func (s *APIV1Service) registerAnalyticsRoutes(g *echo.Group) {
|
|||||||
browserMap[browserName]++
|
browserMap[browserName]++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metric.Enqueue("shortcut analytics")
|
||||||
return c.JSON(http.StatusOK, &AnalysisData{
|
return c.JSON(http.StatusOK, &AnalysisData{
|
||||||
ReferenceData: mapToReferenceInfoSlice(referenceMap),
|
ReferenceData: mapToReferenceInfoSlice(referenceMap),
|
||||||
DeviceData: mapToDeviceInfoSlice(deviceMap),
|
DeviceData: mapToDeviceInfoSlice(deviceMap),
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/boojack/slash/api/auth"
|
"github.com/boojack/slash/api/auth"
|
||||||
storepb "github.com/boojack/slash/proto/gen/store"
|
storepb "github.com/boojack/slash/proto/gen/store"
|
||||||
|
"github.com/boojack/slash/server/metric"
|
||||||
"github.com/boojack/slash/server/service/license"
|
"github.com/boojack/slash/server/service/license"
|
||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
)
|
)
|
||||||
@ -63,6 +64,7 @@ func (s *APIV1Service) registerAuthRoutes(g *echo.Group, secret string) {
|
|||||||
|
|
||||||
cookieExp := time.Now().Add(auth.CookieExpDuration)
|
cookieExp := time.Now().Add(auth.CookieExpDuration)
|
||||||
setTokenCookie(c, auth.AccessTokenCookieName, accessToken, cookieExp)
|
setTokenCookie(c, auth.AccessTokenCookieName, accessToken, cookieExp)
|
||||||
|
metric.Enqueue("user sign in")
|
||||||
return c.JSON(http.StatusOK, convertUserFromStore(user))
|
return c.JSON(http.StatusOK, convertUserFromStore(user))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -129,6 +131,7 @@ func (s *APIV1Service) registerAuthRoutes(g *echo.Group, secret string) {
|
|||||||
|
|
||||||
cookieExp := time.Now().Add(auth.CookieExpDuration)
|
cookieExp := time.Now().Add(auth.CookieExpDuration)
|
||||||
setTokenCookie(c, auth.AccessTokenCookieName, accessToken, cookieExp)
|
setTokenCookie(c, auth.AccessTokenCookieName, accessToken, cookieExp)
|
||||||
|
metric.Enqueue("user sign up")
|
||||||
return c.JSON(http.StatusOK, convertUserFromStore(user))
|
return c.JSON(http.StatusOK, convertUserFromStore(user))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -36,15 +36,15 @@ func extractTokenFromHeader(c echo.Context) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func findAccessToken(c echo.Context) string {
|
func findAccessToken(c echo.Context) string {
|
||||||
accessToken := ""
|
// Check the HTTP request header first.
|
||||||
cookie, _ := c.Cookie(auth.AccessTokenCookieName)
|
accessToken, _ := extractTokenFromHeader(c)
|
||||||
if cookie != nil {
|
|
||||||
accessToken = cookie.Value
|
|
||||||
}
|
|
||||||
if accessToken == "" {
|
if accessToken == "" {
|
||||||
accessToken, _ = extractTokenFromHeader(c)
|
// Check the cookie.
|
||||||
|
cookie, _ := c.Cookie(auth.AccessTokenCookieName)
|
||||||
|
if cookie != nil {
|
||||||
|
accessToken = cookie.Value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return accessToken
|
return accessToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
storepb "github.com/boojack/slash/proto/gen/store"
|
storepb "github.com/boojack/slash/proto/gen/store"
|
||||||
|
"github.com/boojack/slash/server/metric"
|
||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ func (s *APIV1Service) registerRedirectorRoutes(g *echo.Group) {
|
|||||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to get shortcut, err: %s", err)).SetInternal(err)
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to get shortcut, err: %s", err)).SetInternal(err)
|
||||||
}
|
}
|
||||||
if shortcut == nil {
|
if shortcut == nil {
|
||||||
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("not found shortcut with name: %s", shortcutName))
|
return c.Redirect(http.StatusSeeOther, fmt.Sprintf("/404?shortcut=%s", shortcutName))
|
||||||
}
|
}
|
||||||
if shortcut.Visibility != storepb.Visibility_PUBLIC {
|
if shortcut.Visibility != storepb.Visibility_PUBLIC {
|
||||||
userID, ok := c.Get(userIDContextKey).(int32)
|
userID, ok := c.Get(userIDContextKey).(int32)
|
||||||
@ -46,6 +47,7 @@ func (s *APIV1Service) registerRedirectorRoutes(g *echo.Group) {
|
|||||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to create activity, err: %s", err)).SetInternal(err)
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to create activity, err: %s", err)).SetInternal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metric.Enqueue("shortcut redirect")
|
||||||
return redirectToShortcut(c, shortcut)
|
return redirectToShortcut(c, shortcut)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/boojack/slash/internal/util"
|
"github.com/boojack/slash/internal/util"
|
||||||
storepb "github.com/boojack/slash/proto/gen/store"
|
storepb "github.com/boojack/slash/proto/gen/store"
|
||||||
|
"github.com/boojack/slash/server/metric"
|
||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -121,6 +122,7 @@ func (s *APIV1Service) registerShortcutRoutes(g *echo.Group) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to compose shortcut, err: %s", err)).SetInternal(err)
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to compose shortcut, err: %s", err)).SetInternal(err)
|
||||||
}
|
}
|
||||||
|
metric.Enqueue("shortcut create")
|
||||||
return c.JSON(http.StatusOK, shortcutMessage)
|
return c.JSON(http.StatusOK, shortcutMessage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"go.deanishe.net/favicon"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (*APIV1Service) registerURLUtilRoutes(g *echo.Group) {
|
|
||||||
// GET /url/favicon?url=...
|
|
||||||
g.GET("/url/favicon", func(c echo.Context) error {
|
|
||||||
url := c.QueryParam("url")
|
|
||||||
icons, err := favicon.Find(url)
|
|
||||||
if err != nil {
|
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("failed to find favicon, err: %s", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
availableIcons := []*favicon.Icon{}
|
|
||||||
for _, icon := range icons {
|
|
||||||
if icon.Width == icon.Height {
|
|
||||||
availableIcons = append(availableIcons, icon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(availableIcons) == 0 {
|
|
||||||
return echo.NewHTTPError(http.StatusNotFound, "no favicon found")
|
|
||||||
}
|
|
||||||
return c.JSON(http.StatusOK, availableIcons[0].URL)
|
|
||||||
})
|
|
||||||
}
|
|
@ -11,6 +11,7 @@ import (
|
|||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
"github.com/boojack/slash/internal/util"
|
"github.com/boojack/slash/internal/util"
|
||||||
|
"github.com/boojack/slash/server/metric"
|
||||||
"github.com/boojack/slash/server/service/license"
|
"github.com/boojack/slash/server/service/license"
|
||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
)
|
)
|
||||||
@ -137,6 +138,7 @@ func (s *APIV1Service) registerUserRoutes(g *echo.Group) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
userMessage := convertUserFromStore(user)
|
userMessage := convertUserFromStore(user)
|
||||||
|
metric.Enqueue("user create")
|
||||||
return c.JSON(http.StatusOK, userMessage)
|
return c.JSON(http.StatusOK, userMessage)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -27,7 +27,6 @@ func (s *APIV1Service) Start(apiGroup *echo.Group, secret string) {
|
|||||||
apiV1Group.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
|
apiV1Group.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return JWTMiddleware(s, next, secret)
|
return JWTMiddleware(s, next, secret)
|
||||||
})
|
})
|
||||||
s.registerURLUtilRoutes(apiV1Group)
|
|
||||||
s.registerWorkspaceRoutes(apiV1Group)
|
s.registerWorkspaceRoutes(apiV1Group)
|
||||||
s.registerAuthRoutes(apiV1Group, secret)
|
s.registerAuthRoutes(apiV1Group, secret)
|
||||||
s.registerUserRoutes(apiV1Group)
|
s.registerUserRoutes(apiV1Group)
|
||||||
|
@ -4,6 +4,7 @@ import "strings"
|
|||||||
|
|
||||||
var allowedMethodsWhenUnauthorized = map[string]bool{
|
var allowedMethodsWhenUnauthorized = map[string]bool{
|
||||||
"/slash.api.v2.WorkspaceService/GetWorkspaceProfile": true,
|
"/slash.api.v2.WorkspaceService/GetWorkspaceProfile": true,
|
||||||
|
"/slash.api.v2.WorkspaceService/GetWorkspaceSetting": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// isUnauthorizeAllowedMethod returns true if the method is allowed to be called when the user is not authorized.
|
// isUnauthorizeAllowedMethod returns true if the method is allowed to be called when the user is not authorized.
|
||||||
|
@ -74,7 +74,9 @@ func (s *WorkspaceService) GetWorkspaceSetting(ctx context.Context, _ *apiv2pb.G
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "failed to list workspace settings: %v", err)
|
return nil, status.Errorf(codes.Internal, "failed to list workspace settings: %v", err)
|
||||||
}
|
}
|
||||||
workspaceSetting := &apiv2pb.WorkspaceSetting{}
|
workspaceSetting := &apiv2pb.WorkspaceSetting{
|
||||||
|
EnableSignup: true,
|
||||||
|
}
|
||||||
for _, v := range workspaceSettings {
|
for _, v := range workspaceSettings {
|
||||||
if v.Key == storepb.WorkspaceSettingKey_WORKSAPCE_SETTING_ENABLE_SIGNUP {
|
if v.Key == storepb.WorkspaceSettingKey_WORKSAPCE_SETTING_ENABLE_SIGNUP {
|
||||||
workspaceSetting.EnableSignup = v.GetEnableSignup()
|
workspaceSetting.EnableSignup = v.GetEnableSignup()
|
||||||
@ -86,8 +88,6 @@ func (s *WorkspaceService) GetWorkspaceSetting(ctx context.Context, _ *apiv2pb.G
|
|||||||
// For some settings, only admin can get the value.
|
// For some settings, only admin can get the value.
|
||||||
if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_LICENSE_KEY {
|
if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_LICENSE_KEY {
|
||||||
workspaceSetting.LicenseKey = v.GetLicenseKey()
|
workspaceSetting.LicenseKey = v.GetLicenseKey()
|
||||||
} else if v.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_RESOURCE_RELATIVE_PATH {
|
|
||||||
workspaceSetting.ResourceRelativePath = v.GetResourceRelativePath()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,20 +120,7 @@ func (s *WorkspaceService) UpdateWorkspaceSetting(ctx context.Context, request *
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err)
|
return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err)
|
||||||
}
|
}
|
||||||
} else if path == "resource_relative_path" {
|
|
||||||
if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
|
|
||||||
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_RESOURCE_RELATIVE_PATH,
|
|
||||||
Value: &storepb.WorkspaceSetting_ResourceRelativePath{
|
|
||||||
ResourceRelativePath: request.Setting.ResourceRelativePath,
|
|
||||||
},
|
|
||||||
}); err != nil {
|
|
||||||
return nil, status.Errorf(codes.Internal, "failed to update workspace setting: %v", err)
|
|
||||||
}
|
|
||||||
} else if path == "custom_style" {
|
} else if path == "custom_style" {
|
||||||
if !s.LicenseService.IsFeatureEnabled(license.FeatureTypeCustomeStyle) {
|
|
||||||
return nil, status.Errorf(codes.PermissionDenied, "feature custom style is not available")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
|
if _, err := s.Store.UpsertWorkspaceSetting(ctx, &storepb.WorkspaceSetting{
|
||||||
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE,
|
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE,
|
||||||
Value: &storepb.WorkspaceSetting_CustomStyle{
|
Value: &storepb.WorkspaceSetting_CustomStyle{
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
"github.com/boojack/slash/internal/log"
|
"github.com/boojack/slash/internal/log"
|
||||||
"github.com/boojack/slash/server"
|
"github.com/boojack/slash/server"
|
||||||
|
"github.com/boojack/slash/server/metric"
|
||||||
"github.com/boojack/slash/server/profile"
|
"github.com/boojack/slash/server/profile"
|
||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
"github.com/boojack/slash/store/db"
|
"github.com/boojack/slash/store/db"
|
||||||
@ -50,6 +51,9 @@ var (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
|
metric.NewMetricClient(s.Secret, *serverProfile)
|
||||||
|
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
// Trigger graceful shutdown on SIGINT or SIGTERM.
|
// Trigger graceful shutdown on SIGINT or SIGTERM.
|
||||||
// The default signal sent by the `kill` command is SIGTERM,
|
// The default signal sent by the `kill` command is SIGTERM,
|
@ -8,7 +8,7 @@ Slash provides a browser extension to help you use your shortcuts in the search
|
|||||||
|
|
||||||
For Chromuim based browsers, you can install the extension from the [Chrome Web Store](https://chrome.google.com/webstore/detail/slash/ebaiehmkammnacjadffpicipfckgeobg).
|
For Chromuim based browsers, you can install the extension from the [Chrome Web Store](https://chrome.google.com/webstore/detail/slash/ebaiehmkammnacjadffpicipfckgeobg).
|
||||||
|
|
||||||
For Firefox, we don't support the Firefox Add-ons platform yet. And we are working on it.
|
For Firefox, you can install the extension from the [Firefox Add-ons](https://addons.mozilla.org/en-US/firefox/addon/your-slash/).
|
||||||
|
|
||||||
### Generate an access token
|
### Generate an access token
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 257 KiB |
@ -1,21 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "slash-extension",
|
"name": "slash-extension",
|
||||||
"displayName": "Slash",
|
"displayName": "Slash",
|
||||||
"version": "0.1.4",
|
"version": "1.0.0",
|
||||||
"description": "An open source, self-hosted bookmarks and link sharing platform. Save and share your links very easily.",
|
"description": "An open source, self-hosted bookmarks and link sharing platform. Save and share your links very easily.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "plasmo dev",
|
"dev": "plasmo dev",
|
||||||
"build": "plasmo build",
|
"build": "plasmo build",
|
||||||
"package": "plasmo package",
|
"package": "plasmo package",
|
||||||
"lint": "eslint --ext .js,.ts,.tsx, src",
|
"lint": "eslint --ext .js,.ts,.tsx, src",
|
||||||
"lint-fix": "eslint --ext .js,.ts,.tsx, src --fix"
|
"lint-fix": "eslint --ext .js,.ts,.tsx, src --fix",
|
||||||
|
"type-gen": "cd ../../proto && buf generate"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.1",
|
"@emotion/react": "^11.11.1",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@mui/joy": "5.0.0-beta.0",
|
"@mui/joy": "5.0.0-beta.0",
|
||||||
"@plasmohq/storage": "^1.8.0",
|
"@plasmohq/storage": "^1.8.1",
|
||||||
"axios": "^1.5.0",
|
"axios": "^1.5.1",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"lucide-react": "^0.264.0",
|
"lucide-react": "^0.264.0",
|
||||||
@ -23,24 +24,25 @@
|
|||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-hot-toast": "^2.4.1",
|
"react-hot-toast": "^2.4.1",
|
||||||
"zustand": "^4.4.1"
|
"zustand": "^4.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@bufbuild/buf": "^1.27.0",
|
||||||
"@trivago/prettier-plugin-sort-imports": "4.1.0",
|
"@trivago/prettier-plugin-sort-imports": "4.1.0",
|
||||||
"@types/chrome": "0.0.241",
|
"@types/chrome": "0.0.241",
|
||||||
"@types/lodash-es": "^4.17.9",
|
"@types/lodash-es": "^4.17.9",
|
||||||
"@types/node": "20.4.2",
|
"@types/node": "20.4.2",
|
||||||
"@types/react": "18.2.15",
|
"@types/react": "18.2.15",
|
||||||
"@types/react-dom": "18.2.7",
|
"@types/react-dom": "18.2.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.7.0",
|
"@typescript-eslint/eslint-plugin": "^6.8.0",
|
||||||
"@typescript-eslint/parser": "^6.7.0",
|
"@typescript-eslint/parser": "^6.8.0",
|
||||||
"autoprefixer": "^10.4.15",
|
"autoprefixer": "^10.4.16",
|
||||||
"eslint": "^8.49.0",
|
"eslint": "^8.51.0",
|
||||||
"eslint-config-prettier": "^8.10.0",
|
"eslint-config-prettier": "^8.10.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.33.2",
|
||||||
"long": "^5.2.3",
|
"long": "^5.2.3",
|
||||||
"postcss": "^8.4.29",
|
"postcss": "^8.4.31",
|
||||||
"prettier": "2.6.2",
|
"prettier": "2.6.2",
|
||||||
"protobufjs": "^7.2.5",
|
"protobufjs": "^7.2.5",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
|
983
frontend/extension/pnpm-lock.yaml
generated
@ -1,8 +1,7 @@
|
|||||||
import type { Shortcut } from "@/types/proto/api/v2/shortcut_service";
|
import type { Shortcut } from "@/types/proto/api/v2/shortcut_service";
|
||||||
import { useStorage } from "@plasmohq/storage/hook";
|
import { useStorage } from "@plasmohq/storage/hook";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { useEffect, useState } from "react";
|
import { getFaviconWithGoogleS2 } from "@/helpers/utils";
|
||||||
import useFaviconStore from "../stores/favicon";
|
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -11,17 +10,8 @@ interface Props {
|
|||||||
|
|
||||||
const ShortcutView = (props: Props) => {
|
const ShortcutView = (props: Props) => {
|
||||||
const { shortcut } = props;
|
const { shortcut } = props;
|
||||||
const faviconStore = useFaviconStore();
|
|
||||||
const [domain] = useStorage<string>("domain", "");
|
const [domain] = useStorage<string>("domain", "");
|
||||||
const [favicon, setFavicon] = useState<string | undefined>(undefined);
|
const favicon = getFaviconWithGoogleS2(shortcut.link);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
faviconStore.getOrFetchUrlFavicon(shortcut.link).then((url) => {
|
|
||||||
if (url) {
|
|
||||||
setFavicon(url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [shortcut.link]);
|
|
||||||
|
|
||||||
const handleShortcutLinkClick = () => {
|
const handleShortcutLinkClick = () => {
|
||||||
const shortcutLink = `${domain}/s/${shortcut.name}`;
|
const shortcutLink = `${domain}/s/${shortcut.name}`;
|
||||||
@ -32,7 +22,7 @@ const ShortcutView = (props: Props) => {
|
|||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"group w-full px-3 py-2 flex flex-col justify-start items-start border rounded-lg hover:bg-gray-100 hover:shadow"
|
"group w-full px-3 py-2 flex flex-col justify-start items-start border rounded-lg hover:bg-gray-100 hover:shadow dark:border-zinc-800 dark:hover:bg-zinc-800"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="w-full flex flex-row justify-start items-center">
|
<div className="w-full flex flex-row justify-start items-center">
|
||||||
@ -52,13 +42,13 @@ const ShortcutView = (props: Props) => {
|
|||||||
onClick={handleShortcutLinkClick}
|
onClick={handleShortcutLinkClick}
|
||||||
>
|
>
|
||||||
<div className="truncate">
|
<div className="truncate">
|
||||||
<span>{shortcut.title}</span>
|
<span className="dark:text-gray-400">{shortcut.title}</span>
|
||||||
{shortcut.title ? (
|
{shortcut.title ? (
|
||||||
<span className="text-gray-400">(s/{shortcut.name})</span>
|
<span className="text-gray-500">(s/{shortcut.name})</span>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<span className="text-gray-400">s/</span>
|
<span className="text-gray-400 dark:text-gray-500">s/</span>
|
||||||
<span className="truncate">{shortcut.name}</span>
|
<span className="truncate dark:text-gray-400">{shortcut.name}</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import { Storage } from "@plasmohq/storage";
|
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const storage = new Storage();
|
|
||||||
|
|
||||||
export const getUrlFavicon = async (url: string) => {
|
|
||||||
const domain = await storage.getItem<string>("domain");
|
|
||||||
const accessToken = await storage.getItem<string>("access_token");
|
|
||||||
return axios.get<string>(`${domain}/api/v1/url/favicon?url=${url}`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${accessToken}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
@ -3,3 +3,12 @@ import { isNull, isUndefined } from "lodash-es";
|
|||||||
export const isNullorUndefined = (value: any) => {
|
export const isNullorUndefined = (value: any) => {
|
||||||
return isNull(value) || isUndefined(value);
|
return isNull(value) || isUndefined(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getFaviconWithGoogleS2 = (url: string) => {
|
||||||
|
try {
|
||||||
|
const urlObject = new URL(url);
|
||||||
|
return `https://www.google.com/s2/favicons?sz=128&domain=${urlObject.hostname}`;
|
||||||
|
} catch (error) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
43
frontend/extension/src/hooks/useColorTheme.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { useColorScheme } from "@mui/joy";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
const useColorTheme = () => {
|
||||||
|
const { mode: colorTheme, setMode: setColorTheme } = useColorScheme();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const root = document.documentElement;
|
||||||
|
if (colorTheme === "light") {
|
||||||
|
root.classList.remove("dark");
|
||||||
|
} else if (colorTheme === "dark") {
|
||||||
|
root.classList.add("dark");
|
||||||
|
} else {
|
||||||
|
const darkMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||||
|
if (darkMediaQuery.matches) {
|
||||||
|
root.classList.add("dark");
|
||||||
|
} else {
|
||||||
|
root.classList.remove("dark");
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleColorSchemeChange = (e: MediaQueryListEvent) => {
|
||||||
|
if (e.matches) {
|
||||||
|
root.classList.add("dark");
|
||||||
|
} else {
|
||||||
|
root.classList.remove("dark");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
darkMediaQuery.addEventListener("change", handleColorSchemeChange);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("failed to initial color scheme listener", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
darkMediaQuery.removeEventListener("change", handleColorSchemeChange);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [colorTheme]);
|
||||||
|
|
||||||
|
return { colorTheme, setColorTheme };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useColorTheme;
|
@ -1,5 +1,5 @@
|
|||||||
import type { Shortcut } from "@/types/proto/api/v2/shortcut_service";
|
import type { Shortcut } from "@/types/proto/api/v2/shortcut_service";
|
||||||
import { Button, Divider, Input } from "@mui/joy";
|
import { Button, CssVarsProvider, Divider, Input, Select, Option } from "@mui/joy";
|
||||||
import { useStorage } from "@plasmohq/storage/hook";
|
import { useStorage } from "@plasmohq/storage/hook";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Toaster, toast } from "react-hot-toast";
|
import { Toaster, toast } from "react-hot-toast";
|
||||||
@ -7,6 +7,7 @@ import Icon from "./components/Icon";
|
|||||||
import Logo from "./components/Logo";
|
import Logo from "./components/Logo";
|
||||||
import PullShortcutsButton from "./components/PullShortcutsButton";
|
import PullShortcutsButton from "./components/PullShortcutsButton";
|
||||||
import ShortcutsContainer from "./components/ShortcutsContainer";
|
import ShortcutsContainer from "./components/ShortcutsContainer";
|
||||||
|
import useColorTheme from "./hooks/useColorTheme";
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
interface SettingState {
|
interface SettingState {
|
||||||
@ -14,7 +15,23 @@ interface SettingState {
|
|||||||
accessToken: string;
|
accessToken: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const colorThemeOptions = [
|
||||||
|
{
|
||||||
|
value: "system",
|
||||||
|
label: "System",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "light",
|
||||||
|
label: "Light",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "dark",
|
||||||
|
label: "Dark",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const IndexOptions = () => {
|
const IndexOptions = () => {
|
||||||
|
const { colorTheme, setColorTheme } = useColorTheme();
|
||||||
const [domain, setDomain] = useStorage<string>("domain", (v) => (v ? v : ""));
|
const [domain, setDomain] = useStorage<string>("domain", (v) => (v ? v : ""));
|
||||||
const [accessToken, setAccessToken] = useStorage<string>("access_token", (v) => (v ? v : ""));
|
const [accessToken, setAccessToken] = useStorage<string>("access_token", (v) => (v ? v : ""));
|
||||||
const [settingState, setSettingState] = useState<SettingState>({
|
const [settingState, setSettingState] = useState<SettingState>({
|
||||||
@ -44,91 +61,119 @@ const IndexOptions = () => {
|
|||||||
toast.success("Setting saved");
|
toast.success("Setting saved");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSelectColorTheme = async (colorTheme: string) => {
|
||||||
|
setColorTheme(colorTheme as any);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="w-full">
|
||||||
<div className="w-full">
|
<div className="w-full flex flex-row justify-center items-center">
|
||||||
<div className="w-full flex flex-row justify-center items-center">
|
<a
|
||||||
<a
|
className="bg-yellow-100 dark:bg-yellow-500 dark:opacity-70 mt-12 py-2 px-3 rounded-full border dark:border-yellow-600 flex flex-row justify-start items-center cursor-pointer shadow hover:underline hover:text-blue-600"
|
||||||
className="bg-yellow-100 mt-12 py-2 px-3 rounded-full border flex flex-row justify-start items-center cursor-pointer shadow hover:underline hover:text-blue-600"
|
href="https://github.com/boojack/slash#browser-extension"
|
||||||
href="https://github.com/boojack/slash#browser-extension"
|
target="_blank"
|
||||||
target="_blank"
|
>
|
||||||
>
|
<Icon.HelpCircle className="w-4 h-auto" />
|
||||||
<Icon.HelpCircle className="w-4 h-auto" />
|
<span className="mx-1 text-sm">Need help? Check out the docs</span>
|
||||||
<span className="mx-1 text-sm">Need help? Check out the docs</span>
|
<Icon.ExternalLink className="w-4 h-auto" />
|
||||||
<Icon.ExternalLink className="w-4 h-auto" />
|
</a>
|
||||||
</a>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-full max-w-lg mx-auto flex flex-col justify-start items-start mt-12">
|
<div className="w-full max-w-lg mx-auto flex flex-col justify-start items-start mt-12">
|
||||||
<h2 className="flex flex-row justify-start items-center mb-6 text-2xl">
|
<h2 className="flex flex-row justify-start items-center mb-6 text-2xl dark:text-gray-400">
|
||||||
<Logo className="w-10 h-auto mr-2" />
|
<Logo className="w-10 h-auto mr-2" />
|
||||||
<span>Slash</span>
|
<span>Slash</span>
|
||||||
<span className="mx-2 text-gray-400">/</span>
|
<span className="mx-2 text-gray-400">/</span>
|
||||||
<span>Setting</span>
|
<span>Setting</span>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div className="w-full flex flex-col justify-start items-start">
|
<div className="w-full flex flex-col justify-start items-start">
|
||||||
<div className="w-full flex flex-col justify-start items-start mb-4">
|
<div className="w-full flex flex-col justify-start items-start mb-4">
|
||||||
<div className="mb-2 text-base w-full flex flex-row justify-between items-center">
|
<div className="mb-2 text-base w-full flex flex-row justify-between items-center">
|
||||||
<span>Domain</span>
|
<span className="dark:text-gray-400">Domain</span>
|
||||||
{domain !== "" && (
|
{domain !== "" && (
|
||||||
<a
|
<a
|
||||||
className="text-sm flex flex-row justify-start items-center hover:underline hover:text-blue-600"
|
className="text-sm flex flex-row justify-start items-center dark:text-gray-400 hover:underline hover:text-blue-600"
|
||||||
href={domain}
|
href={domain}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<span className="mr-1">Go to my Slash</span>
|
<span className="mr-1">Go to my Slash</span>
|
||||||
<Icon.ExternalLink className="w-4 h-auto" />
|
<Icon.ExternalLink className="w-4 h-auto" />
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
<div className="relative w-full">
|
|
||||||
<Input
|
|
||||||
className="w-full"
|
|
||||||
type="text"
|
|
||||||
placeholder="The domain of your Slash instance"
|
|
||||||
value={settingState.domain}
|
|
||||||
onChange={(e) => setPartialSettingState({ domain: e.target.value })}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="relative w-full">
|
||||||
<div className="w-full flex flex-col justify-start items-start">
|
<Input
|
||||||
<span className="mb-2 text-base">Access Token</span>
|
className="w-full"
|
||||||
<div className="relative w-full">
|
type="text"
|
||||||
<Input
|
placeholder="The domain of your Slash instance"
|
||||||
className="w-full"
|
value={settingState.domain}
|
||||||
type="text"
|
onChange={(e) => setPartialSettingState({ domain: e.target.value })}
|
||||||
placeholder="The access token of your Slash instance"
|
/>
|
||||||
value={settingState.accessToken}
|
|
||||||
onChange={(e) => setPartialSettingState({ accessToken: e.target.value })}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-full mt-6">
|
|
||||||
<Button onClick={handleSaveSetting}>Save</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isInitialized && (
|
<div className="w-full flex flex-col justify-start items-start">
|
||||||
<>
|
<span className="mb-2 text-base dark:text-gray-400">Access Token</span>
|
||||||
<Divider className="!my-6" />
|
<div className="relative w-full">
|
||||||
|
<Input
|
||||||
|
className="w-full"
|
||||||
|
type="text"
|
||||||
|
placeholder="The access token of your Slash instance"
|
||||||
|
value={settingState.accessToken}
|
||||||
|
onChange={(e) => setPartialSettingState({ accessToken: e.target.value })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h2 className="flex flex-row justify-start items-center mb-4">
|
<div className="w-full mt-6 flex flex-row justify-end">
|
||||||
<span className="text-lg">Shortcuts</span>
|
<Button onClick={handleSaveSetting}>Save</Button>
|
||||||
<span className="text-gray-500 mr-1">({shortcuts.length})</span>
|
</div>
|
||||||
<PullShortcutsButton />
|
|
||||||
</h2>
|
<Divider className="!my-6" />
|
||||||
<ShortcutsContainer />
|
|
||||||
</>
|
<p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Preference</p>
|
||||||
)}
|
|
||||||
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
|
<div className="flex flex-row justify-start items-center gap-x-1">
|
||||||
|
<span className="dark:text-gray-400">Color Theme</span>
|
||||||
|
</div>
|
||||||
|
<Select defaultValue={colorTheme} onChange={(_, value) => handleSelectColorTheme(value)}>
|
||||||
|
{colorThemeOptions.map((option) => {
|
||||||
|
return (
|
||||||
|
<Option key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</Option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<Toaster position="top-center" />
|
{isInitialized && (
|
||||||
</>
|
<>
|
||||||
|
<Divider className="!my-6" />
|
||||||
|
|
||||||
|
<h2 className="flex flex-row justify-start items-center mb-4">
|
||||||
|
<span className="text-lg dark:text-gray-400">Shortcuts</span>
|
||||||
|
<span className="text-gray-500 mr-1">({shortcuts.length})</span>
|
||||||
|
<PullShortcutsButton />
|
||||||
|
</h2>
|
||||||
|
<ShortcutsContainer />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default IndexOptions;
|
const Options = () => {
|
||||||
|
return (
|
||||||
|
<CssVarsProvider>
|
||||||
|
<IndexOptions />
|
||||||
|
<Toaster position="top-right" />
|
||||||
|
</CssVarsProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Options;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { Shortcut } from "@/types/proto/api/v2/shortcut_service";
|
import type { Shortcut } from "@/types/proto/api/v2/shortcut_service";
|
||||||
import { Button, Divider, IconButton } from "@mui/joy";
|
import { Button, CssVarsProvider, Divider, IconButton } from "@mui/joy";
|
||||||
import { useStorage } from "@plasmohq/storage/hook";
|
import { useStorage } from "@plasmohq/storage/hook";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
import CreateShortcutsButton from "@/components/CreateShortcutsButton";
|
import CreateShortcutsButton from "@/components/CreateShortcutsButton";
|
||||||
@ -7,9 +7,11 @@ import Icon from "@/components/Icon";
|
|||||||
import Logo from "@/components/Logo";
|
import Logo from "@/components/Logo";
|
||||||
import PullShortcutsButton from "@/components/PullShortcutsButton";
|
import PullShortcutsButton from "@/components/PullShortcutsButton";
|
||||||
import ShortcutsContainer from "@/components/ShortcutsContainer";
|
import ShortcutsContainer from "@/components/ShortcutsContainer";
|
||||||
|
import useColorTheme from "./hooks/useColorTheme";
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
const IndexPopup = () => {
|
const IndexPopup = () => {
|
||||||
|
useColorTheme();
|
||||||
const [domain] = useStorage<string>("domain", "");
|
const [domain] = useStorage<string>("domain", "");
|
||||||
const [accessToken] = useStorage<string>("access_token", "");
|
const [accessToken] = useStorage<string>("access_token", "");
|
||||||
const [shortcuts] = useStorage<Shortcut[]>("shortcuts", []);
|
const [shortcuts] = useStorage<Shortcut[]>("shortcuts", []);
|
||||||
@ -25,85 +27,84 @@ const IndexPopup = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="w-full min-w-[512px] px-4 pt-4">
|
||||||
<div className="w-full min-w-[512px] px-4 pt-4">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="flex flex-row justify-start items-center dark:text-gray-400">
|
||||||
<div className="flex flex-row justify-start items-center">
|
<Logo className="w-6 h-auto mr-2" />
|
||||||
<Logo className="w-6 h-auto mr-2" />
|
<span className="">Slash</span>
|
||||||
<span className="">Slash</span>
|
{isInitialized && (
|
||||||
{isInitialized && (
|
|
||||||
<>
|
|
||||||
<span className="mx-1 text-gray-400">/</span>
|
|
||||||
<span>Shortcuts</span>
|
|
||||||
<span className="text-gray-500 mr-0.5">({shortcuts.length})</span>
|
|
||||||
<PullShortcutsButton />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div>{isInitialized && <CreateShortcutsButton />}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-full mt-4">
|
|
||||||
{isInitialized ? (
|
|
||||||
<>
|
<>
|
||||||
{shortcuts.length !== 0 ? (
|
<span className="mx-1 text-gray-400">/</span>
|
||||||
<ShortcutsContainer />
|
<span>Shortcuts</span>
|
||||||
) : (
|
<span className="text-gray-500 mr-0.5">({shortcuts.length})</span>
|
||||||
<div className="w-full flex flex-col justify-center items-center">
|
<PullShortcutsButton />
|
||||||
<p>No shortcut found.</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Divider className="!mt-4 !mb-2 opacity-40" />
|
|
||||||
|
|
||||||
<div className="w-full flex flex-row justify-between items-center mb-2">
|
|
||||||
<div className="flex flex-row justify-start items-center">
|
|
||||||
<IconButton size="sm" variant="plain" color="neutral" onClick={handleSettingButtonClick}>
|
|
||||||
<Icon.Settings className="w-5 h-auto text-gray-500" />
|
|
||||||
</IconButton>
|
|
||||||
<IconButton
|
|
||||||
size="sm"
|
|
||||||
variant="plain"
|
|
||||||
color="neutral"
|
|
||||||
component="a"
|
|
||||||
href="https://github.com/boojack/slash"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<Icon.Github className="w-5 h-auto text-gray-500" />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row justify-end items-center">
|
|
||||||
<a
|
|
||||||
className="text-sm flex flex-row justify-start items-center text-gray-500 hover:underline hover:text-blue-600"
|
|
||||||
href={domain}
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<span className="mr-1">Go to my Slash</span>
|
|
||||||
<Icon.ExternalLink className="w-4 h-auto" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
|
||||||
<div className="w-full flex flex-col justify-start items-center">
|
|
||||||
<p>No domain and access token found.</p>
|
|
||||||
<div className="w-full flex flex-row justify-center items-center py-4">
|
|
||||||
<Button size="sm" color="primary" onClick={handleSettingButtonClick}>
|
|
||||||
<Icon.Settings className="w-5 h-auto mr-1" /> Setting
|
|
||||||
</Button>
|
|
||||||
<span className="mx-2">Or</span>
|
|
||||||
<Button size="sm" variant="outlined" color="neutral" onClick={handleRefreshButtonClick}>
|
|
||||||
<Icon.RefreshCcw className="w-5 h-auto mr-1" /> Refresh
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div>{isInitialized && <CreateShortcutsButton />}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Toaster position="top-right" />
|
<div className="w-full mt-4">
|
||||||
</>
|
{isInitialized ? (
|
||||||
|
<>
|
||||||
|
{shortcuts.length !== 0 ? (
|
||||||
|
<ShortcutsContainer />
|
||||||
|
) : (
|
||||||
|
<div className="w-full flex flex-col justify-center items-center">
|
||||||
|
<p>No shortcut found.</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Divider className="!mt-4 !mb-2 opacity-40" />
|
||||||
|
|
||||||
|
<div className="w-full flex flex-row justify-between items-center mb-2">
|
||||||
|
<div className="flex flex-row justify-start items-center">
|
||||||
|
<IconButton size="sm" variant="plain" color="neutral" onClick={handleSettingButtonClick}>
|
||||||
|
<Icon.Settings className="w-5 h-auto text-gray-500 dark:text-gray-400" />
|
||||||
|
</IconButton>
|
||||||
|
<IconButton size="sm" variant="plain" color="neutral" component="a" href="https://github.com/boojack/slash" target="_blank">
|
||||||
|
<Icon.Github className="w-5 h-auto text-gray-500 dark:text-gray-400" />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row justify-end items-center">
|
||||||
|
<a
|
||||||
|
className="text-sm flex flex-row justify-start items-center text-gray-500 dark:text-gray-400 hover:underline hover:text-blue-600"
|
||||||
|
href={domain}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span className="mr-1">Go to my Slash</span>
|
||||||
|
<Icon.ExternalLink className="w-4 h-auto" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="w-full flex flex-col justify-start items-center">
|
||||||
|
<Icon.Cookie strokeWidth={1} className="w-20 h-auto mb-4 text-gray-400" />
|
||||||
|
<p className="dark:text-gray-400">Please set your domain and access token first.</p>
|
||||||
|
<div className="w-full flex flex-row justify-center items-center py-4">
|
||||||
|
<Button size="sm" color="primary" onClick={handleSettingButtonClick}>
|
||||||
|
<Icon.Settings className="w-5 h-auto mr-1" /> Setting
|
||||||
|
</Button>
|
||||||
|
<span className="mx-2 dark:text-gray-400">Or</span>
|
||||||
|
<Button size="sm" variant="outlined" color="neutral" onClick={handleRefreshButtonClick}>
|
||||||
|
<Icon.RefreshCcw className="w-5 h-auto mr-1" /> Refresh
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default IndexPopup;
|
const Popup = () => {
|
||||||
|
return (
|
||||||
|
<CssVarsProvider>
|
||||||
|
<IndexPopup />
|
||||||
|
<Toaster position="top-right" />
|
||||||
|
</CssVarsProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Popup;
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
import { create } from "zustand";
|
|
||||||
import { persist } from "zustand/middleware";
|
|
||||||
import { getUrlFavicon } from "../helpers/api";
|
|
||||||
|
|
||||||
interface FaviconState {
|
|
||||||
cache: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
getOrFetchUrlFavicon: (url: string) => Promise<string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const useFaviconStore = create<FaviconState>()(
|
|
||||||
persist(
|
|
||||||
(set, get) => ({
|
|
||||||
cache: {},
|
|
||||||
getOrFetchUrlFavicon: async (url: string) => {
|
|
||||||
const cache = get().cache;
|
|
||||||
if (cache[url]) {
|
|
||||||
return cache[url];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { data: favicon } = await getUrlFavicon(url);
|
|
||||||
if (favicon) {
|
|
||||||
cache[url] = favicon;
|
|
||||||
set(cache);
|
|
||||||
return favicon;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: "favicon_cache",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
export default useFaviconStore;
|
|
@ -5,7 +5,7 @@
|
|||||||
body,
|
body,
|
||||||
html,
|
html,
|
||||||
#root {
|
#root {
|
||||||
@apply text-base;
|
@apply text-base dark:bg-zinc-900;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Noto Sans", "Noto Sans CJK SC", "Microsoft YaHei UI", "Microsoft YaHei",
|
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Noto Sans", "Noto Sans CJK SC", "Microsoft YaHei UI", "Microsoft YaHei",
|
||||||
"WenQuanYi Micro Hei", sans-serif, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
"WenQuanYi Micro Hei", sans-serif, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||||
"Noto Color Emoji";
|
"Noto Color Emoji";
|
||||||
|
@ -11,7 +11,14 @@
|
|||||||
"language": "Language",
|
"language": "Language",
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
"password": "Password"
|
"password": "Password",
|
||||||
|
"account": "Account"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"sign-in": "Sign in",
|
||||||
|
"sign-up": "Sign up",
|
||||||
|
"sign-out": "Sign out",
|
||||||
|
"create-your-account": "Create your account"
|
||||||
},
|
},
|
||||||
"analytics": {
|
"analytics": {
|
||||||
"self": "Analytics",
|
"self": "Analytics",
|
||||||
@ -24,6 +31,7 @@
|
|||||||
"operating-system": "Operating System"
|
"operating-system": "Operating System"
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
|
"visits": "{{count}} visits",
|
||||||
"visibility": {
|
"visibility": {
|
||||||
"private": {
|
"private": {
|
||||||
"self": "Private",
|
"self": "Private",
|
||||||
@ -38,5 +46,37 @@
|
|||||||
"description": "Visible to everyone on the internet"
|
"description": "Visible to everyone on the internet"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"filter": {
|
||||||
|
"all": "All",
|
||||||
|
"mine": "Mine",
|
||||||
|
"compact-mode": "Compact mode",
|
||||||
|
"order-by": "Order by",
|
||||||
|
"direction": "Direction"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"self": "User",
|
||||||
|
"nickname": "Nickname",
|
||||||
|
"email": "Email",
|
||||||
|
"role": "Role",
|
||||||
|
"profile": "Profile",
|
||||||
|
"action": {
|
||||||
|
"add-user": "Add user"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"self": "Setting",
|
||||||
|
"preference": {
|
||||||
|
"self": "Preference",
|
||||||
|
"color-theme": "Color theme"
|
||||||
|
},
|
||||||
|
"workspace": {
|
||||||
|
"self": "Workspace settings",
|
||||||
|
"custom-style": "Custom style",
|
||||||
|
"enable-user-signup": {
|
||||||
|
"self": "Enable user signup",
|
||||||
|
"description": "Once enabled, other users can signup."
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,14 @@
|
|||||||
"language": "语言",
|
"language": "语言",
|
||||||
"search": "搜索",
|
"search": "搜索",
|
||||||
"email": "邮箱",
|
"email": "邮箱",
|
||||||
"password": "密码"
|
"password": "密码",
|
||||||
|
"account": "账号"
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"sign-in": "登录",
|
||||||
|
"sign-up": "注册",
|
||||||
|
"sign-out": "退出登录",
|
||||||
|
"create-your-account": "创建账号"
|
||||||
},
|
},
|
||||||
"analytics": {
|
"analytics": {
|
||||||
"self": "分析",
|
"self": "分析",
|
||||||
@ -24,6 +31,7 @@
|
|||||||
"operating-system": "操作系统"
|
"operating-system": "操作系统"
|
||||||
},
|
},
|
||||||
"shortcut": {
|
"shortcut": {
|
||||||
|
"visits": "{{count}} 次访问",
|
||||||
"visibility": {
|
"visibility": {
|
||||||
"private": {
|
"private": {
|
||||||
"self": "私有的",
|
"self": "私有的",
|
||||||
@ -38,5 +46,37 @@
|
|||||||
"description": "对任何人可见"
|
"description": "对任何人可见"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"filter": {
|
||||||
|
"all": "所有",
|
||||||
|
"mine": "我的",
|
||||||
|
"compact-mode": "紧凑模式",
|
||||||
|
"order-by": "排序方式",
|
||||||
|
"direction": "方向"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"self": "用户",
|
||||||
|
"nickname": "昵称",
|
||||||
|
"email": "邮箱",
|
||||||
|
"role": "角色",
|
||||||
|
"profile": "账号",
|
||||||
|
"action": {
|
||||||
|
"add-user": "添加用户"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"self": "设置",
|
||||||
|
"preference": {
|
||||||
|
"self": "偏好设置",
|
||||||
|
"color-theme": "主题"
|
||||||
|
},
|
||||||
|
"workspace": {
|
||||||
|
"self": "系统设置",
|
||||||
|
"custom-style": "自定义样式",
|
||||||
|
"enable-user-signup": {
|
||||||
|
"self": "启用用户注册",
|
||||||
|
"description": "允许其他用户注册新账号"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,14 @@
|
|||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"serve": "vite preview",
|
"serve": "vite preview",
|
||||||
"lint": "eslint --ext .js,.ts,.tsx, src",
|
"lint": "eslint --ext .js,.ts,.tsx, src",
|
||||||
"lint-fix": "eslint --ext .js,.ts,.tsx, src --fix"
|
"lint-fix": "eslint --ext .js,.ts,.tsx, src --fix",
|
||||||
|
"type-gen": "cd ../../proto && buf generate"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.11.1",
|
"@emotion/react": "^11.11.1",
|
||||||
"@emotion/styled": "^11.11.0",
|
"@emotion/styled": "^11.11.0",
|
||||||
"@mui/joy": "5.0.0-beta.7",
|
"@mui/joy": "5.0.0-beta.7",
|
||||||
"@reduxjs/toolkit": "^1.9.5",
|
"@reduxjs/toolkit": "^1.9.7",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"copy-to-clipboard": "^3.3.3",
|
"copy-to-clipboard": "^3.3.3",
|
||||||
@ -24,31 +25,32 @@
|
|||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hot-toast": "^2.4.1",
|
"react-hot-toast": "^2.4.1",
|
||||||
"react-i18next": "^13.2.2",
|
"react-i18next": "^13.3.0",
|
||||||
"react-redux": "^8.1.2",
|
"react-redux": "^8.1.3",
|
||||||
"react-router-dom": "^6.16.0",
|
"react-router-dom": "^6.17.0",
|
||||||
"react-use": "^17.4.0",
|
"react-use": "^17.4.0",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"zustand": "^4.4.1"
|
"zustand": "^4.4.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@bufbuild/buf": "^1.27.0",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
|
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
|
||||||
"@types/lodash-es": "^4.17.9",
|
"@types/lodash-es": "^4.17.9",
|
||||||
"@types/react": "^18.2.22",
|
"@types/react": "^18.2.28",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.13",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.7.2",
|
"@typescript-eslint/eslint-plugin": "^6.8.0",
|
||||||
"@typescript-eslint/parser": "^6.7.2",
|
"@typescript-eslint/parser": "^6.8.0",
|
||||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
"@vitejs/plugin-react-swc": "^3.4.0",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"eslint": "^8.50.0",
|
"eslint": "^8.51.0",
|
||||||
"eslint-config-prettier": "^8.10.0",
|
"eslint-config-prettier": "^8.10.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.33.2",
|
||||||
"long": "^5.2.3",
|
"long": "^5.2.3",
|
||||||
"postcss": "^8.4.30",
|
"postcss": "^8.4.31",
|
||||||
"prettier": "2.6.2",
|
"prettier": "2.6.2",
|
||||||
"protobufjs": "^7.2.5",
|
"protobufjs": "^7.2.5",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^4.4.9"
|
"vite": "^4.4.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
749
frontend/web/pnpm-lock.yaml
generated
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 257 KiB |
@ -1,15 +1,17 @@
|
|||||||
import { Button, Divider, Input, Modal, ModalDialog, Radio, RadioGroup, Textarea } from "@mui/joy";
|
import { Button, Divider, Input, Modal, ModalDialog, Radio, RadioGroup, Textarea } from "@mui/joy";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
import { isUndefined } from "lodash-es";
|
import { isUndefined, uniq } from "lodash-es";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useAppSelector } from "@/stores";
|
||||||
import useLoading from "../hooks/useLoading";
|
import useLoading from "../hooks/useLoading";
|
||||||
import { shortcutService } from "../services";
|
import { shortcutService } from "../services";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
shortcutId?: ShortcutId;
|
shortcutId?: ShortcutId;
|
||||||
|
initialShortcut?: Partial<Shortcut>;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onConfirm?: () => void;
|
onConfirm?: () => void;
|
||||||
}
|
}
|
||||||
@ -21,8 +23,9 @@ interface State {
|
|||||||
const visibilities: Visibility[] = ["PRIVATE", "WORKSPACE", "PUBLIC"];
|
const visibilities: Visibility[] = ["PRIVATE", "WORKSPACE", "PUBLIC"];
|
||||||
|
|
||||||
const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
||||||
const { onClose, onConfirm, shortcutId } = props;
|
const { onClose, onConfirm, shortcutId, initialShortcut } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { shortcutList } = useAppSelector((state) => state.shortcut);
|
||||||
const [state, setState] = useState<State>({
|
const [state, setState] = useState<State>({
|
||||||
shortcutCreate: {
|
shortcutCreate: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -36,11 +39,13 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
|||||||
description: "",
|
description: "",
|
||||||
image: "",
|
image: "",
|
||||||
},
|
},
|
||||||
|
...initialShortcut,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const [showAdditionalFields, setShowAdditionalFields] = useState<boolean>(false);
|
const [showAdditionalFields, setShowAdditionalFields] = useState<boolean>(false);
|
||||||
const [showOpenGraphMetadata, setShowOpenGraphMetadata] = useState<boolean>(false);
|
const [showOpenGraphMetadata, setShowOpenGraphMetadata] = useState<boolean>(false);
|
||||||
const [tag, setTag] = useState<string>("");
|
const [tag, setTag] = useState<string>("");
|
||||||
|
const tagSuggestions = uniq(shortcutList.map((shortcut) => shortcut.tags).flat());
|
||||||
const requestState = useLoading(false);
|
const requestState = useLoading(false);
|
||||||
const isCreating = isUndefined(shortcutId);
|
const isCreating = isUndefined(shortcutId);
|
||||||
|
|
||||||
@ -149,6 +154,14 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleTagSuggestionsClick = (suggestion: string) => {
|
||||||
|
if (tag === "") {
|
||||||
|
setTag(suggestion);
|
||||||
|
} else {
|
||||||
|
setTag(`${tag} ${suggestion}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSaveBtnClick = async () => {
|
const handleSaveBtnClick = async () => {
|
||||||
if (!state.shortcutCreate.name) {
|
if (!state.shortcutCreate.name) {
|
||||||
toast.error("Name is required");
|
toast.error("Name is required");
|
||||||
@ -220,6 +233,22 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
|||||||
<div className="w-full flex flex-col justify-start items-start mb-3">
|
<div className="w-full flex flex-col justify-start items-start mb-3">
|
||||||
<span className="mb-2">Tags</span>
|
<span className="mb-2">Tags</span>
|
||||||
<Input className="w-full" type="text" placeholder="github slash" value={tag} onChange={handleTagsInputChange} />
|
<Input className="w-full" type="text" placeholder="github slash" value={tag} onChange={handleTagsInputChange} />
|
||||||
|
{tagSuggestions.length > 0 && (
|
||||||
|
<div className="w-full flex flex-row justify-start items-start mt-2">
|
||||||
|
<Icon.Asterisk className="w-4 h-auto shrink-0 mx-1 text-gray-400 dark:text-gray-600" />
|
||||||
|
<div className="w-auto flex flex-row justify-start items-start flex-wrap gap-x-2 gap-y-1">
|
||||||
|
{tagSuggestions.map((tag) => (
|
||||||
|
<span
|
||||||
|
className="text-gray-600 dark:text-gray-500 cursor-pointer max-w-[6rem] truncate block text-sm flex-nowrap leading-4 hover:text-black dark:hover:text-gray-400"
|
||||||
|
key={tag}
|
||||||
|
onClick={() => handleTagSuggestionsClick(tag)}
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-col justify-start items-start mb-3">
|
<div className="w-full flex flex-col justify-start items-start mb-3">
|
||||||
<span className="mb-2">Visibility</span>
|
<span className="mb-2">Visibility</span>
|
||||||
@ -283,10 +312,7 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
|||||||
)}
|
)}
|
||||||
onClick={() => setShowOpenGraphMetadata(!showOpenGraphMetadata)}
|
onClick={() => setShowOpenGraphMetadata(!showOpenGraphMetadata)}
|
||||||
>
|
>
|
||||||
<span className="text-sm flex flex-row justify-start items-center">
|
<span className="text-sm flex flex-row justify-start items-center">Social media metadata</span>
|
||||||
Social media metadata
|
|
||||||
<Icon.Sparkles className="ml-1 w-4 h-auto text-blue-600" />
|
|
||||||
</span>
|
|
||||||
<button className="w-7 h-7 p-1 rounded-md">
|
<button className="w-7 h-7 p-1 rounded-md">
|
||||||
<Icon.ChevronDown className={classnames("w-4 h-auto text-gray-500", showOpenGraphMetadata ? "transform rotate-180" : "")} />
|
<Icon.ChevronDown className={classnames("w-4 h-auto text-gray-500", showOpenGraphMetadata ? "transform rotate-180" : "")} />
|
||||||
</button>
|
</button>
|
||||||
|
@ -66,11 +66,11 @@ const EditUserinfoDialog: React.FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="w-full flex flex-col justify-start items-start mb-3">
|
<div className="w-full flex flex-col justify-start items-start mb-3">
|
||||||
<span className="mb-2">Email</span>
|
<span className="mb-2">{t("common.email")}</span>
|
||||||
<Input className="w-full" type="text" value={email} onChange={handleEmailChanged} />
|
<Input className="w-full" type="text" value={email} onChange={handleEmailChanged} />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-col justify-start items-start mb-3">
|
<div className="w-full flex flex-col justify-start items-start mb-3">
|
||||||
<span className="mb-2">Nickname</span>
|
<span className="mb-2">{t("user.nickname")}</span>
|
||||||
<Input className="w-full" type="text" value={nickname} onChange={handleNicknameChanged} />
|
<Input className="w-full" type="text" value={nickname} onChange={handleNicknameChanged} />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-row justify-end items-center space-x-2">
|
<div className="w-full flex flex-row justify-end items-center space-x-2">
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Avatar } from "@mui/joy";
|
import { Avatar } from "@mui/joy";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import useWorkspaceStore from "@/stores/v1/workspace";
|
import useWorkspaceStore from "@/stores/v1/workspace";
|
||||||
import { PlanType } from "@/types/proto/api/v2/subscription_service";
|
import { PlanType } from "@/types/proto/api/v2/subscription_service";
|
||||||
@ -10,6 +11,7 @@ import Icon from "./Icon";
|
|||||||
import Dropdown from "./common/Dropdown";
|
import Dropdown from "./common/Dropdown";
|
||||||
|
|
||||||
const Header: React.FC = () => {
|
const Header: React.FC = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const workspaceStore = useWorkspaceStore();
|
const workspaceStore = useWorkspaceStore();
|
||||||
const currentUser = useUserStore().getCurrentUser();
|
const currentUser = useUserStore().getCurrentUser();
|
||||||
const [showAboutDialog, setShowAboutDialog] = useState<boolean>(false);
|
const [showAboutDialog, setShowAboutDialog] = useState<boolean>(false);
|
||||||
@ -27,7 +29,7 @@ const Header: React.FC = () => {
|
|||||||
<div className="w-full max-w-6xl mx-auto px-3 md:px-12 py-5 flex flex-row justify-between items-center">
|
<div className="w-full max-w-6xl mx-auto px-3 md:px-12 py-5 flex flex-row justify-between items-center">
|
||||||
<div className="flex flex-row justify-start items-center shrink mr-2">
|
<div className="flex flex-row justify-start items-center shrink mr-2">
|
||||||
<Link to="/" className="text-lg cursor-pointer flex flex-row justify-start items-center dark:text-gray-400">
|
<Link to="/" className="text-lg cursor-pointer flex flex-row justify-start items-center dark:text-gray-400">
|
||||||
<img id="logo-img" src="/logo.png" className="w-8 h-auto mr-2 -mt-0.5 dark:opacity-80" alt="" />
|
<img id="logo-img" src="/logo.png" className="w-8 h-auto mr-2 -mt-0.5 dark:opacity-80 rounded-full shadow" alt="" />
|
||||||
Slash
|
Slash
|
||||||
</Link>
|
</Link>
|
||||||
{profile.plan === PlanType.PRO && (
|
{profile.plan === PlanType.PRO && (
|
||||||
@ -52,27 +54,27 @@ const Header: React.FC = () => {
|
|||||||
to="/setting/general"
|
to="/setting/general"
|
||||||
className="w-full px-2 flex flex-row justify-start items-center text-left dark:text-gray-400 leading-8 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-800 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
className="w-full px-2 flex flex-row justify-start items-center text-left dark:text-gray-400 leading-8 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-800 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
||||||
>
|
>
|
||||||
<Icon.User className="w-4 h-auto mr-2" /> Profile
|
<Icon.User className="w-4 h-auto mr-2" /> {t("user.profile")}
|
||||||
</Link>
|
</Link>
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<Link
|
<Link
|
||||||
to="/setting/workspace"
|
to="/setting/workspace"
|
||||||
className="w-full px-2 flex flex-row justify-start items-center text-left dark:text-gray-400 leading-8 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-800 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
className="w-full px-2 flex flex-row justify-start items-center text-left dark:text-gray-400 leading-8 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-800 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
||||||
>
|
>
|
||||||
<Icon.Settings className="w-4 h-auto mr-2" /> Setting
|
<Icon.Settings className="w-4 h-auto mr-2" /> {t("settings.self")}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
className="w-full px-2 flex flex-row justify-start items-center text-left dark:text-gray-400 leading-8 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-800 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
className="w-full px-2 flex flex-row justify-start items-center text-left dark:text-gray-400 leading-8 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-800 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
||||||
onClick={() => setShowAboutDialog(true)}
|
onClick={() => setShowAboutDialog(true)}
|
||||||
>
|
>
|
||||||
<Icon.Info className="w-4 h-auto mr-2" /> About
|
<Icon.Info className="w-4 h-auto mr-2" /> {t("common.about")}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="w-full px-2 flex flex-row justify-start items-center text-left dark:text-gray-400 leading-8 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-800 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
className="w-full px-2 flex flex-row justify-start items-center text-left dark:text-gray-400 leading-8 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-800 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
|
||||||
onClick={() => handleSignOutButtonClick()}
|
onClick={() => handleSignOutButtonClick()}
|
||||||
>
|
>
|
||||||
<Icon.LogOut className="w-4 h-auto mr-2" /> Sign out
|
<Icon.LogOut className="w-4 h-auto mr-2" /> {t("auth.sign-out")}
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { useAppSelector } from "../stores";
|
import { useAppSelector } from "../stores";
|
||||||
import useViewStore from "../stores/v1/view";
|
import useViewStore from "../stores/v1/view";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
|
|
||||||
const Navigator = () => {
|
const Navigator = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const viewStore = useViewStore();
|
const viewStore = useViewStore();
|
||||||
const { shortcutList } = useAppSelector((state) => state.shortcut);
|
const { shortcutList } = useAppSelector((state) => state.shortcut);
|
||||||
const tags = shortcutList.map((shortcut) => shortcut.tags).flat();
|
const tags = shortcutList.map((shortcut) => shortcut.tags).flat();
|
||||||
@ -22,7 +24,7 @@ const Navigator = () => {
|
|||||||
onClick={() => viewStore.setFilter({ tab: "tab:all" })}
|
onClick={() => viewStore.setFilter({ tab: "tab:all" })}
|
||||||
>
|
>
|
||||||
<Icon.CircleSlash className="w-4 h-auto mr-1" />
|
<Icon.CircleSlash className="w-4 h-auto mr-1" />
|
||||||
<span className="font-normal">All</span>
|
<span className="font-normal">{t("filter.all")}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className={classNames(
|
className={classNames(
|
||||||
@ -34,7 +36,7 @@ const Navigator = () => {
|
|||||||
onClick={() => viewStore.setFilter({ tab: "tab:mine" })}
|
onClick={() => viewStore.setFilter({ tab: "tab:mine" })}
|
||||||
>
|
>
|
||||||
<Icon.User className="w-4 h-auto mr-1" />
|
<Icon.User className="w-4 h-auto mr-1" />
|
||||||
<span className="font-normal">Mine</span>
|
<span className="font-normal">{t("filter.mine")}</span>
|
||||||
</button>
|
</button>
|
||||||
{Array.from(sortedTagMap.keys()).map((tag) => (
|
{Array.from(sortedTagMap.keys()).map((tag) => (
|
||||||
<button
|
<button
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router-dom";
|
import useNavigateTo from "@/hooks/useNavigateTo";
|
||||||
import { shortcutService } from "../services";
|
import { shortcutService } from "../services";
|
||||||
import useUserStore from "../stores/v1/user";
|
import useUserStore from "../stores/v1/user";
|
||||||
import { showCommonDialog } from "./Alert";
|
import { showCommonDialog } from "./Alert";
|
||||||
@ -16,7 +16,7 @@ interface Props {
|
|||||||
const ShortcutActionsDropdown = (props: Props) => {
|
const ShortcutActionsDropdown = (props: Props) => {
|
||||||
const { shortcut } = props;
|
const { shortcut } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigateTo = useNavigateTo();
|
||||||
const currentUser = useUserStore().getCurrentUser();
|
const currentUser = useUserStore().getCurrentUser();
|
||||||
const [showEditDialog, setShowEditDialog] = useState<boolean>(false);
|
const [showEditDialog, setShowEditDialog] = useState<boolean>(false);
|
||||||
const [showQRCodeDialog, setShowQRCodeDialog] = useState<boolean>(false);
|
const [showQRCodeDialog, setShowQRCodeDialog] = useState<boolean>(false);
|
||||||
@ -34,7 +34,7 @@ const ShortcutActionsDropdown = (props: Props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const gotoAnalytics = () => {
|
const gotoAnalytics = () => {
|
||||||
navigate(`/shortcut/${shortcut.id}#analytics`);
|
navigateTo(`/shortcut/${shortcut.id}#analytics`);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { Tooltip } from "@mui/joy";
|
import { Tooltip } from "@mui/joy";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { absolutifyLink } from "../helpers/utils";
|
import { absolutifyLink, getFaviconWithGoogleS2 } from "../helpers/utils";
|
||||||
import useFaviconStore from "../stores/v1/favicon";
|
|
||||||
import useViewStore from "../stores/v1/view";
|
import useViewStore from "../stores/v1/view";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import ShortcutActionsDropdown from "./ShortcutActionsDropdown";
|
import ShortcutActionsDropdown from "./ShortcutActionsDropdown";
|
||||||
@ -20,17 +18,8 @@ const ShortcutView = (props: Props) => {
|
|||||||
const { shortcut } = props;
|
const { shortcut } = props;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const viewStore = useViewStore();
|
const viewStore = useViewStore();
|
||||||
const faviconStore = useFaviconStore();
|
|
||||||
const [favicon, setFavicon] = useState<string | undefined>(undefined);
|
|
||||||
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
|
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
|
||||||
|
const favicon = getFaviconWithGoogleS2(shortcut.link);
|
||||||
useEffect(() => {
|
|
||||||
faviconStore.getOrFetchUrlFavicon(shortcut.link).then((url) => {
|
|
||||||
if (url) {
|
|
||||||
setFavicon(url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [shortcut.link]);
|
|
||||||
|
|
||||||
const handleCopyButtonClick = () => {
|
const handleCopyButtonClick = () => {
|
||||||
copy(shortcutLink);
|
copy(shortcutLink);
|
||||||
@ -63,9 +52,9 @@ const ShortcutView = (props: Props) => {
|
|||||||
href={shortcutLink}
|
href={shortcutLink}
|
||||||
>
|
>
|
||||||
<div className="truncate">
|
<div className="truncate">
|
||||||
<span>{shortcut.title}</span>
|
<span className="dark:text-gray-400">{shortcut.title}</span>
|
||||||
{shortcut.title ? (
|
{shortcut.title ? (
|
||||||
<span className="text-gray-400">(s/{shortcut.name})</span>
|
<span className="text-gray-500">(s/{shortcut.name})</span>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<span className="text-gray-400 dark:text-gray-500">s/</span>
|
<span className="text-gray-400 dark:text-gray-500">s/</span>
|
||||||
@ -104,25 +93,25 @@ const ShortcutView = (props: Props) => {
|
|||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
key={tag}
|
key={tag}
|
||||||
className="max-w-[8rem] truncate text-gray-400 dark:text-gray-500 text-sm font-mono leading-4 cursor-pointer hover:opacity-80"
|
className="max-w-[8rem] truncate text-gray-400 dark:text-gray-500 text-sm leading-4 cursor-pointer hover:opacity-80"
|
||||||
onClick={() => viewStore.setFilter({ tag: tag })}
|
onClick={() => viewStore.setFilter({ tag: tag })}
|
||||||
>
|
>
|
||||||
#{tag}
|
#{tag}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{shortcut.tags.length === 0 && <span className="text-gray-400 text-sm font-mono leading-4 italic">No tags</span>}
|
{shortcut.tags.length === 0 && <span className="text-gray-400 text-sm leading-4 italic">No tags</span>}
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex mt-2 gap-2">
|
<div className="w-full flex mt-2 gap-2 overflow-x-auto">
|
||||||
<Tooltip title="Creator" variant="solid" placement="top" arrow>
|
<Tooltip title="Creator" variant="solid" placement="top" arrow>
|
||||||
<div className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full text-gray-500 text-sm dark:border-zinc-800">
|
<div className="w-auto px-2 leading-6 flex flex-row justify-start items-center flex-nowra whitespace-nowrap border rounded-full text-gray-500 text-sm dark:border-zinc-800">
|
||||||
<Icon.User className="w-4 h-auto mr-1" />
|
<Icon.User className="w-4 h-auto mr-1" />
|
||||||
<span className="max-w-[4rem] sm:max-w-[6rem] truncate">{shortcut.creator.nickname}</span>
|
<span className="max-w-[4rem] sm:max-w-[6rem] truncate">{shortcut.creator.nickname}</span>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.description`)} variant="solid" placement="top" arrow>
|
<Tooltip title={t(`shortcut.visibility.${shortcut.visibility.toLowerCase()}.description`)} variant="solid" placement="top" arrow>
|
||||||
<div
|
<div
|
||||||
className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full cursor-pointer text-gray-500 text-sm dark:border-zinc-800"
|
className="w-auto px-2 leading-6 flex flex-row justify-start items-center flex-nowrap whitespace-nowrap border rounded-full cursor-pointer text-gray-500 text-sm dark:border-zinc-800"
|
||||||
onClick={() => viewStore.setFilter({ visibility: shortcut.visibility })}
|
onClick={() => viewStore.setFilter({ visibility: shortcut.visibility })}
|
||||||
>
|
>
|
||||||
<VisibilityIcon className="w-4 h-auto mr-1" visibility={shortcut.visibility} />
|
<VisibilityIcon className="w-4 h-auto mr-1" visibility={shortcut.visibility} />
|
||||||
@ -132,10 +121,10 @@ const ShortcutView = (props: Props) => {
|
|||||||
<Tooltip title="View count" variant="solid" placement="top" arrow>
|
<Tooltip title="View count" variant="solid" placement="top" arrow>
|
||||||
<Link
|
<Link
|
||||||
to={`/shortcut/${shortcut.id}#analytics`}
|
to={`/shortcut/${shortcut.id}#analytics`}
|
||||||
className="w-auto px-2 leading-6 flex flex-row justify-start items-center border rounded-full cursor-pointer text-gray-500 text-sm dark:border-zinc-800"
|
className="w-auto px-2 leading-6 flex flex-row justify-start items-center flex-nowrap whitespace-nowrap border rounded-full cursor-pointer text-gray-500 text-sm dark:border-zinc-800"
|
||||||
>
|
>
|
||||||
<Icon.BarChart2 className="w-4 h-auto mr-1" />
|
<Icon.BarChart2 className="w-4 h-auto mr-1" />
|
||||||
{shortcut.view} visits
|
{t("shortcut.visits", { count: shortcut.view })}
|
||||||
</Link>
|
</Link>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { absolutifyLink } from "../helpers/utils";
|
import { absolutifyLink, getFaviconWithGoogleS2 } from "../helpers/utils";
|
||||||
import useFaviconStore from "../stores/v1/favicon";
|
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import ShortcutActionsDropdown from "./ShortcutActionsDropdown";
|
import ShortcutActionsDropdown from "./ShortcutActionsDropdown";
|
||||||
|
|
||||||
@ -12,17 +10,8 @@ interface Props {
|
|||||||
|
|
||||||
const ShortcutView = (props: Props) => {
|
const ShortcutView = (props: Props) => {
|
||||||
const { shortcut } = props;
|
const { shortcut } = props;
|
||||||
const faviconStore = useFaviconStore();
|
|
||||||
const [favicon, setFavicon] = useState<string | undefined>(undefined);
|
|
||||||
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
|
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
|
||||||
|
const favicon = getFaviconWithGoogleS2(shortcut.link);
|
||||||
useEffect(() => {
|
|
||||||
faviconStore.getOrFetchUrlFavicon(shortcut.link).then((url) => {
|
|
||||||
if (url) {
|
|
||||||
setFavicon(url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [shortcut.link]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -50,9 +39,9 @@ const ShortcutView = (props: Props) => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<div className="truncate">
|
<div className="truncate">
|
||||||
<span>{shortcut.title}</span>
|
<span className="dark:text-gray-400">{shortcut.title}</span>
|
||||||
{shortcut.title ? (
|
{shortcut.title ? (
|
||||||
<span className="text-gray-400">(s/{shortcut.name})</span>
|
<span className="text-gray-500">(s/{shortcut.name})</span>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<span className="text-gray-400 dark:text-gray-500">s/</span>
|
<span className="text-gray-400 dark:text-gray-500">s/</span>
|
||||||
|
@ -16,8 +16,8 @@ const ShortcutsContainer: React.FC<Props> = (props: Props) => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"w-full grid grid-cols-1 gap-y-2 sm:gap-2",
|
"w-full grid grid-cols-1 gap-3 sm:gap-4",
|
||||||
displayStyle === "full" ? "sm:grid-cols-2" : "grid-cols-2 sm:grid-cols-4 gap-2"
|
displayStyle === "full" ? "sm:grid-cols-2 lg:grid-cols-3" : "grid-cols-2 sm:grid-cols-4"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{shortcutList.map((shortcut) => {
|
{shortcutList.map((shortcut) => {
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { Divider, Option, Select, Switch } from "@mui/joy";
|
import { Divider, Option, Select, Switch } from "@mui/joy";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import useViewStore from "../stores/v1/view";
|
import useViewStore from "../stores/v1/view";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import Dropdown from "./common/Dropdown";
|
import Dropdown from "./common/Dropdown";
|
||||||
|
|
||||||
const ViewSetting = () => {
|
const ViewSetting = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const viewStore = useViewStore();
|
const viewStore = useViewStore();
|
||||||
const order = viewStore.getOrder();
|
const order = viewStore.getOrder();
|
||||||
const { field, direction } = order;
|
const { field, direction } = order;
|
||||||
@ -20,7 +22,7 @@ const ViewSetting = () => {
|
|||||||
actions={
|
actions={
|
||||||
<div className="w-52 p-2 gap-2 flex flex-col justify-start items-start" onClick={(e) => e.stopPropagation()}>
|
<div className="w-52 p-2 gap-2 flex flex-col justify-start items-start" onClick={(e) => e.stopPropagation()}>
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="text-sm shrink-0 mr-2">Compact mode</span>
|
<span className="text-sm shrink-0 mr-2">{t("filter.compact-mode")}</span>
|
||||||
<Switch
|
<Switch
|
||||||
size="sm"
|
size="sm"
|
||||||
checked={displayStyle === "compact"}
|
checked={displayStyle === "compact"}
|
||||||
@ -29,7 +31,7 @@ const ViewSetting = () => {
|
|||||||
</div>
|
</div>
|
||||||
<Divider className="!my-1" />
|
<Divider className="!my-1" />
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="text-sm shrink-0 mr-2">Order by</span>
|
<span className="text-sm shrink-0 mr-2">{t("filter.order-by")}</span>
|
||||||
<Select size="sm" value={field} onChange={(_, value) => viewStore.setOrder({ field: value as any })}>
|
<Select size="sm" value={field} onChange={(_, value) => viewStore.setOrder({ field: value as any })}>
|
||||||
<Option value={"name"}>Name</Option>
|
<Option value={"name"}>Name</Option>
|
||||||
<Option value={"updatedTs"}>CreatedAt</Option>
|
<Option value={"updatedTs"}>CreatedAt</Option>
|
||||||
@ -38,7 +40,7 @@ const ViewSetting = () => {
|
|||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="text-sm shrink-0 mr-2">Direction</span>
|
<span className="text-sm shrink-0 mr-2">{t("filter.direction")}</span>
|
||||||
<Select size="sm" value={direction} onChange={(_, value) => viewStore.setOrder({ direction: value as any })}>
|
<Select size="sm" value={direction} onChange={(_, value) => viewStore.setOrder({ direction: value as any })}>
|
||||||
<Option value={"asc"}>ASC</Option>
|
<Option value={"asc"}>ASC</Option>
|
||||||
<Option value={"desc"}>DESC</Option>
|
<Option value={"desc"}>DESC</Option>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { ReactNode, useEffect, useRef } from "react";
|
import { ReactNode, useEffect, useRef, useState } from "react";
|
||||||
import useToggle from "../../hooks/useToggle";
|
|
||||||
import Icon from "../Icon";
|
import Icon from "../Icon";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -11,14 +10,14 @@ interface Props {
|
|||||||
|
|
||||||
const Dropdown: React.FC<Props> = (props: Props) => {
|
const Dropdown: React.FC<Props> = (props: Props) => {
|
||||||
const { trigger, actions, className, actionsClassName } = props;
|
const { trigger, actions, className, actionsClassName } = props;
|
||||||
const [dropdownStatus, toggleDropdownStatus] = useToggle(false);
|
const [dropdownStatus, setDropdownStatus] = useState(false);
|
||||||
const dropdownWrapperRef = useRef<HTMLDivElement>(null);
|
const dropdownWrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dropdownStatus) {
|
if (dropdownStatus) {
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
if (!dropdownWrapperRef.current?.contains(event.target as Node)) {
|
if (!dropdownWrapperRef.current?.contains(event.target as Node)) {
|
||||||
toggleDropdownStatus(false);
|
setDropdownStatus(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,7 +34,7 @@ const Dropdown: React.FC<Props> = (props: Props) => {
|
|||||||
|
|
||||||
const handleToggleDropdownStatus = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
const handleToggleDropdownStatus = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleDropdownStatus();
|
setDropdownStatus(!dropdownStatus);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -15,7 +15,7 @@ const AccountSection: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="w-full flex flex-col justify-start items-start gap-y-2">
|
<div className="w-full flex flex-col justify-start items-start gap-y-2">
|
||||||
<p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Account</p>
|
<p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">{t("common.account")}</p>
|
||||||
<p className="flex flex-row justify-start items-center mt-2 dark:text-gray-400">
|
<p className="flex flex-row justify-start items-center mt-2 dark:text-gray-400">
|
||||||
<span className="text-xl">{currentUser.nickname}</span>
|
<span className="text-xl">{currentUser.nickname}</span>
|
||||||
{isAdmin && <span className="ml-2 bg-blue-600 text-white px-2 leading-6 text-sm rounded-full">Admin</span>}
|
{isAdmin && <span className="ml-2 bg-blue-600 text-white px-2 leading-6 text-sm rounded-full">Admin</span>}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
import { Button, IconButton } from "@mui/joy";
|
import { Button, IconButton } from "@mui/joy";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import useUserStore from "../../stores/v1/user";
|
import useUserStore from "../../stores/v1/user";
|
||||||
import { showCommonDialog } from "../Alert";
|
import { showCommonDialog } from "../Alert";
|
||||||
import CreateUserDialog from "../CreateUserDialog";
|
import CreateUserDialog from "../CreateUserDialog";
|
||||||
import Icon from "../Icon";
|
import Icon from "../Icon";
|
||||||
|
|
||||||
const MemberSection = () => {
|
const MemberSection = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const [showCreateUserDialog, setShowCreateUserDialog] = useState<boolean>(false);
|
const [showCreateUserDialog, setShowCreateUserDialog] = useState<boolean>(false);
|
||||||
const [currentEditingUser, setCurrentEditingUser] = useState<User | undefined>(undefined);
|
const [currentEditingUser, setCurrentEditingUser] = useState<User | undefined>(undefined);
|
||||||
@ -43,7 +45,7 @@ const MemberSection = () => {
|
|||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div className="sm:flex sm:items-center">
|
<div className="sm:flex sm:items-center">
|
||||||
<div className="sm:flex-auto">
|
<div className="sm:flex-auto">
|
||||||
<p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Users</p>
|
<p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">{t("user.self")}</p>
|
||||||
<p className="mt-2 text-sm text-gray-700 dark:text-gray-600">
|
<p className="mt-2 text-sm text-gray-700 dark:text-gray-600">
|
||||||
A list of all the users in your workspace including their nickname, email and role.
|
A list of all the users in your workspace including their nickname, email and role.
|
||||||
</p>
|
</p>
|
||||||
@ -57,7 +59,7 @@ const MemberSection = () => {
|
|||||||
setCurrentEditingUser(undefined);
|
setCurrentEditingUser(undefined);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Add user
|
{t("user.action.add-user")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -68,20 +70,20 @@ const MemberSection = () => {
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
|
<th scope="col" className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
|
||||||
Nickname
|
{t("user.nickname")}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
|
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
|
||||||
Email
|
{t("user.email")}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
|
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 dark:text-gray-500">
|
||||||
Role
|
{t("user.role")}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" className="relative py-3.5 pl-3 pr-4">
|
<th scope="col" className="relative py-3.5 pl-3 pr-4">
|
||||||
<span className="sr-only">Edit</span>
|
<span className="sr-only">{t("common.edit")}</span>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-gray-200">
|
<tbody className="divide-y divide-gray-200 dark:divide-zinc-800">
|
||||||
{userList.map((user) => (
|
{userList.map((user) => (
|
||||||
<tr key={user.email}>
|
<tr key={user.email}>
|
||||||
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-gray-900 dark:text-gray-500">{user.nickname}</td>
|
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm text-gray-900 dark:text-gray-500">{user.nickname}</td>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Option, Select } from "@mui/joy";
|
import { Option, Select } from "@mui/joy";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { releaseGuard } from "@/helpers/utils";
|
|
||||||
import { UserSetting, UserSetting_ColorTheme, UserSetting_Locale } from "@/types/proto/api/v2/user_setting_service";
|
import { UserSetting, UserSetting_ColorTheme, UserSetting_Locale } from "@/types/proto/api/v2/user_setting_service";
|
||||||
import useUserStore from "../../stores/v1/user";
|
import useUserStore from "../../stores/v1/user";
|
||||||
import BetaBadge from "../BetaBadge";
|
import BetaBadge from "../BetaBadge";
|
||||||
@ -61,10 +60,10 @@ const PreferenceSection: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="w-full flex flex-col justify-start items-start gap-y-2">
|
<div className="w-full flex flex-col justify-start items-start gap-y-2">
|
||||||
<p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Preference</p>
|
<p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">{t("settings.preference.self")}</p>
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<div className="flex flex-row justify-start items-center gap-x-1">
|
<div className="flex flex-row justify-start items-center gap-x-1">
|
||||||
<span className="dark:text-gray-400">Color Theme</span>
|
<span className="dark:text-gray-400">{t("settings.preference.color-theme")}</span>
|
||||||
</div>
|
</div>
|
||||||
<Select defaultValue={colorTheme} onChange={(_, value) => handleSelectColorTheme(value as UserSetting_ColorTheme)}>
|
<Select defaultValue={colorTheme} onChange={(_, value) => handleSelectColorTheme(value as UserSetting_ColorTheme)}>
|
||||||
{colorThemeOptions.map((option) => {
|
{colorThemeOptions.map((option) => {
|
||||||
@ -76,23 +75,21 @@ const PreferenceSection: React.FC = () => {
|
|||||||
})}
|
})}
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
{releaseGuard() && (
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="flex flex-row justify-start items-center gap-x-1">
|
||||||
<div className="flex flex-row justify-start items-center gap-x-1">
|
<span className="dark:text-gray-400">{t("common.language")}</span>
|
||||||
<span className="dark:text-gray-400">{t("common.language")}</span>
|
<BetaBadge />
|
||||||
<BetaBadge />
|
|
||||||
</div>
|
|
||||||
<Select defaultValue={language} onChange={(_, value) => handleSelectLanguage(value as UserSetting_Locale)}>
|
|
||||||
{languageOptions.map((option) => {
|
|
||||||
return (
|
|
||||||
<Option key={option.value} value={option.value}>
|
|
||||||
{option.label}
|
|
||||||
</Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
<Select defaultValue={language} onChange={(_, value) => handleSelectLanguage(value as UserSetting_Locale)}>
|
||||||
|
{languageOptions.map((option) => {
|
||||||
|
return (
|
||||||
|
<Option key={option.value} value={option.value}>
|
||||||
|
{option.label}
|
||||||
|
</Option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -2,11 +2,13 @@ import { Button, Checkbox, Textarea } from "@mui/joy";
|
|||||||
import { isEqual } from "lodash-es";
|
import { isEqual } from "lodash-es";
|
||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { workspaceServiceClient } from "@/grpcweb";
|
import { workspaceServiceClient } from "@/grpcweb";
|
||||||
import useWorkspaceStore from "@/stores/v1/workspace";
|
import useWorkspaceStore from "@/stores/v1/workspace";
|
||||||
import { WorkspaceSetting } from "@/types/proto/api/v2/workspace_service";
|
import { WorkspaceSetting } from "@/types/proto/api/v2/workspace_service";
|
||||||
|
|
||||||
const WorkspaceSection: React.FC = () => {
|
const WorkspaceSection: React.FC = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const workspaceStore = useWorkspaceStore();
|
const workspaceStore = useWorkspaceStore();
|
||||||
const [workspaceSetting, setWorkspaceSetting] = useState<WorkspaceSetting>(workspaceStore.setting);
|
const [workspaceSetting, setWorkspaceSetting] = useState<WorkspaceSetting>(workspaceStore.setting);
|
||||||
const originalWorkspaceSetting = useRef<WorkspaceSetting>(workspaceStore.setting);
|
const originalWorkspaceSetting = useRef<WorkspaceSetting>(workspaceStore.setting);
|
||||||
@ -56,11 +58,12 @@ const WorkspaceSection: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full flex flex-col justify-start items-start space-y-4">
|
<div className="w-full flex flex-col justify-start items-start space-y-4">
|
||||||
<p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">Workspace settings</p>
|
<p className="text-base font-semibold leading-6 text-gray-900 dark:text-gray-500">{t("settings.workspace.self")}</p>
|
||||||
<div className="w-full flex flex-col justify-start items-start">
|
<div className="w-full flex flex-col justify-start items-start">
|
||||||
<p className="mt-2 dark:text-gray-400">Custom style</p>
|
<p className="mt-2 dark:text-gray-400">{t("settings.workspace.custom-style")}</p>
|
||||||
<Textarea
|
<Textarea
|
||||||
className="w-full mt-2"
|
className="w-full mt-2"
|
||||||
|
placeholder="* {font-family: ui-monospace Monaco Consolas;}"
|
||||||
minRows={2}
|
minRows={2}
|
||||||
maxRows={5}
|
maxRows={5}
|
||||||
value={workspaceSetting.customStyle}
|
value={workspaceSetting.customStyle}
|
||||||
@ -69,15 +72,15 @@ const WorkspaceSection: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-col justify-start items-start">
|
<div className="w-full flex flex-col justify-start items-start">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Enable user signup"
|
label={t("settings.workspace.enable-user-signup.self")}
|
||||||
checked={workspaceSetting.enableSignup}
|
checked={workspaceSetting.enableSignup}
|
||||||
onChange={(event) => handleEnableSignUpChange(event.target.checked)}
|
onChange={(event) => handleEnableSignUpChange(event.target.checked)}
|
||||||
/>
|
/>
|
||||||
<p className="mt-2 text-gray-500">Once enabled, other users can signup.</p>
|
<p className="mt-2 text-gray-500">{t("settings.workspace.enable-user-signup.description")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button variant="outlined" color="neutral" disabled={!allowSave} onClick={handleSaveWorkspaceSetting}>
|
<Button variant="outlined" color="neutral" disabled={!allowSave} onClick={handleSaveWorkspaceSetting}>
|
||||||
Save
|
{t("common.save")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -71,7 +71,3 @@ export function patchShortcut(shortcutPatch: ShortcutPatch) {
|
|||||||
export function deleteShortcutById(shortcutId: ShortcutId) {
|
export function deleteShortcutById(shortcutId: ShortcutId) {
|
||||||
return axios.delete(`/api/v1/shortcut/${shortcutId}`);
|
return axios.delete(`/api/v1/shortcut/${shortcutId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUrlFavicon(url: string) {
|
|
||||||
return axios.get<string>(`/api/v1/url/favicon?url=${url}`);
|
|
||||||
}
|
|
||||||
|
@ -13,3 +13,12 @@ export const absolutifyLink = (rel: string): string => {
|
|||||||
export const releaseGuard = () => {
|
export const releaseGuard = () => {
|
||||||
return import.meta.env.MODE === "development";
|
return import.meta.env.MODE === "development";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getFaviconWithGoogleS2 = (url: string) => {
|
||||||
|
try {
|
||||||
|
const urlObject = new URL(url);
|
||||||
|
return `https://www.google.com/s2/favicons?sz=128&domain=${urlObject.hostname}`;
|
||||||
|
} catch (error) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
20
frontend/web/src/hooks/useNavigateTo.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { NavigateOptions, useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
|
const useNavigateTo = () => {
|
||||||
|
const navigateTo = useNavigate();
|
||||||
|
|
||||||
|
const navigateToWithViewTransition = (to: string, options?: NavigateOptions) => {
|
||||||
|
const document = window.document as any;
|
||||||
|
if (!document.startViewTransition) {
|
||||||
|
navigateTo(to, options);
|
||||||
|
} else {
|
||||||
|
document.startViewTransition(() => {
|
||||||
|
navigateTo(to, options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return navigateToWithViewTransition;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useNavigateTo;
|
@ -1,21 +0,0 @@
|
|||||||
import { useCallback, useState } from "react";
|
|
||||||
|
|
||||||
// Parameter is the boolean, with default "false" value
|
|
||||||
const useToggle = (initialState = false): [boolean, (nextState?: boolean) => void] => {
|
|
||||||
// Initialize the state
|
|
||||||
const [state, setState] = useState(initialState);
|
|
||||||
|
|
||||||
// Define and memorize toggler function in case we pass down the comopnent,
|
|
||||||
// This function change the boolean value to it's opposite value
|
|
||||||
const toggle = useCallback((nextState?: boolean) => {
|
|
||||||
if (nextState !== undefined) {
|
|
||||||
setState(nextState);
|
|
||||||
} else {
|
|
||||||
setState((state) => !state);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return [state, toggle];
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useToggle;
|
|
@ -2,13 +2,14 @@ import { useColorScheme } from "@mui/joy";
|
|||||||
import { isEqual } from "lodash-es";
|
import { isEqual } from "lodash-es";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Outlet, useNavigate } from "react-router-dom";
|
import { Outlet } from "react-router-dom";
|
||||||
import { UserSetting_ColorTheme } from "@/types/proto/api/v2/user_setting_service";
|
import useNavigateTo from "@/hooks/useNavigateTo";
|
||||||
|
import { UserSetting_ColorTheme, UserSetting_Locale } from "@/types/proto/api/v2/user_setting_service";
|
||||||
import Header from "../components/Header";
|
import Header from "../components/Header";
|
||||||
import useUserStore from "../stores/v1/user";
|
import useUserStore from "../stores/v1/user";
|
||||||
|
|
||||||
const Root: React.FC = () => {
|
const Root: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigateTo = useNavigateTo();
|
||||||
const { setMode } = useColorScheme();
|
const { setMode } = useColorScheme();
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
@ -18,7 +19,7 @@ const Root: React.FC = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!currentUser) {
|
if (!currentUser) {
|
||||||
navigate("/auth", {
|
navigateTo("/auth", {
|
||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@ -33,7 +34,7 @@ const Root: React.FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEqual(currentUserSetting.locale, "LOCALE_ZH")) {
|
if (isEqual(currentUserSetting.locale, UserSetting_Locale.LOCALE_ZH)) {
|
||||||
i18n.changeLanguage("zh");
|
i18n.changeLanguage("zh");
|
||||||
} else {
|
} else {
|
||||||
i18n.changeLanguage("en");
|
i18n.changeLanguage("en");
|
||||||
|
@ -69,9 +69,9 @@ const Home: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
<FilterView />
|
<FilterView />
|
||||||
{loadingState.isLoading ? (
|
{loadingState.isLoading ? (
|
||||||
<div className="py-12 w-full flex flex-row justify-center items-center opacity-80">
|
<div className="py-12 w-full flex flex-row justify-center items-center opacity-80 dark:text-gray-500">
|
||||||
<Icon.Loader className="mr-2 w-5 h-auto animate-spin" />
|
<Icon.Loader className="mr-2 w-5 h-auto animate-spin" />
|
||||||
loading
|
{t("common.loading")}
|
||||||
</div>
|
</div>
|
||||||
) : orderedShortcutList.length === 0 ? (
|
) : orderedShortcutList.length === 0 ? (
|
||||||
<div className="py-16 w-full flex flex-col justify-center items-center text-gray-400">
|
<div className="py-16 w-full flex flex-col justify-center items-center text-gray-400">
|
||||||
|
62
frontend/web/src/pages/NotFound.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { Button } from "@mui/joy";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useLocation } from "react-router-dom";
|
||||||
|
import CreateShortcutDialog from "@/components/CreateShortcutDialog";
|
||||||
|
import Icon from "@/components/Icon";
|
||||||
|
import useNavigateTo from "@/hooks/useNavigateTo";
|
||||||
|
import useUserStore from "@/stores/v1/user";
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
showCreateShortcutButton: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NotFound = () => {
|
||||||
|
const location = useLocation();
|
||||||
|
const navigateTo = useNavigateTo();
|
||||||
|
const currentUser = useUserStore().getCurrentUser();
|
||||||
|
const [state, setState] = useState<State>({
|
||||||
|
showCreateShortcutButton: false,
|
||||||
|
});
|
||||||
|
const [showCreateShortcutDialog, setShowCreateShortcutDialog] = useState(false);
|
||||||
|
const params = new URLSearchParams(location.search);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const shortcut = params.get("shortcut");
|
||||||
|
if (currentUser && shortcut) {
|
||||||
|
setState({
|
||||||
|
...state,
|
||||||
|
showCreateShortcutButton: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="w-full h-full overflow-y-auto overflow-x-hidden bg-zinc-100 dark:bg-zinc-800">
|
||||||
|
<div className="w-full h-full flex flex-col justify-center items-center">
|
||||||
|
<Icon.Meh strokeWidth={1} className="w-20 h-auto opacity-80 dark:text-gray-300" />
|
||||||
|
<p className="mt-4 mb-8 text-4xl font-mono dark:text-gray-300">404</p>
|
||||||
|
{state.showCreateShortcutButton && (
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
startDecorator={<Icon.Plus className="w-5 h-auto" />}
|
||||||
|
onClick={() => setShowCreateShortcutDialog(true)}
|
||||||
|
>
|
||||||
|
Create shortcut
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showCreateShortcutDialog && (
|
||||||
|
<CreateShortcutDialog
|
||||||
|
initialShortcut={{ name: params.get("shortcut") || "" }}
|
||||||
|
onClose={() => setShowCreateShortcutDialog(false)}
|
||||||
|
onConfirm={() => navigateTo("/")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NotFound;
|
@ -1,10 +1,11 @@
|
|||||||
import { Tooltip } from "@mui/joy";
|
import { Tooltip } from "@mui/joy";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
import { useEffect, useState } from "react";
|
import { useState } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useLoaderData, useNavigate } from "react-router-dom";
|
import { useLoaderData } from "react-router-dom";
|
||||||
|
import useNavigateTo from "@/hooks/useNavigateTo";
|
||||||
import { showCommonDialog } from "../components/Alert";
|
import { showCommonDialog } from "../components/Alert";
|
||||||
import AnalyticsView from "../components/AnalyticsView";
|
import AnalyticsView from "../components/AnalyticsView";
|
||||||
import CreateShortcutDialog from "../components/CreateShortcutDialog";
|
import CreateShortcutDialog from "../components/CreateShortcutDialog";
|
||||||
@ -12,9 +13,8 @@ import GenerateQRCodeDialog from "../components/GenerateQRCodeDialog";
|
|||||||
import Icon from "../components/Icon";
|
import Icon from "../components/Icon";
|
||||||
import VisibilityIcon from "../components/VisibilityIcon";
|
import VisibilityIcon from "../components/VisibilityIcon";
|
||||||
import Dropdown from "../components/common/Dropdown";
|
import Dropdown from "../components/common/Dropdown";
|
||||||
import { absolutifyLink } from "../helpers/utils";
|
import { absolutifyLink, getFaviconWithGoogleS2 } from "../helpers/utils";
|
||||||
import { shortcutService } from "../services";
|
import { shortcutService } from "../services";
|
||||||
import useFaviconStore from "../stores/v1/favicon";
|
|
||||||
import useUserStore from "../stores/v1/user";
|
import useUserStore from "../stores/v1/user";
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@ -23,26 +23,17 @@ interface State {
|
|||||||
|
|
||||||
const ShortcutDetail = () => {
|
const ShortcutDetail = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigateTo = useNavigateTo();
|
||||||
const shortcutId = (useLoaderData() as Shortcut).id;
|
const shortcutId = (useLoaderData() as Shortcut).id;
|
||||||
const shortcut = shortcutService.getShortcutById(shortcutId) as Shortcut;
|
const shortcut = shortcutService.getShortcutById(shortcutId) as Shortcut;
|
||||||
const currentUser = useUserStore().getCurrentUser();
|
const currentUser = useUserStore().getCurrentUser();
|
||||||
const faviconStore = useFaviconStore();
|
|
||||||
const [state, setState] = useState<State>({
|
const [state, setState] = useState<State>({
|
||||||
showEditModal: false,
|
showEditModal: false,
|
||||||
});
|
});
|
||||||
const [favicon, setFavicon] = useState<string | undefined>(undefined);
|
|
||||||
const [showQRCodeDialog, setShowQRCodeDialog] = useState<boolean>(false);
|
const [showQRCodeDialog, setShowQRCodeDialog] = useState<boolean>(false);
|
||||||
const havePermission = currentUser.role === "ADMIN" || shortcut.creatorId === currentUser.id;
|
const havePermission = currentUser.role === "ADMIN" || shortcut.creatorId === currentUser.id;
|
||||||
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
|
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
|
||||||
|
const favicon = getFaviconWithGoogleS2(shortcut.link);
|
||||||
useEffect(() => {
|
|
||||||
faviconStore.getOrFetchUrlFavicon(shortcut.link).then((url) => {
|
|
||||||
if (url) {
|
|
||||||
setFavicon(url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [shortcut.link]);
|
|
||||||
|
|
||||||
const handleCopyButtonClick = () => {
|
const handleCopyButtonClick = () => {
|
||||||
copy(shortcutLink);
|
copy(shortcutLink);
|
||||||
@ -56,7 +47,7 @@ const ShortcutDetail = () => {
|
|||||||
style: "danger",
|
style: "danger",
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
await shortcutService.deleteShortcutById(shortcut.id);
|
await shortcutService.deleteShortcutById(shortcut.id);
|
||||||
navigate("/", {
|
navigateTo("/", {
|
||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -146,14 +137,12 @@ const ShortcutDetail = () => {
|
|||||||
<div className="mt-4 ml-1 flex flex-row justify-start items-start flex-wrap gap-2">
|
<div className="mt-4 ml-1 flex flex-row justify-start items-start flex-wrap gap-2">
|
||||||
{shortcut.tags.map((tag) => {
|
{shortcut.tags.map((tag) => {
|
||||||
return (
|
return (
|
||||||
<span key={tag} className="max-w-[8rem] truncate text-gray-400 text font-mono leading-4 dark:text-gray-500">
|
<span key={tag} className="max-w-[8rem] truncate text-gray-400 text leading-4 dark:text-gray-500">
|
||||||
#{tag}
|
#{tag}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{shortcut.tags.length === 0 && (
|
{shortcut.tags.length === 0 && <span className="text-gray-400 text-sm leading-4 italic dark:text-gray-500">No tags</span>}
|
||||||
<span className="text-gray-400 text-sm font-mono leading-4 italic dark:text-gray-500">No tags</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex mt-4 gap-2">
|
<div className="w-full flex mt-4 gap-2">
|
||||||
<Tooltip title="Creator" variant="solid" placement="top" arrow>
|
<Tooltip title="Creator" variant="solid" placement="top" arrow>
|
||||||
|
@ -2,7 +2,8 @@ import { Button, Input } from "@mui/joy";
|
|||||||
import React, { FormEvent, useEffect, useState } from "react";
|
import React, { FormEvent, useEffect, useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import useNavigateTo from "@/hooks/useNavigateTo";
|
||||||
import useWorkspaceStore from "@/stores/v1/workspace";
|
import useWorkspaceStore from "@/stores/v1/workspace";
|
||||||
import * as api from "../helpers/api";
|
import * as api from "../helpers/api";
|
||||||
import useLoading from "../hooks/useLoading";
|
import useLoading from "../hooks/useLoading";
|
||||||
@ -10,7 +11,7 @@ import useUserStore from "../stores/v1/user";
|
|||||||
|
|
||||||
const SignIn: React.FC = () => {
|
const SignIn: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigateTo = useNavigateTo();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const workspaceStore = useWorkspaceStore();
|
const workspaceStore = useWorkspaceStore();
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
@ -20,7 +21,7 @@ const SignIn: React.FC = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (userStore.getCurrentUser()) {
|
if (userStore.getCurrentUser()) {
|
||||||
return navigate("/", {
|
return navigateTo("/", {
|
||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -52,7 +53,7 @@ const SignIn: React.FC = () => {
|
|||||||
await api.signin(email, password);
|
await api.signin(email, password);
|
||||||
const user = await userStore.fetchCurrentUser();
|
const user = await userStore.fetchCurrentUser();
|
||||||
if (user) {
|
if (user) {
|
||||||
navigate("/", {
|
navigateTo("/", {
|
||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -70,7 +71,7 @@ const SignIn: React.FC = () => {
|
|||||||
<div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center">
|
<div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center">
|
||||||
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
||||||
<div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4">
|
<div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4">
|
||||||
<img id="logo-img" src="/logo.png" className="w-12 h-auto mr-2 -mt-1" alt="logo" />
|
<img id="logo-img" src="/logo.png" className="w-12 h-auto mr-2 -mt-1 rounded-full shadow" alt="logo" />
|
||||||
<span className="text-3xl opacity-80 dark:text-gray-500">Slash</span>
|
<span className="text-3xl opacity-80 dark:text-gray-500">Slash</span>
|
||||||
</div>
|
</div>
|
||||||
<form className="w-full mt-6" onSubmit={handleSigninBtnClick}>
|
<form className="w-full mt-6" onSubmit={handleSigninBtnClick}>
|
||||||
@ -99,15 +100,15 @@ const SignIn: React.FC = () => {
|
|||||||
disabled={actionBtnLoadingState.isLoading || !allowConfirm}
|
disabled={actionBtnLoadingState.isLoading || !allowConfirm}
|
||||||
onClick={handleSigninBtnClick}
|
onClick={handleSigninBtnClick}
|
||||||
>
|
>
|
||||||
Sign in
|
{t("auth.sign-in")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{workspaceStore.setting.enableSignup && (
|
{workspaceStore.profile.enableSignup && (
|
||||||
<p className="w-full mt-4 text-sm">
|
<p className="w-full mt-4 text-sm">
|
||||||
<span className="dark:text-gray-500">{"Don't have an account yet?"}</span>
|
<span className="dark:text-gray-500">{"Don't have an account yet?"}</span>
|
||||||
<Link to="/auth/signup" className="cursor-pointer ml-2 text-blue-600 hover:underline">
|
<Link to="/auth/signup" className="cursor-pointer ml-2 text-blue-600 hover:underline">
|
||||||
Sign up
|
{t("auth.sign-up")}
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
@ -2,7 +2,8 @@ import { Button, Input } from "@mui/joy";
|
|||||||
import React, { FormEvent, useEffect, useState } from "react";
|
import React, { FormEvent, useEffect, useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import useNavigateTo from "@/hooks/useNavigateTo";
|
||||||
import useWorkspaceStore from "@/stores/v1/workspace";
|
import useWorkspaceStore from "@/stores/v1/workspace";
|
||||||
import * as api from "../helpers/api";
|
import * as api from "../helpers/api";
|
||||||
import useLoading from "../hooks/useLoading";
|
import useLoading from "../hooks/useLoading";
|
||||||
@ -10,7 +11,7 @@ import useUserStore from "../stores/v1/user";
|
|||||||
|
|
||||||
const SignUp: React.FC = () => {
|
const SignUp: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigateTo = useNavigateTo();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const workspaceStore = useWorkspaceStore();
|
const workspaceStore = useWorkspaceStore();
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
@ -21,13 +22,13 @@ const SignUp: React.FC = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (userStore.getCurrentUser()) {
|
if (userStore.getCurrentUser()) {
|
||||||
return navigate("/", {
|
return navigateTo("/", {
|
||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!workspaceStore.setting.enableSignup) {
|
if (!workspaceStore.profile.enableSignup) {
|
||||||
return navigate("/auth", {
|
return navigateTo("/auth", {
|
||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -59,7 +60,7 @@ const SignUp: React.FC = () => {
|
|||||||
await api.signup(email, nickname, password);
|
await api.signup(email, nickname, password);
|
||||||
const user = await userStore.fetchCurrentUser();
|
const user = await userStore.fetchCurrentUser();
|
||||||
if (user) {
|
if (user) {
|
||||||
navigate("/", {
|
navigateTo("/", {
|
||||||
replace: true,
|
replace: true,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -77,10 +78,10 @@ const SignUp: React.FC = () => {
|
|||||||
<div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center">
|
<div className="w-80 max-w-full h-full py-4 flex flex-col justify-start items-center">
|
||||||
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
<div className="w-full py-4 grow flex flex-col justify-center items-center">
|
||||||
<div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4">
|
<div className="flex flex-row justify-start items-center w-auto mx-auto gap-y-2 mb-4">
|
||||||
<img id="logo-img" src="/logo.png" className="w-12 h-auto mr-2 -mt-1" alt="logo" />
|
<img id="logo-img" src="/logo.png" className="w-12 h-auto mr-2 -mt-1 rounded-full shadow" alt="logo" />
|
||||||
<span className="text-3xl opacity-80 dark:text-gray-500">Slash</span>
|
<span className="text-3xl opacity-80 dark:text-gray-500">Slash</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="w-full text-2xl mt-6 dark:text-gray-500">Create your account</p>
|
<p className="w-full text-2xl mt-6 dark:text-gray-500">{t("auth.create-your-account")}</p>
|
||||||
<form className="w-full mt-4" onSubmit={handleSignupBtnClick}>
|
<form className="w-full mt-4" onSubmit={handleSignupBtnClick}>
|
||||||
<div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading ? "opacity-80" : ""}`}>
|
<div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading ? "opacity-80" : ""}`}>
|
||||||
<div className="w-full flex flex-col mb-2">
|
<div className="w-full flex flex-col mb-2">
|
||||||
@ -111,14 +112,14 @@ const SignUp: React.FC = () => {
|
|||||||
disabled={actionBtnLoadingState.isLoading || !allowConfirm}
|
disabled={actionBtnLoadingState.isLoading || !allowConfirm}
|
||||||
onClick={handleSignupBtnClick}
|
onClick={handleSignupBtnClick}
|
||||||
>
|
>
|
||||||
Sign up
|
{t("auth.sign-up")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<p className="w-full mt-4 text-sm">
|
<p className="w-full mt-4 text-sm">
|
||||||
<span className="dark:text-gray-500">{"Already has an account?"}</span>
|
<span className="dark:text-gray-500">{"Already has an account?"}</span>
|
||||||
<Link to="/auth" className="cursor-pointer ml-2 text-blue-600 hover:underline">
|
<Link to="/auth" className="cursor-pointer ml-2 text-blue-600 hover:underline">
|
||||||
Sign in
|
{t("auth.sign-in")}
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Button, Divider, Link, Textarea } from "@mui/joy";
|
import { Alert, Button, Divider, Link, Textarea } from "@mui/joy";
|
||||||
import { useEffect, useState } from "react";
|
import { useState } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import Icon from "@/components/Icon";
|
import Icon from "@/components/Icon";
|
||||||
import SubscriptionFAQ from "@/components/SubscriptionFAQ";
|
import SubscriptionFAQ from "@/components/SubscriptionFAQ";
|
||||||
@ -16,17 +16,12 @@ const SubscriptionSetting: React.FC = () => {
|
|||||||
const isAdmin = currentUser.role === "ADMIN";
|
const isAdmin = currentUser.role === "ADMIN";
|
||||||
const profile = workspaceStore.profile;
|
const profile = workspaceStore.profile;
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isAdmin) {
|
|
||||||
window.location.href = "/";
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (!isAdmin) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleUpdateLicenseKey = async () => {
|
const handleUpdateLicenseKey = async () => {
|
||||||
|
if (!isAdmin) {
|
||||||
|
toast.error("Only admin can upload license key");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { subscription } = await subscriptionServiceClient.updateSubscription({
|
const { subscription } = await subscriptionServiceClient.updateSubscription({
|
||||||
licenseKey,
|
licenseKey,
|
||||||
@ -60,7 +55,7 @@ const SubscriptionSetting: React.FC = () => {
|
|||||||
<div className="w-full flex justify-between items-center mt-4">
|
<div className="w-full flex justify-between items-center mt-4">
|
||||||
<div>
|
<div>
|
||||||
{profile.plan === PlanType.FREE && (
|
{profile.plan === PlanType.FREE && (
|
||||||
<Link href="https://yourselfhosted.lemonsqueezy.com/checkout?cart=df958121-81ad-4815-8b28-3f2d8e9c8e51" target="_blank">
|
<Link href="https://yourselfhosted.lemonsqueezy.com/checkout/buy/d03a2696-8a8b-49c9-9e19-d425e3884fd7" target="_blank">
|
||||||
Buy a license key
|
Buy a license key
|
||||||
<Icon.ExternalLink className="w-4 h-auto ml-1" />
|
<Icon.ExternalLink className="w-4 h-auto ml-1" />
|
||||||
</Link>
|
</Link>
|
||||||
@ -74,6 +69,10 @@ const SubscriptionSetting: React.FC = () => {
|
|||||||
<Divider />
|
<Divider />
|
||||||
<section className="w-full pb-8 dark:bg-zinc-900 flex items-center justify-center">
|
<section className="w-full pb-8 dark:bg-zinc-900 flex items-center justify-center">
|
||||||
<div className="w-full px-6">
|
<div className="w-full px-6">
|
||||||
|
<Alert className="!inline-block mb-12">
|
||||||
|
Slash is open source bookmarks and link sharing platform. Our source code is available and accessible on{" "}
|
||||||
|
<Link href="https://github.com/boojack/slash">GitHub</Link> so anyone can get it, inspect it and review it.
|
||||||
|
</Alert>
|
||||||
<div className="w-full grid grid-cols-1 gap-12 mt-8 md:grid-cols-3">
|
<div className="w-full grid grid-cols-1 gap-12 mt-8 md:grid-cols-3">
|
||||||
<div className="flex flex-col p-6 bg-white dark:bg-zinc-800 shadow-lg rounded-lg justify-between border border-gray-300 dark:border-zinc-700">
|
<div className="flex flex-col p-6 bg-white dark:bg-zinc-800 shadow-lg rounded-lg justify-between border border-gray-300 dark:border-zinc-700">
|
||||||
<div>
|
<div>
|
||||||
@ -138,7 +137,7 @@ const SubscriptionSetting: React.FC = () => {
|
|||||||
<Link
|
<Link
|
||||||
className="w-full"
|
className="w-full"
|
||||||
underline="none"
|
underline="none"
|
||||||
href="https://yourselfhosted.lemonsqueezy.com/checkout?cart=df958121-81ad-4815-8b28-3f2d8e9c8e51"
|
href="https://yourselfhosted.lemonsqueezy.com/checkout/buy/d03a2696-8a8b-49c9-9e19-d425e3884fd7"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button className="w-full bg-gradient-to-r from-pink-500 to-purple-500 shadow hover:opacity-80">Get Started</Button>
|
<Button className="w-full bg-gradient-to-r from-pink-500 to-purple-500 shadow hover:opacity-80">Get Started</Button>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { createBrowserRouter } from "react-router-dom";
|
import { createBrowserRouter } from "react-router-dom";
|
||||||
|
import NotFound from "@/pages/NotFound";
|
||||||
import SignIn from "@/pages/SignIn";
|
import SignIn from "@/pages/SignIn";
|
||||||
import SignUp from "@/pages/SignUp";
|
import SignUp from "@/pages/SignUp";
|
||||||
import SubscriptionSetting from "@/pages/SubscriptionSetting";
|
import SubscriptionSetting from "@/pages/SubscriptionSetting";
|
||||||
@ -53,6 +54,10 @@ const router = createBrowserRouter([
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "*",
|
||||||
|
element: <NotFound />,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
import { create } from "zustand";
|
|
||||||
import { persist } from "zustand/middleware";
|
|
||||||
import * as api from "../../helpers/api";
|
|
||||||
|
|
||||||
interface FaviconState {
|
|
||||||
cache: {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
getOrFetchUrlFavicon: (url: string) => Promise<string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const useFaviconStore = create<FaviconState>()(
|
|
||||||
persist(
|
|
||||||
(set, get) => ({
|
|
||||||
cache: {},
|
|
||||||
getOrFetchUrlFavicon: async (url: string) => {
|
|
||||||
const cache = get().cache;
|
|
||||||
if (cache[url]) {
|
|
||||||
return cache[url];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { data: favicon } = await api.getUrlFavicon(url);
|
|
||||||
if (favicon) {
|
|
||||||
cache[url] = favicon;
|
|
||||||
set(cache);
|
|
||||||
return favicon;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: "favicon_cache",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
export default useFaviconStore;
|
|
@ -2,6 +2,12 @@ import react from "@vitejs/plugin-react-swc";
|
|||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
|
let devProxyServer = "http://localhost:8082/";
|
||||||
|
if (process.env.DEV_PROXY_SERVER && process.env.DEV_PROXY_SERVER.length > 0) {
|
||||||
|
console.log("Use devProxyServer from environment: ", process.env.DEV_PROXY_SERVER);
|
||||||
|
devProxyServer = process.env.DEV_PROXY_SERVER;
|
||||||
|
}
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
@ -9,13 +15,17 @@ export default defineConfig({
|
|||||||
host: "0.0.0.0",
|
host: "0.0.0.0",
|
||||||
port: 3000,
|
port: 3000,
|
||||||
proxy: {
|
proxy: {
|
||||||
"/api/": {
|
"^/api": {
|
||||||
target: "http://localhost:8082/",
|
target: devProxyServer,
|
||||||
changeOrigin: true,
|
xfwd: true,
|
||||||
},
|
},
|
||||||
"/s/": {
|
"^/slash.api.v2": {
|
||||||
target: "http://localhost:8082/",
|
target: devProxyServer,
|
||||||
changeOrigin: true,
|
xfwd: true,
|
||||||
|
},
|
||||||
|
"^/s/": {
|
||||||
|
target: devProxyServer,
|
||||||
|
xfwd: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
14
go.mod
@ -10,10 +10,10 @@ require (
|
|||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.11.0
|
golang.org/x/crypto v0.14.0
|
||||||
golang.org/x/net v0.12.0 // indirect
|
golang.org/x/net v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.10.0 // indirect
|
golang.org/x/sys v0.13.0 // indirect
|
||||||
golang.org/x/text v0.11.0 // indirect
|
golang.org/x/text v0.13.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,13 +29,10 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PuerkitoBio/goquery v1.6.0 // indirect
|
|
||||||
github.com/andybalholm/cascadia v1.1.0 // indirect
|
|
||||||
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
|
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
|
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/friendsofgo/errors v0.9.2 // indirect
|
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
@ -57,7 +54,6 @@ require (
|
|||||||
go.uber.org/atomic v1.9.0 // indirect
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
go.uber.org/multierr v1.8.0 // indirect
|
go.uber.org/multierr v1.8.0 // indirect
|
||||||
golang.org/x/tools v0.6.0 // indirect
|
golang.org/x/tools v0.6.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
|
||||||
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
@ -82,7 +78,7 @@ require (
|
|||||||
github.com/mssola/useragent v1.0.0
|
github.com/mssola/useragent v1.0.0
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
go.deanishe.net/favicon v0.1.0
|
github.com/posthog/posthog-go v0.0.0-20230801140217-d607812dee69
|
||||||
go.uber.org/zap v1.21.0
|
go.uber.org/zap v1.21.0
|
||||||
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
|
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df
|
||||||
golang.org/x/mod v0.11.0
|
golang.org/x/mod v0.11.0
|
||||||
|
95
go.sum
@ -39,8 +39,6 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
|||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||||
github.com/PuerkitoBio/goquery v1.6.0 h1:j7taAbelrdcsOlGeMenZxc2AWXD5fieT1/znArdnx94=
|
|
||||||
github.com/PuerkitoBio/goquery v1.6.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||||
@ -50,18 +48,14 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
|||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
|
||||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
|
||||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
|
|
||||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
@ -116,8 +110,6 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB
|
|||||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||||
github.com/friendsofgo/errors v0.9.2 h1:X6NYxef4efCBdwI7BgS820zFaN7Cphrmb+Pljdzjtgk=
|
|
||||||
github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||||
@ -135,8 +127,6 @@ github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgO
|
|||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
|
|
||||||
github.com/go-openapi/strfmt v0.19.8/go.mod h1:qBBipho+3EoIqn6YDI+4RnQEtj6jT/IdKm+PAlXxSUc=
|
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
@ -145,32 +135,7 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
|
|||||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
|
|
||||||
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
|
|
||||||
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
|
|
||||||
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
|
||||||
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
|
||||||
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
|
|
||||||
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
|
|
||||||
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
|
|
||||||
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
|
|
||||||
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
|
|
||||||
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
|
|
||||||
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
|
|
||||||
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
|
|
||||||
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
|
|
||||||
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
|
|
||||||
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
|
|
||||||
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
|
||||||
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
|
|
||||||
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
|
|
||||||
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
|
|
||||||
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
|
|
||||||
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
|
|
||||||
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
|
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||||
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||||
@ -217,7 +182,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
|||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
@ -250,7 +214,6 @@ github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbu
|
|||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
@ -304,11 +267,7 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
|||||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||||
github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
|
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
|
||||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
@ -323,18 +282,14 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
|
|||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
|
|
||||||
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
|
||||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=
|
github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=
|
||||||
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
@ -356,8 +311,6 @@ github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0U
|
|||||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
|
||||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
@ -370,7 +323,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
|||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
|
||||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
@ -391,7 +343,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
|||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
|
||||||
github.com/mssola/useragent v1.0.0 h1:WRlDpXyxHDNfvZaPEut5Biveq86Ze4o4EMffyMxmH5o=
|
github.com/mssola/useragent v1.0.0 h1:WRlDpXyxHDNfvZaPEut5Biveq86Ze4o4EMffyMxmH5o=
|
||||||
github.com/mssola/useragent v1.0.0/go.mod h1:hz9Cqz4RXusgg1EdI4Al0INR62kP7aPSRNHnpU+b85Y=
|
github.com/mssola/useragent v1.0.0/go.mod h1:hz9Cqz4RXusgg1EdI4Al0INR62kP7aPSRNHnpU+b85Y=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
@ -425,7 +376,6 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
|
|||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||||
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
|
||||||
@ -440,6 +390,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR
|
|||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
|
github.com/posthog/posthog-go v0.0.0-20230801140217-d607812dee69 h1:01dHVodha5BzrMtVmcpPeA4VYbZEsTXQ6m4123zQXJk=
|
||||||
|
github.com/posthog/posthog-go v0.0.0-20230801140217-d607812dee69/go.mod h1:migYMxlAqcnQy+3eN8mcL0b2tpKy6R+8Zc0lxwk4dKM=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
@ -467,8 +419,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qq
|
|||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
@ -481,8 +431,6 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0
|
|||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
@ -500,7 +448,6 @@ github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUq
|
|||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
|
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
|
||||||
@ -510,14 +457,12 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3
|
|||||||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
@ -526,7 +471,6 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
|
|||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
||||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
@ -534,24 +478,20 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs
|
|||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
|
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
|
||||||
github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.deanishe.net/favicon v0.1.0 h1:Afy941gjRik+DjUUcYHUxcztFEeFse2ITBkMMOlgefM=
|
|
||||||
go.deanishe.net/favicon v0.1.0/go.mod h1:vIKVI+lUh8k3UAzaN4gjC+cpyatLQWmx0hVX4vLE8jU=
|
|
||||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||||
go.mongodb.org/mongo-driver v1.4.2/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
|
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
@ -581,17 +521,15 @@ go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
|||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@ -631,7 +569,6 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@ -674,8 +611,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
|
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -689,7 +626,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -709,13 +645,10 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -762,8 +695,8 @@ golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@ -772,8 +705,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@ -789,13 +722,9 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
|
|||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
@ -844,8 +773,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
|
||||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
@ -39,14 +39,12 @@ message WorkspaceSetting {
|
|||||||
string license_key = 1;
|
string license_key = 1;
|
||||||
// Whether to enable other users to sign up.
|
// Whether to enable other users to sign up.
|
||||||
bool enable_signup = 2;
|
bool enable_signup = 2;
|
||||||
// The relative path of the resource directory.
|
|
||||||
string resource_relative_path = 3;
|
|
||||||
// The custom style.
|
// The custom style.
|
||||||
string custom_style = 4;
|
string custom_style = 3;
|
||||||
// The custom script.
|
// The custom script.
|
||||||
string custom_script = 5;
|
string custom_script = 4;
|
||||||
// The auto backup setting.
|
// The auto backup setting.
|
||||||
AutoBackupWorkspaceSetting auto_backup = 6;
|
AutoBackupWorkspaceSetting auto_backup = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AutoBackupWorkspaceSetting {
|
message AutoBackupWorkspaceSetting {
|
||||||
|
@ -1006,7 +1006,6 @@
|
|||||||
| ----- | ---- | ----- | ----------- |
|
| ----- | ---- | ----- | ----------- |
|
||||||
| license_key | [string](#string) | | |
|
| license_key | [string](#string) | | |
|
||||||
| enable_signup | [bool](#bool) | | Whether to enable other users to sign up. |
|
| enable_signup | [bool](#bool) | | Whether to enable other users to sign up. |
|
||||||
| resource_relative_path | [string](#string) | | The relative path of the resource directory. |
|
|
||||||
| custom_style | [string](#string) | | The custom style. |
|
| custom_style | [string](#string) | | The custom style. |
|
||||||
| custom_script | [string](#string) | | The custom script. |
|
| custom_script | [string](#string) | | The custom script. |
|
||||||
| auto_backup | [AutoBackupWorkspaceSetting](#slash-api-v2-AutoBackupWorkspaceSetting) | | The auto backup setting. |
|
| auto_backup | [AutoBackupWorkspaceSetting](#slash-api-v2-AutoBackupWorkspaceSetting) | | The auto backup setting. |
|
||||||
|
@ -113,14 +113,12 @@ type WorkspaceSetting struct {
|
|||||||
LicenseKey string `protobuf:"bytes,1,opt,name=license_key,json=licenseKey,proto3" json:"license_key,omitempty"`
|
LicenseKey string `protobuf:"bytes,1,opt,name=license_key,json=licenseKey,proto3" json:"license_key,omitempty"`
|
||||||
// Whether to enable other users to sign up.
|
// Whether to enable other users to sign up.
|
||||||
EnableSignup bool `protobuf:"varint,2,opt,name=enable_signup,json=enableSignup,proto3" json:"enable_signup,omitempty"`
|
EnableSignup bool `protobuf:"varint,2,opt,name=enable_signup,json=enableSignup,proto3" json:"enable_signup,omitempty"`
|
||||||
// The relative path of the resource directory.
|
|
||||||
ResourceRelativePath string `protobuf:"bytes,3,opt,name=resource_relative_path,json=resourceRelativePath,proto3" json:"resource_relative_path,omitempty"`
|
|
||||||
// The custom style.
|
// The custom style.
|
||||||
CustomStyle string `protobuf:"bytes,4,opt,name=custom_style,json=customStyle,proto3" json:"custom_style,omitempty"`
|
CustomStyle string `protobuf:"bytes,3,opt,name=custom_style,json=customStyle,proto3" json:"custom_style,omitempty"`
|
||||||
// The custom script.
|
// The custom script.
|
||||||
CustomScript string `protobuf:"bytes,5,opt,name=custom_script,json=customScript,proto3" json:"custom_script,omitempty"`
|
CustomScript string `protobuf:"bytes,4,opt,name=custom_script,json=customScript,proto3" json:"custom_script,omitempty"`
|
||||||
// The auto backup setting.
|
// The auto backup setting.
|
||||||
AutoBackup *AutoBackupWorkspaceSetting `protobuf:"bytes,6,opt,name=auto_backup,json=autoBackup,proto3" json:"auto_backup,omitempty"`
|
AutoBackup *AutoBackupWorkspaceSetting `protobuf:"bytes,5,opt,name=auto_backup,json=autoBackup,proto3" json:"auto_backup,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *WorkspaceSetting) Reset() {
|
func (x *WorkspaceSetting) Reset() {
|
||||||
@ -169,13 +167,6 @@ func (x *WorkspaceSetting) GetEnableSignup() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *WorkspaceSetting) GetResourceRelativePath() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.ResourceRelativePath
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *WorkspaceSetting) GetCustomStyle() string {
|
func (x *WorkspaceSetting) GetCustomStyle() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.CustomStyle
|
return x.CustomStyle
|
||||||
@ -564,101 +555,98 @@ var file_api_v2_workspace_service_proto_rawDesc = []byte{
|
|||||||
0x0b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x23, 0x0a, 0x0d,
|
0x0b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x23, 0x0a, 0x0d,
|
||||||
0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x05, 0x20,
|
0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x05, 0x20,
|
||||||
0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x63, 0x72, 0x69, 0x70,
|
0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x63, 0x72, 0x69, 0x70,
|
||||||
0x74, 0x22, 0xa1, 0x02, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53,
|
0x74, 0x22, 0xeb, 0x01, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53,
|
||||||
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73,
|
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73,
|
||||||
0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x69, 0x63,
|
0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x69, 0x63,
|
||||||
0x65, 0x6e, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
0x65, 0x6e, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
||||||
0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c,
|
0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c,
|
||||||
0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x12, 0x34, 0x0a, 0x16,
|
0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x12, 0x21, 0x0a, 0x0c,
|
||||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76,
|
0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01,
|
||||||
0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x72, 0x65,
|
0x28, 0x09, 0x52, 0x0b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12,
|
||||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61,
|
0x23, 0x0a, 0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
|
||||||
0x74, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x73, 0x74, 0x79,
|
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x63,
|
||||||
0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d,
|
0x72, 0x69, 0x70, 0x74, 0x12, 0x49, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x62, 0x61, 0x63,
|
||||||
0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f,
|
0x6b, 0x75, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6c, 0x61, 0x73,
|
||||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x75,
|
0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x42, 0x61, 0x63,
|
||||||
0x73, 0x74, 0x6f, 0x6d, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x49, 0x0a, 0x0b, 0x61, 0x75,
|
|
||||||
0x74, 0x6f, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
|
||||||
0x28, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x41,
|
|
||||||
0x75, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
|
|
||||||
0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x42,
|
|
||||||
0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x7a, 0x0a, 0x1a, 0x41, 0x75, 0x74, 0x6f, 0x42, 0x61, 0x63,
|
|
||||||
0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74,
|
0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74,
|
||||||
0x69, 0x6e, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01,
|
0x69, 0x6e, 0x67, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22,
|
||||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x27, 0x0a,
|
0x7a, 0x0a, 0x1a, 0x41, 0x75, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72,
|
||||||
0x0f, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x18, 0x0a,
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72,
|
0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07,
|
||||||
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x6b, 0x65,
|
0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x72, 0x6f, 0x6e, 0x5f,
|
||||||
0x65, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x4b, 0x65, 0x65,
|
0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x70, 0x22, 0x1c, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
|
0x52, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||||
0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22,
|
0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x6b, 0x65, 0x65, 0x70, 0x18, 0x03, 0x20, 0x01,
|
||||||
0x57, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50,
|
0x28, 0x05, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x4b, 0x65, 0x65, 0x70, 0x22, 0x1c, 0x0a, 0x1a, 0x47,
|
||||||
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38,
|
0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69,
|
||||||
0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x57, 0x0a, 0x1b, 0x47, 0x65, 0x74,
|
||||||
0x1e, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x57,
|
0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
|
||||||
0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52,
|
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x66,
|
||||||
0x07, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x57,
|
0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x6c, 0x61, 0x73,
|
||||||
0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52,
|
0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x57, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72,
|
0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x66, 0x69,
|
||||||
0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73,
|
0x6c, 0x65, 0x22, 0x1c, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
|
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61,
|
|
||||||
0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53,
|
|
||||||
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x22,
|
|
||||||
0x7a, 0x0a, 0x1d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
|
|
||||||
0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
0x12, 0x38, 0x0a, 0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28,
|
0x22, 0x57, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
|
||||||
0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32,
|
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
0x38, 0x0a, 0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||||
0x67, 0x52, 0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70,
|
0x32, 0x1e, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e,
|
||||||
0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
|
0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
|
||||||
0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x5a, 0x0a, 0x1e, 0x55,
|
0x52, 0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x7a, 0x0a, 0x1d, 0x55, 0x70, 0x64,
|
||||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65,
|
0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74,
|
||||||
0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a,
|
0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x07, 0x73, 0x65,
|
||||||
0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e,
|
0x74, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x6c,
|
||||||
0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x6f,
|
0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73,
|
||||||
0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07,
|
0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x65, 0x74,
|
||||||
0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x32, 0xce, 0x03, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b,
|
0x74, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d,
|
||||||
0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x8d, 0x01, 0x0a,
|
0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74,
|
||||||
0x13, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f,
|
0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x5a, 0x0a, 0x1e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57,
|
||||||
0x66, 0x69, 0x6c, 0x65, 0x12, 0x28, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69,
|
0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52,
|
||||||
0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x07, 0x73, 0x65, 0x74, 0x74, 0x69,
|
||||||
0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29,
|
0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68,
|
||||||
|
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
|
||||||
|
0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||||
|
0x67, 0x32, 0xce, 0x03, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53,
|
||||||
|
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x8d, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x57, 0x6f,
|
||||||
|
0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x28,
|
||||||
0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65,
|
0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65,
|
||||||
0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
|
0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
|
||||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68,
|
||||||
0x1b, 0x12, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73,
|
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73,
|
||||||
0x70, 0x61, 0x63, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x8d, 0x01, 0x0a,
|
0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
0x13, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74,
|
0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x61, 0x70,
|
||||||
0x74, 0x69, 0x6e, 0x67, 0x12, 0x28, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69,
|
0x69, 0x2f, 0x76, 0x32, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x70,
|
||||||
0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
|
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x8d, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x57, 0x6f,
|
||||||
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29,
|
0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x28,
|
||||||
0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65,
|
0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65,
|
||||||
0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||||
0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68,
|
||||||
0x1b, 0x12, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73,
|
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73,
|
||||||
0x70, 0x61, 0x63, 0x65, 0x2f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x99, 0x01, 0x0a,
|
0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
|
0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x61, 0x70,
|
||||||
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x2b, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e,
|
0x69, 0x2f, 0x76, 0x32, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x73,
|
||||||
0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72,
|
0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x99, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74,
|
||||||
0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71,
|
0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69,
|
0x67, 0x12, 0x2b, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32,
|
||||||
0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70,
|
0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
|
||||||
0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c,
|
||||||
0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x3a, 0x01, 0x2a, 0x22, 0x19, 0x2f,
|
0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x55, 0x70,
|
||||||
0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
|
0x64, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74,
|
||||||
0x2f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x42, 0xac, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d,
|
0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3,
|
||||||
0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x15, 0x57,
|
0xe4, 0x93, 0x02, 0x1e, 0x3a, 0x01, 0x2a, 0x22, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32,
|
||||||
0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50,
|
0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x2f, 0x73, 0x65, 0x74, 0x74, 0x69,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
0x6e, 0x67, 0x42, 0xac, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68,
|
||||||
0x6f, 0x6d, 0x2f, 0x62, 0x6f, 0x6f, 0x6a, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6c, 0x61, 0x73, 0x68,
|
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
|
||||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76,
|
0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01,
|
||||||
0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x53, 0x41, 0x58, 0xaa, 0x02, 0x0c,
|
0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f, 0x6f,
|
||||||
0x53, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c, 0x53,
|
0x6a, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
0x6c, 0x61, 0x73, 0x68, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, 0x53, 0x6c,
|
0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76,
|
||||||
0x61, 0x73, 0x68, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65,
|
0x32, 0xa2, 0x02, 0x03, 0x53, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x2e,
|
||||||
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x3a, 0x3a,
|
0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x41,
|
||||||
0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x41, 0x70,
|
||||||
|
0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
|
||||||
|
0xea, 0x02, 0x0e, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56,
|
||||||
|
0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -310,7 +310,6 @@
|
|||||||
| license_key | [string](#string) | | |
|
| license_key | [string](#string) | | |
|
||||||
| secret_session | [string](#string) | | |
|
| secret_session | [string](#string) | | |
|
||||||
| enable_signup | [bool](#bool) | | |
|
| enable_signup | [bool](#bool) | | |
|
||||||
| resource_relative_path | [string](#string) | | |
|
|
||||||
| custom_style | [string](#string) | | |
|
| custom_style | [string](#string) | | |
|
||||||
| custom_script | [string](#string) | | |
|
| custom_script | [string](#string) | | |
|
||||||
| auto_backup | [AutoBackupWorkspaceSetting](#slash-store-AutoBackupWorkspaceSetting) | | |
|
| auto_backup | [AutoBackupWorkspaceSetting](#slash-store-AutoBackupWorkspaceSetting) | | |
|
||||||
@ -333,10 +332,9 @@
|
|||||||
| WORKSPACE_SETTING_LICENSE_KEY | 1 | The license key. |
|
| WORKSPACE_SETTING_LICENSE_KEY | 1 | The license key. |
|
||||||
| WORKSPACE_SETTING_SECRET_SESSION | 2 | The secret session key used to encrypt session data. |
|
| WORKSPACE_SETTING_SECRET_SESSION | 2 | The secret session key used to encrypt session data. |
|
||||||
| WORKSAPCE_SETTING_ENABLE_SIGNUP | 3 | Whether to enable other users to sign up. |
|
| WORKSAPCE_SETTING_ENABLE_SIGNUP | 3 | Whether to enable other users to sign up. |
|
||||||
| WORKSPACE_SETTING_RESOURCE_RELATIVE_PATH | 4 | The relative path of the resource directory. |
|
| WORKSPACE_SETTING_CUSTOM_STYLE | 4 | The custom style. |
|
||||||
| WORKSPACE_SETTING_CUSTOM_STYLE | 5 | The custom style. |
|
| WORKSPACE_SETTING_CUSTOM_SCRIPT | 5 | The custom script. |
|
||||||
| WORKSPACE_SETTING_CUSTOM_SCRIPT | 6 | The custom script. |
|
| WORKSPACE_SETTING_AUTO_BACKUP | 6 | The auto backup setting. |
|
||||||
| WORKSPACE_SETTING_AUTO_BACKUP | 7 | The auto backup setting. |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,14 +30,12 @@ const (
|
|||||||
WorkspaceSettingKey_WORKSPACE_SETTING_SECRET_SESSION WorkspaceSettingKey = 2
|
WorkspaceSettingKey_WORKSPACE_SETTING_SECRET_SESSION WorkspaceSettingKey = 2
|
||||||
// Whether to enable other users to sign up.
|
// Whether to enable other users to sign up.
|
||||||
WorkspaceSettingKey_WORKSAPCE_SETTING_ENABLE_SIGNUP WorkspaceSettingKey = 3
|
WorkspaceSettingKey_WORKSAPCE_SETTING_ENABLE_SIGNUP WorkspaceSettingKey = 3
|
||||||
// The relative path of the resource directory.
|
|
||||||
WorkspaceSettingKey_WORKSPACE_SETTING_RESOURCE_RELATIVE_PATH WorkspaceSettingKey = 4
|
|
||||||
// The custom style.
|
// The custom style.
|
||||||
WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE WorkspaceSettingKey = 5
|
WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE WorkspaceSettingKey = 4
|
||||||
// The custom script.
|
// The custom script.
|
||||||
WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_SCRIPT WorkspaceSettingKey = 6
|
WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_SCRIPT WorkspaceSettingKey = 5
|
||||||
// The auto backup setting.
|
// The auto backup setting.
|
||||||
WorkspaceSettingKey_WORKSPACE_SETTING_AUTO_BACKUP WorkspaceSettingKey = 7
|
WorkspaceSettingKey_WORKSPACE_SETTING_AUTO_BACKUP WorkspaceSettingKey = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enum value maps for WorkspaceSettingKey.
|
// Enum value maps for WorkspaceSettingKey.
|
||||||
@ -47,20 +45,18 @@ var (
|
|||||||
1: "WORKSPACE_SETTING_LICENSE_KEY",
|
1: "WORKSPACE_SETTING_LICENSE_KEY",
|
||||||
2: "WORKSPACE_SETTING_SECRET_SESSION",
|
2: "WORKSPACE_SETTING_SECRET_SESSION",
|
||||||
3: "WORKSAPCE_SETTING_ENABLE_SIGNUP",
|
3: "WORKSAPCE_SETTING_ENABLE_SIGNUP",
|
||||||
4: "WORKSPACE_SETTING_RESOURCE_RELATIVE_PATH",
|
4: "WORKSPACE_SETTING_CUSTOM_STYLE",
|
||||||
5: "WORKSPACE_SETTING_CUSTOM_STYLE",
|
5: "WORKSPACE_SETTING_CUSTOM_SCRIPT",
|
||||||
6: "WORKSPACE_SETTING_CUSTOM_SCRIPT",
|
6: "WORKSPACE_SETTING_AUTO_BACKUP",
|
||||||
7: "WORKSPACE_SETTING_AUTO_BACKUP",
|
|
||||||
}
|
}
|
||||||
WorkspaceSettingKey_value = map[string]int32{
|
WorkspaceSettingKey_value = map[string]int32{
|
||||||
"WORKSPACE_SETTING_KEY_UNSPECIFIED": 0,
|
"WORKSPACE_SETTING_KEY_UNSPECIFIED": 0,
|
||||||
"WORKSPACE_SETTING_LICENSE_KEY": 1,
|
"WORKSPACE_SETTING_LICENSE_KEY": 1,
|
||||||
"WORKSPACE_SETTING_SECRET_SESSION": 2,
|
"WORKSPACE_SETTING_SECRET_SESSION": 2,
|
||||||
"WORKSAPCE_SETTING_ENABLE_SIGNUP": 3,
|
"WORKSAPCE_SETTING_ENABLE_SIGNUP": 3,
|
||||||
"WORKSPACE_SETTING_RESOURCE_RELATIVE_PATH": 4,
|
"WORKSPACE_SETTING_CUSTOM_STYLE": 4,
|
||||||
"WORKSPACE_SETTING_CUSTOM_STYLE": 5,
|
"WORKSPACE_SETTING_CUSTOM_SCRIPT": 5,
|
||||||
"WORKSPACE_SETTING_CUSTOM_SCRIPT": 6,
|
"WORKSPACE_SETTING_AUTO_BACKUP": 6,
|
||||||
"WORKSPACE_SETTING_AUTO_BACKUP": 7,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -102,7 +98,6 @@ type WorkspaceSetting struct {
|
|||||||
// *WorkspaceSetting_LicenseKey
|
// *WorkspaceSetting_LicenseKey
|
||||||
// *WorkspaceSetting_SecretSession
|
// *WorkspaceSetting_SecretSession
|
||||||
// *WorkspaceSetting_EnableSignup
|
// *WorkspaceSetting_EnableSignup
|
||||||
// *WorkspaceSetting_ResourceRelativePath
|
|
||||||
// *WorkspaceSetting_CustomStyle
|
// *WorkspaceSetting_CustomStyle
|
||||||
// *WorkspaceSetting_CustomScript
|
// *WorkspaceSetting_CustomScript
|
||||||
// *WorkspaceSetting_AutoBackup
|
// *WorkspaceSetting_AutoBackup
|
||||||
@ -176,13 +171,6 @@ func (x *WorkspaceSetting) GetEnableSignup() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *WorkspaceSetting) GetResourceRelativePath() string {
|
|
||||||
if x, ok := x.GetValue().(*WorkspaceSetting_ResourceRelativePath); ok {
|
|
||||||
return x.ResourceRelativePath
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *WorkspaceSetting) GetCustomStyle() string {
|
func (x *WorkspaceSetting) GetCustomStyle() string {
|
||||||
if x, ok := x.GetValue().(*WorkspaceSetting_CustomStyle); ok {
|
if x, ok := x.GetValue().(*WorkspaceSetting_CustomStyle); ok {
|
||||||
return x.CustomStyle
|
return x.CustomStyle
|
||||||
@ -220,20 +208,16 @@ type WorkspaceSetting_EnableSignup struct {
|
|||||||
EnableSignup bool `protobuf:"varint,4,opt,name=enable_signup,json=enableSignup,proto3,oneof"`
|
EnableSignup bool `protobuf:"varint,4,opt,name=enable_signup,json=enableSignup,proto3,oneof"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkspaceSetting_ResourceRelativePath struct {
|
|
||||||
ResourceRelativePath string `protobuf:"bytes,5,opt,name=resource_relative_path,json=resourceRelativePath,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WorkspaceSetting_CustomStyle struct {
|
type WorkspaceSetting_CustomStyle struct {
|
||||||
CustomStyle string `protobuf:"bytes,6,opt,name=custom_style,json=customStyle,proto3,oneof"`
|
CustomStyle string `protobuf:"bytes,5,opt,name=custom_style,json=customStyle,proto3,oneof"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkspaceSetting_CustomScript struct {
|
type WorkspaceSetting_CustomScript struct {
|
||||||
CustomScript string `protobuf:"bytes,7,opt,name=custom_script,json=customScript,proto3,oneof"`
|
CustomScript string `protobuf:"bytes,6,opt,name=custom_script,json=customScript,proto3,oneof"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkspaceSetting_AutoBackup struct {
|
type WorkspaceSetting_AutoBackup struct {
|
||||||
AutoBackup *AutoBackupWorkspaceSetting `protobuf:"bytes,8,opt,name=auto_backup,json=autoBackup,proto3,oneof"`
|
AutoBackup *AutoBackupWorkspaceSetting `protobuf:"bytes,7,opt,name=auto_backup,json=autoBackup,proto3,oneof"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*WorkspaceSetting_LicenseKey) isWorkspaceSetting_Value() {}
|
func (*WorkspaceSetting_LicenseKey) isWorkspaceSetting_Value() {}
|
||||||
@ -242,8 +226,6 @@ func (*WorkspaceSetting_SecretSession) isWorkspaceSetting_Value() {}
|
|||||||
|
|
||||||
func (*WorkspaceSetting_EnableSignup) isWorkspaceSetting_Value() {}
|
func (*WorkspaceSetting_EnableSignup) isWorkspaceSetting_Value() {}
|
||||||
|
|
||||||
func (*WorkspaceSetting_ResourceRelativePath) isWorkspaceSetting_Value() {}
|
|
||||||
|
|
||||||
func (*WorkspaceSetting_CustomStyle) isWorkspaceSetting_Value() {}
|
func (*WorkspaceSetting_CustomStyle) isWorkspaceSetting_Value() {}
|
||||||
|
|
||||||
func (*WorkspaceSetting_CustomScript) isWorkspaceSetting_Value() {}
|
func (*WorkspaceSetting_CustomScript) isWorkspaceSetting_Value() {}
|
||||||
@ -323,7 +305,7 @@ var File_store_workspace_setting_proto protoreflect.FileDescriptor
|
|||||||
var file_store_workspace_setting_proto_rawDesc = []byte{
|
var file_store_workspace_setting_proto_rawDesc = []byte{
|
||||||
0x0a, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
|
0x0a, 0x1d, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
|
||||||
0x65, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
0x65, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||||
0x0b, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x92, 0x03, 0x0a,
|
0x0b, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, 0xda, 0x02, 0x0a,
|
||||||
0x10, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
0x10, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
|
||||||
0x67, 0x12, 0x32, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20,
|
0x67, 0x12, 0x32, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20,
|
||||||
0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x57, 0x6f, 0x72,
|
0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x57, 0x6f, 0x72,
|
||||||
@ -335,59 +317,53 @@ var file_store_workspace_setting_proto_rawDesc = []byte{
|
|||||||
0x48, 0x00, 0x52, 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
|
0x48, 0x00, 0x52, 0x0d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f,
|
||||||
0x6e, 0x12, 0x25, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e,
|
0x6e, 0x12, 0x25, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e,
|
||||||
0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62,
|
0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62,
|
||||||
0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x12, 0x36, 0x0a, 0x16, 0x72, 0x65, 0x73, 0x6f,
|
0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x12, 0x23, 0x0a, 0x0c, 0x63, 0x75, 0x73, 0x74,
|
||||||
0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61,
|
0x6f, 0x6d, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,
|
||||||
0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f,
|
0x52, 0x0b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x25, 0x0a,
|
||||||
0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68,
|
0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x06,
|
||||||
0x12, 0x23, 0x0a, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65,
|
0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x63,
|
||||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d,
|
0x72, 0x69, 0x70, 0x74, 0x12, 0x4a, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x62, 0x61, 0x63,
|
||||||
0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x25, 0x0a, 0x0d, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f,
|
0x6b, 0x75, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x6c, 0x61, 0x73,
|
||||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c,
|
0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b,
|
||||||
0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x4a, 0x0a, 0x0b,
|
0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69,
|
||||||
0x61, 0x75, 0x74, 0x6f, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28,
|
0x6e, 0x67, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,
|
||||||
0x0b, 0x32, 0x27, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e,
|
0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x7a, 0x0a, 0x1a, 0x41, 0x75, 0x74,
|
||||||
0x41, 0x75, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70,
|
0x6f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
|
||||||
0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x75,
|
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c,
|
||||||
0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
|
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
|
||||||
0x65, 0x22, 0x7a, 0x0a, 0x1a, 0x41, 0x75, 0x74, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x57,
|
0x64, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73,
|
||||||
0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12,
|
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x6f, 0x6e,
|
||||||
0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
|
0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61,
|
||||||
0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x72, 0x6f,
|
0x78, 0x5f, 0x6b, 0x65, 0x65, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6d, 0x61,
|
||||||
0x6e, 0x5f, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
|
0x78, 0x4b, 0x65, 0x65, 0x70, 0x2a, 0x96, 0x02, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70,
|
||||||
0x28, 0x09, 0x52, 0x0e, 0x63, 0x72, 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69,
|
0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a,
|
||||||
0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x6b, 0x65, 0x65, 0x70, 0x18, 0x03,
|
0x21, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49,
|
||||||
0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x4b, 0x65, 0x65, 0x70, 0x2a, 0xc4, 0x02,
|
0x4e, 0x47, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
|
||||||
0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69,
|
0x45, 0x44, 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43,
|
||||||
0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x21, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41,
|
0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53,
|
||||||
0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x55,
|
0x45, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x57, 0x4f, 0x52, 0x4b, 0x53,
|
||||||
0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d,
|
0x50, 0x41, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x45, 0x43,
|
||||||
0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e,
|
0x52, 0x45, 0x54, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x23, 0x0a,
|
||||||
0x47, 0x5f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x01, 0x12,
|
0x1f, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x41, 0x50, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49,
|
||||||
0x24, 0x0a, 0x20, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54,
|
0x4e, 0x47, 0x5f, 0x45, 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x55, 0x50,
|
||||||
0x54, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x45, 0x43, 0x52, 0x45, 0x54, 0x5f, 0x53, 0x45, 0x53, 0x53,
|
0x10, 0x03, 0x12, 0x22, 0x0a, 0x1e, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f,
|
||||||
0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x23, 0x0a, 0x1f, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x41, 0x50,
|
0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x5f, 0x53,
|
||||||
0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x4e, 0x41, 0x42, 0x4c,
|
0x54, 0x59, 0x4c, 0x45, 0x10, 0x04, 0x12, 0x23, 0x0a, 0x1f, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50,
|
||||||
0x45, 0x5f, 0x53, 0x49, 0x47, 0x4e, 0x55, 0x50, 0x10, 0x03, 0x12, 0x2c, 0x0a, 0x28, 0x57, 0x4f,
|
0x41, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x55, 0x53, 0x54,
|
||||||
0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f,
|
0x4f, 0x4d, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x10, 0x05, 0x12, 0x21, 0x0a, 0x1d, 0x57,
|
||||||
0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x52, 0x45, 0x4c, 0x41, 0x54, 0x49, 0x56,
|
0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47,
|
||||||
0x45, 0x5f, 0x50, 0x41, 0x54, 0x48, 0x10, 0x04, 0x12, 0x22, 0x0a, 0x1e, 0x57, 0x4f, 0x52, 0x4b,
|
0x5f, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x42, 0x41, 0x43, 0x4b, 0x55, 0x50, 0x10, 0x06, 0x42, 0x9f,
|
||||||
0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x43, 0x55,
|
0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f,
|
||||||
0x53, 0x54, 0x4f, 0x4d, 0x5f, 0x53, 0x54, 0x59, 0x4c, 0x45, 0x10, 0x05, 0x12, 0x23, 0x0a, 0x1f,
|
0x72, 0x65, 0x42, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74,
|
||||||
0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e,
|
0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x28, 0x67, 0x69, 0x74,
|
||||||
0x47, 0x5f, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x5f, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x10,
|
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f, 0x6f, 0x6a, 0x61, 0x63, 0x6b, 0x2f,
|
||||||
0x06, 0x12, 0x21, 0x0a, 0x1d, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x53,
|
0x73, 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f,
|
||||||
0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x42, 0x41, 0x43, 0x4b,
|
0x73, 0x74, 0x6f, 0x72, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x53, 0x6c,
|
||||||
0x55, 0x50, 0x10, 0x07, 0x42, 0x9f, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61,
|
0x61, 0x73, 0x68, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x53, 0x6c, 0x61, 0x73,
|
||||||
0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70,
|
0x68, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c,
|
||||||
0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
|
0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
|
||||||
0x01, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6f,
|
0x61, 0xea, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65,
|
||||||
0x6f, 0x6a, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x53,
|
|
||||||
0x58, 0xaa, 0x02, 0x0b, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca,
|
|
||||||
0x02, 0x0b, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17,
|
|
||||||
0x53, 0x6c, 0x61, 0x73, 0x68, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d,
|
|
||||||
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x3a,
|
|
||||||
0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -454,7 +430,6 @@ func file_store_workspace_setting_proto_init() {
|
|||||||
(*WorkspaceSetting_LicenseKey)(nil),
|
(*WorkspaceSetting_LicenseKey)(nil),
|
||||||
(*WorkspaceSetting_SecretSession)(nil),
|
(*WorkspaceSetting_SecretSession)(nil),
|
||||||
(*WorkspaceSetting_EnableSignup)(nil),
|
(*WorkspaceSetting_EnableSignup)(nil),
|
||||||
(*WorkspaceSetting_ResourceRelativePath)(nil),
|
|
||||||
(*WorkspaceSetting_CustomStyle)(nil),
|
(*WorkspaceSetting_CustomStyle)(nil),
|
||||||
(*WorkspaceSetting_CustomScript)(nil),
|
(*WorkspaceSetting_CustomScript)(nil),
|
||||||
(*WorkspaceSetting_AutoBackup)(nil),
|
(*WorkspaceSetting_AutoBackup)(nil),
|
||||||
|
@ -11,10 +11,9 @@ message WorkspaceSetting {
|
|||||||
string license_key = 2;
|
string license_key = 2;
|
||||||
string secret_session = 3;
|
string secret_session = 3;
|
||||||
bool enable_signup = 4;
|
bool enable_signup = 4;
|
||||||
string resource_relative_path = 5;
|
string custom_style = 5;
|
||||||
string custom_style = 6;
|
string custom_script = 6;
|
||||||
string custom_script = 7;
|
AutoBackupWorkspaceSetting auto_backup = 7;
|
||||||
AutoBackupWorkspaceSetting auto_backup = 8;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,14 +25,12 @@ enum WorkspaceSettingKey {
|
|||||||
WORKSPACE_SETTING_SECRET_SESSION = 2;
|
WORKSPACE_SETTING_SECRET_SESSION = 2;
|
||||||
// Whether to enable other users to sign up.
|
// Whether to enable other users to sign up.
|
||||||
WORKSAPCE_SETTING_ENABLE_SIGNUP = 3;
|
WORKSAPCE_SETTING_ENABLE_SIGNUP = 3;
|
||||||
// The relative path of the resource directory.
|
|
||||||
WORKSPACE_SETTING_RESOURCE_RELATIVE_PATH = 4;
|
|
||||||
// The custom style.
|
// The custom style.
|
||||||
WORKSPACE_SETTING_CUSTOM_STYLE = 5;
|
WORKSPACE_SETTING_CUSTOM_STYLE = 4;
|
||||||
// The custom script.
|
// The custom script.
|
||||||
WORKSPACE_SETTING_CUSTOM_SCRIPT = 6;
|
WORKSPACE_SETTING_CUSTOM_SCRIPT = 5;
|
||||||
// The auto backup setting.
|
// The auto backup setting.
|
||||||
WORKSPACE_SETTING_AUTO_BACKUP = 7;
|
WORKSPACE_SETTING_AUTO_BACKUP = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AutoBackupWorkspaceSetting {
|
message AutoBackupWorkspaceSetting {
|
||||||
|
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 257 KiB |
Before Width: | Height: | Size: 3.5 KiB |
@ -3,7 +3,7 @@ tmp_dir = ".air"
|
|||||||
|
|
||||||
[build]
|
[build]
|
||||||
bin = "./.air/slash --mode dev"
|
bin = "./.air/slash --mode dev"
|
||||||
cmd = "go build -o ./.air/slash ./cmd/slash/main.go"
|
cmd = "go build -o ./.air/slash ./bin/slash/main.go"
|
||||||
delay = 1000
|
delay = 1000
|
||||||
exclude_dir = [".air", "frontend", "build"]
|
exclude_dir = [".air", "frontend", "build"]
|
||||||
exclude_file = []
|
exclude_file = []
|
||||||
|
51
server/metric/metric.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package metric
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/posthog/posthog-go"
|
||||||
|
|
||||||
|
"github.com/boojack/slash/server/profile"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PostHogAPIKey = "phc_YFEi1aqUBW9sX2KDzdvMtK43DNu0mkeoKMKc0EQum2t"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
client *MetricClient
|
||||||
|
)
|
||||||
|
|
||||||
|
type MetricClient struct {
|
||||||
|
workspaceID string
|
||||||
|
profile *profile.Profile
|
||||||
|
phClient *posthog.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMetricClient(workspaceID string, profile profile.Profile) (*MetricClient, error) {
|
||||||
|
phClient, err := posthog.NewWithConfig(PostHogAPIKey, posthog.Config{
|
||||||
|
Endpoint: "https://app.posthog.com",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
client = &MetricClient{
|
||||||
|
workspaceID: workspaceID,
|
||||||
|
profile: &profile,
|
||||||
|
phClient: &phClient,
|
||||||
|
}
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Enqueue(event string) {
|
||||||
|
if client == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if client.profile.Mode != "prod" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
|
(*client.phClient).Enqueue(posthog.Capture{
|
||||||
|
DistinctId: `slash-` + client.workspaceID,
|
||||||
|
Event: event,
|
||||||
|
})
|
||||||
|
}
|
@ -18,8 +18,10 @@ import (
|
|||||||
apiv2 "github.com/boojack/slash/api/v2"
|
apiv2 "github.com/boojack/slash/api/v2"
|
||||||
"github.com/boojack/slash/internal/log"
|
"github.com/boojack/slash/internal/log"
|
||||||
storepb "github.com/boojack/slash/proto/gen/store"
|
storepb "github.com/boojack/slash/proto/gen/store"
|
||||||
|
"github.com/boojack/slash/server/metric"
|
||||||
"github.com/boojack/slash/server/profile"
|
"github.com/boojack/slash/server/profile"
|
||||||
"github.com/boojack/slash/server/service/license"
|
"github.com/boojack/slash/server/service/license"
|
||||||
|
"github.com/boojack/slash/server/service/resource"
|
||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,6 +30,7 @@ type Server struct {
|
|||||||
|
|
||||||
Profile *profile.Profile
|
Profile *profile.Profile
|
||||||
Store *store.Store
|
Store *store.Store
|
||||||
|
Secret string
|
||||||
|
|
||||||
licenseService *license.LicenseService
|
licenseService *license.LicenseService
|
||||||
|
|
||||||
@ -92,11 +95,12 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
|
|||||||
secret := "slash"
|
secret := "slash"
|
||||||
if profile.Mode == "prod" {
|
if profile.Mode == "prod" {
|
||||||
var err error
|
var err error
|
||||||
secret, err = s.getSystemSecretSessionName(ctx)
|
secret, err = s.getSecretSessionName(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s.Secret = secret
|
||||||
|
|
||||||
rootGroup := e.Group("")
|
rootGroup := e.Group("")
|
||||||
// Register API v1 routes.
|
// Register API v1 routes.
|
||||||
@ -110,7 +114,7 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register resource service.
|
// Register resource service.
|
||||||
resourceService := NewResourceService(profile, store)
|
resourceService := resource.NewResourceService(profile, store)
|
||||||
resourceService.Register(rootGroup)
|
resourceService.Register(rootGroup)
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
@ -132,6 +136,7 @@ func (s *Server) Start(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
metric.Enqueue("server start")
|
||||||
return s.e.Start(fmt.Sprintf(":%d", s.Profile.Port))
|
return s.e.Start(fmt.Sprintf(":%d", s.Profile.Port))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +165,7 @@ func grpcRequestSkipper(c echo.Context) bool {
|
|||||||
return strings.HasPrefix(c.Request().URL.Path, "/slash.api.v2.")
|
return strings.HasPrefix(c.Request().URL.Path, "/slash.api.v2.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getSystemSecretSessionName(ctx context.Context) (string, error) {
|
func (s *Server) getSecretSessionName(ctx context.Context) (string, error) {
|
||||||
secretSessionSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
|
secretSessionSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
|
||||||
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SECRET_SESSION,
|
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_SECRET_SESSION,
|
||||||
})
|
})
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package server
|
package resource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -9,11 +9,14 @@ import (
|
|||||||
"github.com/h2non/filetype"
|
"github.com/h2non/filetype"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
|
||||||
storepb "github.com/boojack/slash/proto/gen/store"
|
|
||||||
"github.com/boojack/slash/server/profile"
|
"github.com/boojack/slash/server/profile"
|
||||||
"github.com/boojack/slash/store"
|
"github.com/boojack/slash/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
resourceRelativePath = "resources"
|
||||||
|
)
|
||||||
|
|
||||||
type ResourceService struct {
|
type ResourceService struct {
|
||||||
Profile *profile.Profile
|
Profile *profile.Profile
|
||||||
Store *store.Store
|
Store *store.Store
|
||||||
@ -27,21 +30,9 @@ func NewResourceService(profile *profile.Profile, store *store.Store) *ResourceS
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register registers the resource service to the echo server.
|
// Register registers the resource service to the echo server.
|
||||||
func (s *ResourceService) Register(g *echo.Group) {
|
func (*ResourceService) Register(g *echo.Group) {
|
||||||
g.GET("/resources/:id", func(c echo.Context) error {
|
g.GET("/resources/:id", func(c echo.Context) error {
|
||||||
ctx := c.Request().Context()
|
|
||||||
resourceID := c.Param("resourceId")
|
resourceID := c.Param("resourceId")
|
||||||
resourceRelativePathSetting, err := s.Store.GetWorkspaceSetting(ctx, &store.FindWorkspaceSetting{
|
|
||||||
Key: storepb.WorkspaceSettingKey_WORKSPACE_SETTING_RESOURCE_RELATIVE_PATH,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, "failed to workspace resource relative path setting").SetInternal(err)
|
|
||||||
}
|
|
||||||
if resourceRelativePathSetting == nil {
|
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, "found no workspace resource relative path setting")
|
|
||||||
}
|
|
||||||
|
|
||||||
resourceRelativePath := resourceRelativePathSetting.GetResourceRelativePath()
|
|
||||||
resourcePath := fmt.Sprintf("%s/%s", resourceRelativePath, resourceID)
|
resourcePath := fmt.Sprintf("%s/%s", resourceRelativePath, resourceID)
|
||||||
buf, err := os.ReadFile(resourcePath)
|
buf, err := os.ReadFile(resourcePath)
|
||||||
if err != nil {
|
if err != nil {
|
@ -9,10 +9,10 @@ import (
|
|||||||
|
|
||||||
// Version is the service current released version.
|
// Version is the service current released version.
|
||||||
// Semantic versioning: https://semver.org/
|
// Semantic versioning: https://semver.org/
|
||||||
var Version = "0.4.4"
|
var Version = "0.4.6"
|
||||||
|
|
||||||
// DevVersion is the service current development version.
|
// DevVersion is the service current development version.
|
||||||
var DevVersion = "0.4.4"
|
var DevVersion = "0.4.6"
|
||||||
|
|
||||||
func GetCurrentVersion(mode string) string {
|
func GetCurrentVersion(mode string) string {
|
||||||
if mode == "dev" || mode == "demo" {
|
if mode == "dev" || mode == "demo" {
|
||||||
|
115
store/db/db.go
@ -62,72 +62,80 @@ func (db *DB) Open(ctx context.Context) (err error) {
|
|||||||
return errors.Wrapf(err, "failed to open db with dsn: %s", db.profile.DSN)
|
return errors.Wrapf(err, "failed to open db with dsn: %s", db.profile.DSN)
|
||||||
}
|
}
|
||||||
db.DBInstance = sqliteDB
|
db.DBInstance = sqliteDB
|
||||||
|
currentVersion := version.GetCurrentVersion(db.profile.Mode)
|
||||||
|
|
||||||
if db.profile.Mode == "prod" {
|
if db.profile.Mode == "prod" {
|
||||||
_, err := os.Stat(db.profile.DSN)
|
_, err := os.Stat(db.profile.DSN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If db file not exists, we should create a new one with latest schema.
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
|
||||||
if err := db.applyLatestSchema(ctx); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to apply latest schema")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return errors.Wrap(err, "failed to get db file stat")
|
return errors.Wrap(err, "failed to get db file stat")
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// If db file exists, we should check if we need to migrate the database.
|
// If db file not exists, we should create a new one with latest schema.
|
||||||
currentVersion := version.GetCurrentVersion(db.profile.Mode)
|
err := db.applyLatestSchema(ctx)
|
||||||
migrationHistoryList, err := db.FindMigrationHistoryList(ctx, &MigrationHistoryFind{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to find migration history")
|
return errors.Wrap(err, "failed to apply latest schema")
|
||||||
}
|
}
|
||||||
if len(migrationHistoryList) == 0 {
|
_, err = db.UpsertMigrationHistory(ctx, &MigrationHistoryUpsert{
|
||||||
_, err := db.UpsertMigrationHistory(ctx, &MigrationHistoryUpsert{
|
Version: currentVersion,
|
||||||
Version: currentVersion,
|
})
|
||||||
})
|
if err != nil {
|
||||||
if err != nil {
|
return errors.Wrap(err, "failed to upsert migration history")
|
||||||
return errors.Wrap(err, "failed to upsert migration history")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
migrationHistoryVersionList := []string{}
|
// If db file exists, we should check if we need to migrate the database.
|
||||||
for _, migrationHistory := range migrationHistoryList {
|
migrationHistoryList, err := db.FindMigrationHistoryList(ctx, &MigrationHistoryFind{})
|
||||||
migrationHistoryVersionList = append(migrationHistoryVersionList, migrationHistory.Version)
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to find migration history")
|
||||||
|
}
|
||||||
|
if len(migrationHistoryList) == 0 {
|
||||||
|
_, err := db.UpsertMigrationHistory(ctx, &MigrationHistoryUpsert{
|
||||||
|
Version: currentVersion,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to upsert migration history")
|
||||||
}
|
}
|
||||||
sort.Sort(version.SortVersion(migrationHistoryVersionList))
|
return nil
|
||||||
latestMigrationHistoryVersion := migrationHistoryVersionList[len(migrationHistoryVersionList)-1]
|
}
|
||||||
|
|
||||||
if version.IsVersionGreaterThan(version.GetSchemaVersion(currentVersion), latestMigrationHistoryVersion) {
|
migrationHistoryVersionList := []string{}
|
||||||
minorVersionList := getMinorVersionList()
|
for _, migrationHistory := range migrationHistoryList {
|
||||||
|
migrationHistoryVersionList = append(migrationHistoryVersionList, migrationHistory.Version)
|
||||||
|
}
|
||||||
|
sort.Sort(version.SortVersion(migrationHistoryVersionList))
|
||||||
|
latestMigrationHistoryVersion := migrationHistoryVersionList[len(migrationHistoryVersionList)-1]
|
||||||
|
|
||||||
// backup the raw database file before migration
|
if version.IsVersionGreaterThan(version.GetSchemaVersion(currentVersion), latestMigrationHistoryVersion) {
|
||||||
rawBytes, err := os.ReadFile(db.profile.DSN)
|
minorVersionList := getMinorVersionList()
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to read raw database file")
|
|
||||||
}
|
|
||||||
backupDBFilePath := fmt.Sprintf("%s/slash_%s_%d_backup.db", db.profile.Data, db.profile.Version, time.Now().Unix())
|
|
||||||
if err := os.WriteFile(backupDBFilePath, rawBytes, 0644); err != nil {
|
|
||||||
return errors.Wrap(err, "failed to write raw database file")
|
|
||||||
}
|
|
||||||
println("succeed to copy a backup database file")
|
|
||||||
|
|
||||||
println("start migrate")
|
// backup the raw database file before migration
|
||||||
for _, minorVersion := range minorVersionList {
|
rawBytes, err := os.ReadFile(db.profile.DSN)
|
||||||
normalizedVersion := minorVersion + ".0"
|
if err != nil {
|
||||||
if version.IsVersionGreaterThan(normalizedVersion, latestMigrationHistoryVersion) && version.IsVersionGreaterOrEqualThan(currentVersion, normalizedVersion) {
|
return errors.Wrap(err, "failed to read raw database file")
|
||||||
println("applying migration for", normalizedVersion)
|
}
|
||||||
if err := db.applyMigrationForMinorVersion(ctx, minorVersion); err != nil {
|
backupDBFilePath := fmt.Sprintf("%s/slash_%s_%d_backup.db", db.profile.Data, db.profile.Version, time.Now().Unix())
|
||||||
return errors.Wrap(err, "failed to apply minor version migration")
|
if err := os.WriteFile(backupDBFilePath, rawBytes, 0644); err != nil {
|
||||||
}
|
return errors.Wrap(err, "failed to write raw database file")
|
||||||
|
}
|
||||||
|
println("succeed to copy a backup database file")
|
||||||
|
|
||||||
|
println("start migrate")
|
||||||
|
for _, minorVersion := range minorVersionList {
|
||||||
|
normalizedVersion := minorVersion + ".0"
|
||||||
|
if version.IsVersionGreaterThan(normalizedVersion, latestMigrationHistoryVersion) && version.IsVersionGreaterOrEqualThan(currentVersion, normalizedVersion) {
|
||||||
|
println("applying migration for", normalizedVersion)
|
||||||
|
if err := db.applyMigrationForMinorVersion(ctx, minorVersion); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to apply minor version migration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println("end migrate")
|
}
|
||||||
|
println("end migrate")
|
||||||
|
|
||||||
// remove the created backup db file after migrate succeed
|
// remove the created backup db file after migrate succeed
|
||||||
if err := os.Remove(backupDBFilePath); err != nil {
|
if err := os.Remove(backupDBFilePath); err != nil {
|
||||||
println(fmt.Sprintf("Failed to remove temp database file, err %v", err))
|
println(fmt.Sprintf("Failed to remove temp database file, err %v", err))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -157,7 +165,7 @@ func (db *DB) applyLatestSchema(ctx context.Context) error {
|
|||||||
if db.profile.Mode == "prod" {
|
if db.profile.Mode == "prod" {
|
||||||
schemaMode = "prod"
|
schemaMode = "prod"
|
||||||
}
|
}
|
||||||
latestSchemaPath := fmt.Sprintf("%s/%s/%s", "migration", schemaMode, latestSchemaFileName)
|
latestSchemaPath := fmt.Sprintf("migration/%s/%s", schemaMode, latestSchemaFileName)
|
||||||
buf, err := migrationFS.ReadFile(latestSchemaPath)
|
buf, err := migrationFS.ReadFile(latestSchemaPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed to read latest schema %q", latestSchemaPath)
|
return errors.Wrapf(err, "failed to read latest schema %q", latestSchemaPath)
|
||||||
@ -170,9 +178,9 @@ func (db *DB) applyLatestSchema(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) applyMigrationForMinorVersion(ctx context.Context, minorVersion string) error {
|
func (db *DB) applyMigrationForMinorVersion(ctx context.Context, minorVersion string) error {
|
||||||
filenames, err := fs.Glob(migrationFS, fmt.Sprintf("%s/%s/*.sql", "migration/prod", minorVersion))
|
filenames, err := fs.Glob(migrationFS, fmt.Sprintf("migration/prod/%s/*.sql", minorVersion))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to read ddl files")
|
return errors.Wrap(err, "failed to read migrate files")
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(filenames)
|
sort.Strings(filenames)
|
||||||
@ -203,13 +211,12 @@ func (db *DB) applyMigrationForMinorVersion(ctx context.Context, minorVersion st
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) seed(ctx context.Context) error {
|
func (db *DB) seed(ctx context.Context) error {
|
||||||
filenames, err := fs.Glob(seedFS, fmt.Sprintf("%s/*.sql", "seed"))
|
filenames, err := fs.Glob(seedFS, "seed/*.sql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to read seed files")
|
return errors.Wrap(err, "failed to read seed files")
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(filenames)
|
sort.Strings(filenames)
|
||||||
|
|
||||||
// Loop over all seed files and execute them in order.
|
// Loop over all seed files and execute them in order.
|
||||||
for _, filename := range filenames {
|
for _, filename := range filenames {
|
||||||
buf, err := seedFS.ReadFile(filename)
|
buf, err := seedFS.ReadFile(filename)
|
||||||
|
@ -32,8 +32,6 @@ func (s *Store) UpsertWorkspaceSetting(ctx context.Context, upsert *storepb.Work
|
|||||||
valueString = upsert.GetSecretSession()
|
valueString = upsert.GetSecretSession()
|
||||||
} else if upsert.Key == storepb.WorkspaceSettingKey_WORKSAPCE_SETTING_ENABLE_SIGNUP {
|
} else if upsert.Key == storepb.WorkspaceSettingKey_WORKSAPCE_SETTING_ENABLE_SIGNUP {
|
||||||
valueString = strconv.FormatBool(upsert.GetEnableSignup())
|
valueString = strconv.FormatBool(upsert.GetEnableSignup())
|
||||||
} else if upsert.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_RESOURCE_RELATIVE_PATH {
|
|
||||||
valueString = upsert.GetResourceRelativePath()
|
|
||||||
} else if upsert.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE {
|
} else if upsert.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE {
|
||||||
valueString = upsert.GetCustomStyle()
|
valueString = upsert.GetCustomStyle()
|
||||||
} else if upsert.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_SCRIPT {
|
} else if upsert.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_SCRIPT {
|
||||||
@ -98,8 +96,6 @@ func (s *Store) ListWorkspaceSettings(ctx context.Context, find *FindWorkspaceSe
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
workspaceSetting.Value = &storepb.WorkspaceSetting_EnableSignup{EnableSignup: enableSignup}
|
workspaceSetting.Value = &storepb.WorkspaceSetting_EnableSignup{EnableSignup: enableSignup}
|
||||||
} else if workspaceSetting.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_RESOURCE_RELATIVE_PATH {
|
|
||||||
workspaceSetting.Value = &storepb.WorkspaceSetting_ResourceRelativePath{ResourceRelativePath: valueString}
|
|
||||||
} else if workspaceSetting.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE {
|
} else if workspaceSetting.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_STYLE {
|
||||||
workspaceSetting.Value = &storepb.WorkspaceSetting_CustomStyle{CustomStyle: valueString}
|
workspaceSetting.Value = &storepb.WorkspaceSetting_CustomStyle{CustomStyle: valueString}
|
||||||
} else if workspaceSetting.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_SCRIPT {
|
} else if workspaceSetting.Key == storepb.WorkspaceSettingKey_WORKSPACE_SETTING_CUSTOM_SCRIPT {
|
||||||
|