Merge 'master' branch
Change-Id: Iee99400c7095770e61cde94b3b2c8eb0ddec463d
3
.clabot
@ -64,6 +64,7 @@
|
||||
"sixcorners",
|
||||
"alexottoboni",
|
||||
"dominickmarino",
|
||||
"hectorj2f"
|
||||
"hectorj2f",
|
||||
"nergdron"
|
||||
]
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ COPY web/marketing/ /app/marketing
|
||||
RUN npm install
|
||||
RUN npm run build
|
||||
|
||||
# Fetch ca-certificates file for arch independent builds below
|
||||
FROM alpine as ca-cert
|
||||
RUN apk -U add ca-certificates
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
# Fetch ca-certificates file for arch independent builds below
|
||||
FROM alpine as ca-cert
|
||||
RUN apk -U add ca-certificates
|
||||
|
||||
ARG DOCKER_ARCH
|
||||
FROM ${DOCKER_ARCH:-amd64}/alpine
|
||||
ARG TAG
|
||||
@ -5,7 +9,7 @@ ARG GOARCH
|
||||
ENV GOARCH ${GOARCH}
|
||||
EXPOSE 28967
|
||||
WORKDIR /app
|
||||
COPY resources/certs.pem /etc/ssl/certs/ca-certificates.crt
|
||||
COPY --from=ca-cert /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
COPY release/${TAG}/storagenode_linux_${GOARCH:-amd64} /app/storagenode
|
||||
COPY cmd/storagenode/entrypoint /entrypoint
|
||||
COPY cmd/storagenode/dashboard.sh /app/dashboard.sh
|
||||
|
@ -6,6 +6,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@ -132,7 +133,7 @@ func main() {
|
||||
target := args[0]
|
||||
|
||||
if *retries <= 0 {
|
||||
*retries = 1 << 31
|
||||
*retries = math.MaxInt32
|
||||
}
|
||||
for try := 0; try < *retries; try++ {
|
||||
if tryConnect(target) {
|
||||
|
@ -1,3 +1,7 @@
|
||||
# Fetch ca-certificates file for arch independent builds below
|
||||
FROM alpine as ca-cert
|
||||
RUN apk -U add ca-certificates
|
||||
|
||||
ARG DOCKER_ARCH
|
||||
FROM ${DOCKER_ARCH:-amd64}/alpine
|
||||
ARG TAG
|
||||
@ -9,6 +13,7 @@ ENV CONF_PATH=/root/.local/storj/uplink \
|
||||
SATELLITE_ADDR=
|
||||
WORKDIR /app
|
||||
VOLUME /root/.local/storj/uplink
|
||||
COPY --from=ca-cert /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
COPY release/${TAG}/uplink_linux_${GOARCH:-amd64} /app/uplink
|
||||
COPY cmd/uplink/entrypoint /entrypoint
|
||||
ENTRYPOINT ["/entrypoint"]
|
||||
|
4
go.mod
@ -42,9 +42,9 @@ require (
|
||||
golang.org/x/sys v0.0.0-20200929083018-4d22bbb62b3c
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
|
||||
google.golang.org/api v0.20.0 // indirect
|
||||
storj.io/common v0.0.0-20201204143755-a03c37168cb1
|
||||
storj.io/common v0.0.0-20201207172416-78f4e59925c3
|
||||
storj.io/drpc v0.0.16
|
||||
storj.io/monkit-jaeger v0.0.0-20200518165323-80778fc3f91b
|
||||
storj.io/private v0.0.0-20201026143115-bc926bfa3bca
|
||||
storj.io/private v0.0.0-20201126162939-6fbb1e924f51
|
||||
storj.io/uplink v1.3.2-0.20201204110139-e7cbbe88e717
|
||||
)
|
||||
|
8
go.sum
@ -903,15 +903,15 @@ sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3
|
||||
storj.io/common v0.0.0-20200424175742-65ac59022f4f/go.mod h1:pZyXiIE7bGETIRXtfs0nICqMwp7PM8HqnDuyUeldNA0=
|
||||
storj.io/common v0.0.0-20201026135900-1aaeec90670b/go.mod h1:GqdmNf3fLm2UZX/7Zr0BLFCJ4gFjgm6eHrk/fnmr5jQ=
|
||||
storj.io/common v0.0.0-20201124202331-31c1d1dc486d/go.mod h1:ocAfQaE1dpflrdTr8hXRZTWP1bq2jXz7ieGSBVCmHEc=
|
||||
storj.io/common v0.0.0-20201204143755-a03c37168cb1 h1:SwSIESeyaX3kOhZN1jeNPbegSraFTdxtWD+Dn0dT7y4=
|
||||
storj.io/common v0.0.0-20201204143755-a03c37168cb1/go.mod h1:6sepaQTRLuygvA+GNPzdgRPOB1+wFfjde76KBWofbMY=
|
||||
storj.io/common v0.0.0-20201207172416-78f4e59925c3 h1:D+rAQBzjl0Mw3VQ+1Sjv5/53I7JaIymMrkDW5DYBgRE=
|
||||
storj.io/common v0.0.0-20201207172416-78f4e59925c3/go.mod h1:6sepaQTRLuygvA+GNPzdgRPOB1+wFfjde76KBWofbMY=
|
||||
storj.io/drpc v0.0.11/go.mod h1:TiFc2obNjL9/3isMW1Rpxjy8V9uE0B2HMeMFGiiI7Iw=
|
||||
storj.io/drpc v0.0.14/go.mod h1:82nfl+6YwRwF6UG31cEWWUqv/FaKvP5SGqUvoqTxCMA=
|
||||
storj.io/drpc v0.0.16 h1:9sxypc5lKi/0D69cR21BR0S21+IvXfON8L5nXMVNTwQ=
|
||||
storj.io/drpc v0.0.16/go.mod h1:zdmQ93nx4Z35u11pQ+GAnBy4DGOK3HJCSOfeh2RryTo=
|
||||
storj.io/monkit-jaeger v0.0.0-20200518165323-80778fc3f91b h1:Bbg9JCtY6l3HrDxs3BXzT2UYnYCBLqNi6i84Y8QIPUs=
|
||||
storj.io/monkit-jaeger v0.0.0-20200518165323-80778fc3f91b/go.mod h1:gj4vuCeyCRjRmH8LIrgoyU9Dc9uR6H+/GcDUXmTbf80=
|
||||
storj.io/private v0.0.0-20201026143115-bc926bfa3bca h1:ekR7vtUYC5+cDyim0ZJaSZeXidyzQqDYsnFPYXgTozc=
|
||||
storj.io/private v0.0.0-20201026143115-bc926bfa3bca/go.mod h1:EaLnIyNyqWQUJB+7+KWVez0In9czl0nHHlm2WobebuA=
|
||||
storj.io/private v0.0.0-20201126162939-6fbb1e924f51 h1:3aNbTNJeZ00cnzgYFdGyBUxtBEYqBCEzvk6Svh0gIwc=
|
||||
storj.io/private v0.0.0-20201126162939-6fbb1e924f51/go.mod h1:3KcGiA7phL3a0HUCe5ar90SlIU3iFb8hKInaEZQ5P7o=
|
||||
storj.io/uplink v1.3.2-0.20201204110139-e7cbbe88e717 h1:a1VgBKF3XKs8NY4AMFyVMjWYCskExlN8OUmCBKHEjbc=
|
||||
storj.io/uplink v1.3.2-0.20201204110139-e7cbbe88e717/go.mod h1:OmI3WhL5JFxBUt3v+q7RtW1RMndMvtHB5Dp6YN8ro3c=
|
||||
|
@ -180,6 +180,16 @@ func (client *Uplink) DialPiecestore(ctx context.Context, destination Peer) (*pi
|
||||
return piecestore.DialNodeURL(ctx, client.Dialer, destination.NodeURL(), client.Log.Named("uplink>piecestore"), piecestore.DefaultConfig)
|
||||
}
|
||||
|
||||
// OpenProject opens project with predefined access grant and gives access to pure uplink API.
|
||||
func (client *Uplink) OpenProject(ctx context.Context, satellite *Satellite) (*uplink.Project, error) {
|
||||
_, found := testuplink.GetMaxSegmentSize(ctx)
|
||||
if !found {
|
||||
ctx = testuplink.WithMaxSegmentSize(ctx, satellite.Config.Metainfo.MaxSegmentSize)
|
||||
}
|
||||
|
||||
return uplink.OpenProject(ctx, client.Access[satellite.ID()])
|
||||
}
|
||||
|
||||
// Upload data to specific satellite.
|
||||
func (client *Uplink) Upload(ctx context.Context, satellite *Satellite, bucket string, path storj.Path, data []byte) error {
|
||||
return client.UploadWithExpiration(ctx, satellite, bucket, path, data, time.Time{})
|
||||
|
@ -276,3 +276,16 @@ func TestDeleteWithOfflineStoragenode(t *testing.T) {
|
||||
require.Equal(t, 0, len(objects))
|
||||
})
|
||||
}
|
||||
|
||||
func TestUplinkOpenProject(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
|
||||
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
||||
project, err := planet.Uplinks[0].OpenProject(ctx, planet.Satellites[0])
|
||||
require.NoError(t, err)
|
||||
defer ctx.Check(project.Close)
|
||||
|
||||
_, err = project.EnsureBucket(ctx, "bucket-name")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
|
||||
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
|
||||
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
|
||||
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
|
||||
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
|
||||
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
|
||||
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
|
||||
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
|
||||
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
|
||||
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
|
||||
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
|
||||
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
|
||||
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
|
||||
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
|
||||
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
|
||||
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
|
||||
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
|
||||
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
|
||||
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
|
||||
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
|
||||
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
|
||||
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
|
||||
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
|
||||
-----END CERTIFICATE-----
|
@ -12,6 +12,18 @@ import (
|
||||
"storj.io/storj/satellite/metainfo/metabase"
|
||||
)
|
||||
|
||||
// ListAllBucketsCursor defines cursor for ListAllBuckets listing.
|
||||
type ListAllBucketsCursor struct {
|
||||
ProjectID uuid.UUID
|
||||
BucketName []byte
|
||||
}
|
||||
|
||||
// ListAllBucketsOptions defines ListAllBuckets listing options.
|
||||
type ListAllBucketsOptions struct {
|
||||
Cursor ListAllBucketsCursor
|
||||
Limit int
|
||||
}
|
||||
|
||||
// BucketsDB is the interface for the database to interact with buckets.
|
||||
//
|
||||
// architecture: Database
|
||||
@ -28,6 +40,8 @@ type BucketsDB interface {
|
||||
DeleteBucket(ctx context.Context, bucketName []byte, projectID uuid.UUID) (err error)
|
||||
// List returns all buckets for a project
|
||||
ListBuckets(ctx context.Context, projectID uuid.UUID, listOpts storj.BucketListOptions, allowedBuckets macaroon.AllowedBuckets) (bucketList storj.BucketList, err error)
|
||||
// ListAllBuckets returns a list of all buckets.
|
||||
ListAllBuckets(ctx context.Context, listOpts ListAllBucketsOptions) (bucketList storj.BucketList, err error)
|
||||
// CountBuckets returns the number of buckets a project currently has
|
||||
CountBuckets(ctx context.Context, projectID uuid.UUID) (int, error)
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"storj.io/common/macaroon"
|
||||
"storj.io/common/storj"
|
||||
"storj.io/common/uuid"
|
||||
"storj.io/storj/satellite/metainfo"
|
||||
"storj.io/storj/satellite/metainfo/metabase"
|
||||
"storj.io/storj/satellite/satellitedb/dbx"
|
||||
)
|
||||
@ -205,6 +206,63 @@ func (db *bucketsDB) ListBuckets(ctx context.Context, projectID uuid.UUID, listO
|
||||
return bucketList, nil
|
||||
}
|
||||
|
||||
// ListAllBuckets returns a list of all buckets.
|
||||
func (db *bucketsDB) ListAllBuckets(ctx context.Context, listOpts metainfo.ListAllBucketsOptions) (bucketList storj.BucketList, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
const defaultListLimit = 10000
|
||||
if listOpts.Limit < 1 || listOpts.Limit > defaultListLimit {
|
||||
listOpts.Limit = defaultListLimit
|
||||
}
|
||||
limit := listOpts.Limit + 1 // add one to detect More
|
||||
|
||||
if listOpts.Cursor.BucketName == nil {
|
||||
listOpts.Cursor.BucketName = []byte{}
|
||||
}
|
||||
|
||||
for {
|
||||
dbxBuckets, err := db.db.Limited_BucketMetainfo_By_ProjectId_GreaterOrEqual_And_Name_Greater_OrderBy_Asc_ProjectId_Name(ctx,
|
||||
dbx.BucketMetainfo_ProjectId(listOpts.Cursor.ProjectID[:]),
|
||||
dbx.BucketMetainfo_Name(listOpts.Cursor.BucketName),
|
||||
limit,
|
||||
0,
|
||||
)
|
||||
if err != nil {
|
||||
return bucketList, storj.ErrBucket.Wrap(err)
|
||||
}
|
||||
|
||||
bucketList.More = len(dbxBuckets) > listOpts.Limit
|
||||
if bucketList.More {
|
||||
// If there are more buckets than listOpts.limit returned,
|
||||
// then remove the extra buckets so that we do not return
|
||||
// more then the limit
|
||||
dbxBuckets = dbxBuckets[0:listOpts.Limit]
|
||||
}
|
||||
|
||||
if bucketList.Items == nil {
|
||||
bucketList.Items = make([]storj.Bucket, 0, len(dbxBuckets))
|
||||
}
|
||||
|
||||
for _, dbxBucket := range dbxBuckets {
|
||||
item, err := convertDBXtoBucket(dbxBucket)
|
||||
if err != nil {
|
||||
return bucketList, storj.ErrBucket.Wrap(err)
|
||||
}
|
||||
bucketList.Items = append(bucketList.Items, item)
|
||||
}
|
||||
|
||||
if len(bucketList.Items) < listOpts.Limit && bucketList.More {
|
||||
lastBucket := bucketList.Items[len(bucketList.Items)-1]
|
||||
listOpts.Cursor.ProjectID = lastBucket.ProjectID
|
||||
listOpts.Cursor.BucketName = []byte(lastBucket.Name)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return bucketList, nil
|
||||
}
|
||||
|
||||
// CountBuckets returns the number of buckets a project currently has.
|
||||
func (db *bucketsDB) CountBuckets(ctx context.Context, projectID uuid.UUID) (count int, err error) {
|
||||
count64, err := db.db.Count_BucketMetainfo_Name_By_ProjectId(ctx, dbx.BucketMetainfo_ProjectId(projectID[:]))
|
||||
|
103
satellite/satellitedb/buckets_test.go
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package satellitedb_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"storj.io/common/storj"
|
||||
"storj.io/common/testcontext"
|
||||
"storj.io/common/testrand"
|
||||
"storj.io/storj/satellite"
|
||||
"storj.io/storj/satellite/console"
|
||||
"storj.io/storj/satellite/metainfo"
|
||||
"storj.io/storj/satellite/satellitedb/satellitedbtest"
|
||||
)
|
||||
|
||||
func TestListAllBuckets(t *testing.T) {
|
||||
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
||||
// no buckets
|
||||
list, err := db.Buckets().ListAllBuckets(ctx, metainfo.ListAllBucketsOptions{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(list.Items))
|
||||
|
||||
first, err := db.Console().Projects().Insert(ctx, &console.Project{
|
||||
Name: "first",
|
||||
ID: testrand.UUID(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
second, err := db.Console().Projects().Insert(ctx, &console.Project{
|
||||
Name: "second",
|
||||
ID: testrand.UUID(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
projects := []*console.Project{first, second}
|
||||
if bytes.Compare(first.ID[:], second.ID[:]) > 0 {
|
||||
projects = []*console.Project{second, first}
|
||||
}
|
||||
|
||||
buckets := make([]storj.Bucket, 10)
|
||||
for i, project := range projects {
|
||||
for index := 0; index < (len(buckets) / 2); index++ {
|
||||
var err error
|
||||
buckets[index+(i*5)], err = db.Buckets().CreateBucket(ctx, storj.Bucket{
|
||||
ID: testrand.UUID(),
|
||||
Name: "bucket-test-" + strconv.Itoa(index),
|
||||
ProjectID: project.ID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
list, err = db.Buckets().ListAllBuckets(ctx, metainfo.ListAllBucketsOptions{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(buckets), len(list.Items))
|
||||
require.False(t, list.More)
|
||||
require.Zero(t, cmp.Diff(buckets, list.Items))
|
||||
|
||||
list, err = db.Buckets().ListAllBuckets(ctx, metainfo.ListAllBucketsOptions{
|
||||
Cursor: metainfo.ListAllBucketsCursor{
|
||||
ProjectID: projects[1].ID,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(buckets)/2, len(list.Items))
|
||||
require.Zero(t, cmp.Diff(buckets[len(buckets)/2:], list.Items))
|
||||
|
||||
list, err = db.Buckets().ListAllBuckets(ctx, metainfo.ListAllBucketsOptions{
|
||||
Cursor: metainfo.ListAllBucketsCursor{
|
||||
ProjectID: projects[1].ID,
|
||||
BucketName: []byte("bucket-test-2"),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(list.Items))
|
||||
require.False(t, list.More)
|
||||
require.Zero(t, cmp.Diff(buckets[8:], list.Items))
|
||||
|
||||
list, err = db.Buckets().ListAllBuckets(ctx, metainfo.ListAllBucketsOptions{
|
||||
Cursor: metainfo.ListAllBucketsCursor{
|
||||
ProjectID: projects[1].ID,
|
||||
BucketName: []byte("bucket-test-4"),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(list.Items))
|
||||
|
||||
list, err = db.Buckets().ListAllBuckets(ctx, metainfo.ListAllBucketsOptions{
|
||||
Limit: 2,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(list.Items))
|
||||
require.True(t, list.More)
|
||||
require.Zero(t, cmp.Diff(buckets[:2], list.Items))
|
||||
})
|
||||
}
|
@ -1002,6 +1002,13 @@ read limitoffset ( // After
|
||||
orderby asc bucket_metainfo.name
|
||||
)
|
||||
|
||||
read limitoffset ( // After
|
||||
select bucket_metainfo
|
||||
where bucket_metainfo.project_id >= ?
|
||||
where bucket_metainfo.name > ?
|
||||
orderby asc bucket_metainfo.project_id bucket_metainfo.name
|
||||
)
|
||||
|
||||
read count (
|
||||
select bucket_metainfo.name
|
||||
where bucket_metainfo.project_id = ?
|
||||
|
@ -12747,6 +12747,56 @@ func (obj *pgxImpl) Limited_BucketMetainfo_By_ProjectId_And_Name_Greater_OrderBy
|
||||
|
||||
}
|
||||
|
||||
func (obj *pgxImpl) Limited_BucketMetainfo_By_ProjectId_GreaterOrEqual_And_Name_Greater_OrderBy_Asc_ProjectId_Name(ctx context.Context,
|
||||
bucket_metainfo_project_id_greater_or_equal BucketMetainfo_ProjectId_Field,
|
||||
bucket_metainfo_name_greater BucketMetainfo_Name_Field,
|
||||
limit int, offset int64) (
|
||||
rows []*BucketMetainfo, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
var __embed_stmt = __sqlbundle_Literal("SELECT bucket_metainfos.id, bucket_metainfos.project_id, bucket_metainfos.name, bucket_metainfos.partner_id, bucket_metainfos.path_cipher, bucket_metainfos.created_at, bucket_metainfos.default_segment_size, bucket_metainfos.default_encryption_cipher_suite, bucket_metainfos.default_encryption_block_size, bucket_metainfos.default_redundancy_algorithm, bucket_metainfos.default_redundancy_share_size, bucket_metainfos.default_redundancy_required_shares, bucket_metainfos.default_redundancy_repair_shares, bucket_metainfos.default_redundancy_optimal_shares, bucket_metainfos.default_redundancy_total_shares FROM bucket_metainfos WHERE bucket_metainfos.project_id >= ? AND bucket_metainfos.name > ? ORDER BY bucket_metainfos.project_id, bucket_metainfos.name LIMIT ? OFFSET ?")
|
||||
|
||||
var __values []interface{}
|
||||
__values = append(__values, bucket_metainfo_project_id_greater_or_equal.value(), bucket_metainfo_name_greater.value())
|
||||
|
||||
__values = append(__values, limit, offset)
|
||||
|
||||
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
|
||||
obj.logStmt(__stmt, __values...)
|
||||
|
||||
for {
|
||||
rows, err = func() (rows []*BucketMetainfo, err error) {
|
||||
__rows, err := obj.driver.QueryContext(ctx, __stmt, __values...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer __rows.Close()
|
||||
|
||||
for __rows.Next() {
|
||||
bucket_metainfo := &BucketMetainfo{}
|
||||
err = __rows.Scan(&bucket_metainfo.Id, &bucket_metainfo.ProjectId, &bucket_metainfo.Name, &bucket_metainfo.PartnerId, &bucket_metainfo.PathCipher, &bucket_metainfo.CreatedAt, &bucket_metainfo.DefaultSegmentSize, &bucket_metainfo.DefaultEncryptionCipherSuite, &bucket_metainfo.DefaultEncryptionBlockSize, &bucket_metainfo.DefaultRedundancyAlgorithm, &bucket_metainfo.DefaultRedundancyShareSize, &bucket_metainfo.DefaultRedundancyRequiredShares, &bucket_metainfo.DefaultRedundancyRepairShares, &bucket_metainfo.DefaultRedundancyOptimalShares, &bucket_metainfo.DefaultRedundancyTotalShares)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows = append(rows, bucket_metainfo)
|
||||
}
|
||||
err = __rows.Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}()
|
||||
if err != nil {
|
||||
if obj.shouldRetry(err) {
|
||||
continue
|
||||
}
|
||||
return nil, obj.makeErr(err)
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (obj *pgxImpl) Count_BucketMetainfo_Name_By_ProjectId(ctx context.Context,
|
||||
bucket_metainfo_project_id BucketMetainfo_ProjectId_Field) (
|
||||
count int64, err error) {
|
||||
@ -19534,6 +19584,56 @@ func (obj *pgxcockroachImpl) Limited_BucketMetainfo_By_ProjectId_And_Name_Greate
|
||||
|
||||
}
|
||||
|
||||
func (obj *pgxcockroachImpl) Limited_BucketMetainfo_By_ProjectId_GreaterOrEqual_And_Name_Greater_OrderBy_Asc_ProjectId_Name(ctx context.Context,
|
||||
bucket_metainfo_project_id_greater_or_equal BucketMetainfo_ProjectId_Field,
|
||||
bucket_metainfo_name_greater BucketMetainfo_Name_Field,
|
||||
limit int, offset int64) (
|
||||
rows []*BucketMetainfo, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
var __embed_stmt = __sqlbundle_Literal("SELECT bucket_metainfos.id, bucket_metainfos.project_id, bucket_metainfos.name, bucket_metainfos.partner_id, bucket_metainfos.path_cipher, bucket_metainfos.created_at, bucket_metainfos.default_segment_size, bucket_metainfos.default_encryption_cipher_suite, bucket_metainfos.default_encryption_block_size, bucket_metainfos.default_redundancy_algorithm, bucket_metainfos.default_redundancy_share_size, bucket_metainfos.default_redundancy_required_shares, bucket_metainfos.default_redundancy_repair_shares, bucket_metainfos.default_redundancy_optimal_shares, bucket_metainfos.default_redundancy_total_shares FROM bucket_metainfos WHERE bucket_metainfos.project_id >= ? AND bucket_metainfos.name > ? ORDER BY bucket_metainfos.project_id, bucket_metainfos.name LIMIT ? OFFSET ?")
|
||||
|
||||
var __values []interface{}
|
||||
__values = append(__values, bucket_metainfo_project_id_greater_or_equal.value(), bucket_metainfo_name_greater.value())
|
||||
|
||||
__values = append(__values, limit, offset)
|
||||
|
||||
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
|
||||
obj.logStmt(__stmt, __values...)
|
||||
|
||||
for {
|
||||
rows, err = func() (rows []*BucketMetainfo, err error) {
|
||||
__rows, err := obj.driver.QueryContext(ctx, __stmt, __values...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer __rows.Close()
|
||||
|
||||
for __rows.Next() {
|
||||
bucket_metainfo := &BucketMetainfo{}
|
||||
err = __rows.Scan(&bucket_metainfo.Id, &bucket_metainfo.ProjectId, &bucket_metainfo.Name, &bucket_metainfo.PartnerId, &bucket_metainfo.PathCipher, &bucket_metainfo.CreatedAt, &bucket_metainfo.DefaultSegmentSize, &bucket_metainfo.DefaultEncryptionCipherSuite, &bucket_metainfo.DefaultEncryptionBlockSize, &bucket_metainfo.DefaultRedundancyAlgorithm, &bucket_metainfo.DefaultRedundancyShareSize, &bucket_metainfo.DefaultRedundancyRequiredShares, &bucket_metainfo.DefaultRedundancyRepairShares, &bucket_metainfo.DefaultRedundancyOptimalShares, &bucket_metainfo.DefaultRedundancyTotalShares)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows = append(rows, bucket_metainfo)
|
||||
}
|
||||
err = __rows.Err()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}()
|
||||
if err != nil {
|
||||
if obj.shouldRetry(err) {
|
||||
continue
|
||||
}
|
||||
return nil, obj.makeErr(err)
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (obj *pgxcockroachImpl) Count_BucketMetainfo_Name_By_ProjectId(ctx context.Context,
|
||||
bucket_metainfo_project_id BucketMetainfo_ProjectId_Field) (
|
||||
count int64, err error) {
|
||||
@ -24069,6 +24169,18 @@ func (rx *Rx) Limited_BucketMetainfo_By_ProjectId_And_Name_Greater_OrderBy_Asc_N
|
||||
return tx.Limited_BucketMetainfo_By_ProjectId_And_Name_Greater_OrderBy_Asc_Name(ctx, bucket_metainfo_project_id, bucket_metainfo_name_greater, limit, offset)
|
||||
}
|
||||
|
||||
func (rx *Rx) Limited_BucketMetainfo_By_ProjectId_GreaterOrEqual_And_Name_Greater_OrderBy_Asc_ProjectId_Name(ctx context.Context,
|
||||
bucket_metainfo_project_id_greater_or_equal BucketMetainfo_ProjectId_Field,
|
||||
bucket_metainfo_name_greater BucketMetainfo_Name_Field,
|
||||
limit int, offset int64) (
|
||||
rows []*BucketMetainfo, err error) {
|
||||
var tx *Tx
|
||||
if tx, err = rx.getTx(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
return tx.Limited_BucketMetainfo_By_ProjectId_GreaterOrEqual_And_Name_Greater_OrderBy_Asc_ProjectId_Name(ctx, bucket_metainfo_project_id_greater_or_equal, bucket_metainfo_name_greater, limit, offset)
|
||||
}
|
||||
|
||||
func (rx *Rx) Limited_CoinpaymentsTransaction_By_CreatedAt_LessOrEqual_And_Status_OrderBy_Desc_CreatedAt(ctx context.Context,
|
||||
coinpayments_transaction_created_at_less_or_equal CoinpaymentsTransaction_CreatedAt_Field,
|
||||
coinpayments_transaction_status CoinpaymentsTransaction_Status_Field,
|
||||
@ -25146,6 +25258,12 @@ type Methods interface {
|
||||
limit int, offset int64) (
|
||||
rows []*BucketMetainfo, err error)
|
||||
|
||||
Limited_BucketMetainfo_By_ProjectId_GreaterOrEqual_And_Name_Greater_OrderBy_Asc_ProjectId_Name(ctx context.Context,
|
||||
bucket_metainfo_project_id_greater_or_equal BucketMetainfo_ProjectId_Field,
|
||||
bucket_metainfo_name_greater BucketMetainfo_Name_Field,
|
||||
limit int, offset int64) (
|
||||
rows []*BucketMetainfo, err error)
|
||||
|
||||
Limited_CoinpaymentsTransaction_By_CreatedAt_LessOrEqual_And_Status_OrderBy_Desc_CreatedAt(ctx context.Context,
|
||||
coinpayments_transaction_created_at_less_or_equal CoinpaymentsTransaction_CreatedAt_Field,
|
||||
coinpayments_transaction_status CoinpaymentsTransaction_Status_Field,
|
||||
|
@ -8,4 +8,5 @@ type DiskSpaceInfo struct {
|
||||
Used int64 `json:"used"`
|
||||
Available int64 `json:"available"`
|
||||
Trash int64 `json:"trash"`
|
||||
Overused int64 `json:"overused"`
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ package console
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/spacemonkeygo/monkit/v3"
|
||||
@ -210,6 +211,11 @@ func (s *Service) GetDashboardData(ctx context.Context) (_ *Dashboard, err error
|
||||
Trash: trash,
|
||||
}
|
||||
|
||||
overused := s.allocatedDiskSpace.Int64() - pieceTotal - trash
|
||||
if overused < 0 {
|
||||
data.DiskSpace.Overused = int64(math.Abs(float64(overused)))
|
||||
}
|
||||
|
||||
data.Bandwidth = BandwidthInfo{
|
||||
Used: bandwidthUsage,
|
||||
}
|
||||
|
@ -36,28 +36,28 @@ export default class ProgressBar extends Vue {
|
||||
* Indicates if current route is on name step.
|
||||
*/
|
||||
public get isNameStep(): boolean {
|
||||
return this.$route.name === RouteConfig.NameStep.name;
|
||||
return this.$route.name === RouteConfig.NameStep.name || this.$route.name === RouteConfig.AccessGrantName.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is on permissions step.
|
||||
*/
|
||||
public get isPermissionsStep(): boolean {
|
||||
return this.$route.name === RouteConfig.PermissionsStep.name;
|
||||
return this.$route.name === RouteConfig.PermissionsStep.name || this.$route.name === RouteConfig.AccessGrantPermissions.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is on passphrase step.
|
||||
*/
|
||||
public get isPassphraseStep(): boolean {
|
||||
return this.$route.name === RouteConfig.CreatePassphraseStep.name || this.$route.name === RouteConfig.EnterPassphraseStep.name;
|
||||
return this.$route.name === RouteConfig.CreatePassphraseStep.name || this.$route.name === RouteConfig.EnterPassphraseStep.name || this.$route.name === RouteConfig.AccessGrantPassphrase.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is on result step.
|
||||
*/
|
||||
public get isResultStep(): boolean {
|
||||
return this.$route.name === RouteConfig.ResultStep.name;
|
||||
return this.$route.name === RouteConfig.ResultStep.name || this.$route.name === RouteConfig.AccessGrantResult.name;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -5,6 +5,7 @@
|
||||
<div class="buckets-selection">
|
||||
<div
|
||||
class="buckets-selection__toggle-container"
|
||||
:class="{ disabled: isOnboardingTour }"
|
||||
@click.stop="toggleDropdown"
|
||||
>
|
||||
<h1 class="buckets-selection__toggle-container__name">{{ selectionLabel }}</h1>
|
||||
@ -28,6 +29,8 @@ import BucketsDropdown from '@/components/accessGrants/permissions/BucketsDropdo
|
||||
|
||||
import ExpandIcon from '@/../static/images/common/BlackArrowExpand.svg';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
ExpandIcon,
|
||||
@ -41,6 +44,8 @@ export default class BucketsSelection extends Vue {
|
||||
* Toggles dropdown visibility.
|
||||
*/
|
||||
public toggleDropdown(): void {
|
||||
if (this.isOnboardingTour) return;
|
||||
|
||||
this.isDropdownShown = !this.isDropdownShown;
|
||||
}
|
||||
|
||||
@ -51,6 +56,13 @@ export default class BucketsSelection extends Vue {
|
||||
this.isDropdownShown = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is onboarding tour.
|
||||
*/
|
||||
public get isOnboardingTour(): boolean {
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns selection options (all or items count).
|
||||
*/
|
||||
@ -90,6 +102,7 @@ export default class BucketsSelection extends Vue {
|
||||
justify-content: space-between;
|
||||
padding: 15px 20px;
|
||||
width: calc(100% - 40px);
|
||||
border-radius: 6px;
|
||||
|
||||
&__name {
|
||||
font-style: normal;
|
||||
@ -101,4 +114,10 @@ export default class BucketsSelection extends Vue {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
background: #f5f6fa;
|
||||
border: 1px solid rgba(56, 75, 101, 0.4);
|
||||
}
|
||||
</style>
|
||||
|
@ -2,7 +2,7 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="create-passphrase">
|
||||
<div class="create-passphrase" :class="{ 'border-radius': isOnboardingTour }">
|
||||
<BackIcon class="create-passphrase__back-icon" @click="onBackClick"/>
|
||||
<h1 class="create-passphrase__title">Encryption Passphrase</h1>
|
||||
<div class="create-passphrase__warning">
|
||||
@ -195,6 +195,18 @@ export default class CreatePassphraseStep extends Vue {
|
||||
setTimeout(() => {
|
||||
this.isLoading = false;
|
||||
|
||||
if (this.isOnboardingTour) {
|
||||
this.$router.push({
|
||||
name: RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant.with(RouteConfig.AccessGrantResult)).name,
|
||||
params: {
|
||||
access: this.access,
|
||||
key: this.key,
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push({
|
||||
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.ResultStep)).name,
|
||||
params: {
|
||||
@ -210,6 +222,17 @@ export default class CreatePassphraseStep extends Vue {
|
||||
* Redirects to previous step.
|
||||
*/
|
||||
public onBackClick(): void {
|
||||
if (this.isOnboardingTour) {
|
||||
this.$router.push({
|
||||
name: RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant.with(RouteConfig.AccessGrantPermissions)).name,
|
||||
params: {
|
||||
key: this.key,
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push({
|
||||
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.PermissionsStep)).name,
|
||||
params: {
|
||||
@ -217,6 +240,13 @@ export default class CreatePassphraseStep extends Vue {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is onboarding tour.
|
||||
*/
|
||||
public get isOnboardingTour(): boolean {
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -363,6 +393,10 @@ export default class CreatePassphraseStep extends Vue {
|
||||
border-bottom: 3px solid #0068dc;
|
||||
}
|
||||
|
||||
.border-radius {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/deep/ .label-container {
|
||||
|
||||
&__main {
|
||||
|
@ -2,7 +2,7 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="name-step">
|
||||
<div class="name-step" :class="{ 'border-radius': isOnboardingTour }">
|
||||
<h1 class="name-step__title">Name Your Access Grant</h1>
|
||||
<p class="name-step__sub-title">Enter a name for your new Access grant to get started.</p>
|
||||
<HeaderedInput
|
||||
@ -14,6 +14,7 @@
|
||||
/>
|
||||
<div class="name-step__buttons-area">
|
||||
<VButton
|
||||
v-if="!isOnboardingTour"
|
||||
class="cancel-button"
|
||||
label="Cancel"
|
||||
width="50%"
|
||||
@ -84,7 +85,7 @@ export default class NameStep extends Vue {
|
||||
}
|
||||
|
||||
if (!this.name) {
|
||||
this.errorMessage = 'Access Grant name can`t be empty';
|
||||
this.errorMessage = 'Access Grant name can\'t be empty';
|
||||
|
||||
return;
|
||||
}
|
||||
@ -113,6 +114,18 @@ export default class NameStep extends Vue {
|
||||
}
|
||||
|
||||
this.isLoading = false;
|
||||
|
||||
if (this.isOnboardingTour) {
|
||||
await this.$router.push({
|
||||
name: RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant.with(RouteConfig.AccessGrantPermissions)).name,
|
||||
params: {
|
||||
key: this.key,
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$router.push({
|
||||
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.PermissionsStep)).name,
|
||||
params: {
|
||||
@ -120,6 +133,13 @@ export default class NameStep extends Vue {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is onboarding tour.
|
||||
*/
|
||||
public get isOnboardingTour(): boolean {
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -161,6 +181,7 @@ export default class NameStep extends Vue {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 130px;
|
||||
}
|
||||
}
|
||||
@ -168,4 +189,8 @@ export default class NameStep extends Vue {
|
||||
.cancel-button {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.border-radius {
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
|
@ -2,7 +2,7 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="permissions">
|
||||
<div class="permissions" :class="{ 'border-radius': isOnboardingTour }">
|
||||
<BackIcon class="permissions__back-icon" @click="onBackClick"/>
|
||||
<h1 class="permissions__title">Access Permissions</h1>
|
||||
<p class="permissions__sub-title">
|
||||
@ -55,7 +55,7 @@
|
||||
:on-press="onContinueInBrowserClick"
|
||||
:is-disabled="isLoading"
|
||||
/>
|
||||
<p class="permissions__cli-link" @click.stop="onContinueInCLIClick">
|
||||
<p v-if="!isOnboardingTour" class="permissions__cli-link" @click.stop="onContinueInCLIClick">
|
||||
Continue in CLI
|
||||
</p>
|
||||
</div>
|
||||
@ -179,6 +179,17 @@ export default class PermissionsStep extends Vue {
|
||||
setTimeout(() => {
|
||||
this.isLoading = false;
|
||||
|
||||
if (this.isOnboardingTour) {
|
||||
this.$router.push({
|
||||
name: RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant.with(RouteConfig.AccessGrantPassphrase)).name,
|
||||
params: {
|
||||
key: this.restrictedKey,
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.accessGrantsAmount > 1) {
|
||||
this.$router.push({
|
||||
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.EnterPassphraseStep)).name,
|
||||
@ -199,6 +210,13 @@ export default class PermissionsStep extends Vue {
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is onboarding tour.
|
||||
*/
|
||||
public get isOnboardingTour(): boolean {
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns stored selected bucket names.
|
||||
*/
|
||||
@ -359,4 +377,8 @@ export default class PermissionsStep extends Vue {
|
||||
color: #0068dc;
|
||||
}
|
||||
}
|
||||
|
||||
.border-radius {
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
|
@ -2,7 +2,7 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="generate-grant">
|
||||
<div class="generate-grant" :class="{ 'border-radius': isOnboardingTour }">
|
||||
<BackIcon class="generate-grant__back-icon" @click="onBackClick"/>
|
||||
<h1 class="generate-grant__title">Generate Access Grant</h1>
|
||||
<div class="generate-grant__warning">
|
||||
@ -192,6 +192,17 @@ export default class ResultStep extends Vue {
|
||||
* Redirects to previous step.
|
||||
*/
|
||||
public onBackClick(): void {
|
||||
if (this.isOnboardingTour) {
|
||||
this.$router.push({
|
||||
name: RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant.with(RouteConfig.AccessGrantPassphrase)).name,
|
||||
params: {
|
||||
key: this.$route.params.key,
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.accessGrantsAmount > 1) {
|
||||
this.$router.push({
|
||||
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.EnterPassphraseStep)).name,
|
||||
@ -216,6 +227,12 @@ export default class ResultStep extends Vue {
|
||||
* Proceed to upload data step.
|
||||
*/
|
||||
public onDoneClick(): void {
|
||||
if (this.isOnboardingTour) {
|
||||
this.$router.push(RouteConfig.ProjectDashboard.path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push({
|
||||
name: RouteConfig.AccessGrants.with(RouteConfig.CreateAccessGrant.with(RouteConfig.UploadStep)).name,
|
||||
params: {
|
||||
@ -243,6 +260,13 @@ export default class ResultStep extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is onboarding tour.
|
||||
*/
|
||||
public get isOnboardingTour(): boolean {
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns generated gateway credentials from store.
|
||||
*/
|
||||
@ -292,7 +316,7 @@ export default class ResultStep extends Vue {
|
||||
|
||||
&__warning {
|
||||
padding: 20px;
|
||||
width: calc(100% - 40px);
|
||||
width: calc(100% - 42px);
|
||||
background: #fff9f7;
|
||||
border: 1px solid #f84b00;
|
||||
border-radius: 8px;
|
||||
@ -336,7 +360,7 @@ export default class ResultStep extends Vue {
|
||||
align-items: center;
|
||||
border-radius: 9px;
|
||||
padding: 10px;
|
||||
width: calc(100% - 20px);
|
||||
width: calc(100% - 22px);
|
||||
border: 1px solid rgba(56, 75, 101, 0.4);
|
||||
|
||||
&__value {
|
||||
@ -446,4 +470,8 @@ export default class ResultStep extends Vue {
|
||||
margin-top: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.border-radius {
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
|
@ -199,7 +199,7 @@ export default class TokenDepositSelection extends Vue {
|
||||
* Indicates if app state is in onboarding tour state.
|
||||
*/
|
||||
private get isOnboardingTour(): boolean {
|
||||
return this.$route.name === RouteConfig.OnboardingTour.name;
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -20,7 +20,7 @@ import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import { AuthHttpApi } from '@/api/auth';
|
||||
import { RouteConfig } from '@/router';
|
||||
import { API_KEYS_ACTIONS } from '@/store/modules/apiKeys';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { USER_ACTIONS } from '@/store/modules/users';
|
||||
@ -58,7 +58,7 @@ export default class AccountDropdown extends Vue {
|
||||
await this.$store.dispatch(PM_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(USER_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(API_KEYS_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(NOTIFICATION_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(APP_STATE_ACTIONS.CLOSE_POPUPS);
|
||||
|
@ -39,7 +39,7 @@ import { Component, Vue } from 'vue-property-decorator';
|
||||
import SelectionIcon from '@/../static/images/header/selection.svg';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { API_KEYS_ACTIONS } from '@/store/modules/apiKeys';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
@ -68,7 +68,7 @@ export default class ProjectDropdown extends Vue {
|
||||
try {
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
|
||||
await this.$store.dispatch(PM_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||
await this.$store.dispatch(API_KEYS_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, this.$store.getters.selectedProject.id);
|
||||
} catch (error) {
|
||||
|
@ -60,7 +60,7 @@ export default class ProjectSelection extends Vue {
|
||||
* Indicates if current route is onboarding tour.
|
||||
*/
|
||||
public get isOnboardingTour(): boolean {
|
||||
return this.$route.name === RouteConfig.OnboardingTour.name;
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ export default class ResourcesDropdown extends Vue {
|
||||
* Indicates if current route is onboarding tour.
|
||||
*/
|
||||
public get isOnboardingTour(): boolean {
|
||||
return this.$route.name === RouteConfig.OnboardingTour.name;
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -43,7 +43,7 @@ export default class ResourcesSelection extends Vue {
|
||||
* Indicates if current route is onboarding tour.
|
||||
*/
|
||||
public get isOnboardingTour(): boolean {
|
||||
return this.$route.name === RouteConfig.OnboardingTour.name;
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,7 +43,7 @@ export default class SettingsSelection extends Vue {
|
||||
* Indicates if current route is onboarding tour.
|
||||
*/
|
||||
public get isOnboardingTour(): boolean {
|
||||
return this.$route.name === RouteConfig.OnboardingTour.name;
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,7 @@ import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import EditProjectDropdown from '@/components/navigation/EditProjectDropdown.vue';
|
||||
|
||||
import ApiKeysIcon from '@/../static/images/navigation/apiKeys.svg';
|
||||
import AccessGrantsIcon from '@/../static/images/navigation/apiKeys.svg';
|
||||
import DashboardIcon from '@/../static/images/navigation/dashboard.svg';
|
||||
import TeamIcon from '@/../static/images/navigation/team.svg';
|
||||
|
||||
@ -34,7 +34,7 @@ import { NavigationLink } from '@/types/navigation';
|
||||
@Component({
|
||||
components: {
|
||||
DashboardIcon,
|
||||
ApiKeysIcon,
|
||||
AccessGrantsIcon,
|
||||
TeamIcon,
|
||||
EditProjectDropdown,
|
||||
},
|
||||
@ -45,7 +45,7 @@ export default class NavigationArea extends Vue {
|
||||
*/
|
||||
public readonly navigation: NavigationLink[] = [
|
||||
RouteConfig.ProjectDashboard.withIcon(DashboardIcon),
|
||||
RouteConfig.ApiKeys.withIcon(ApiKeysIcon),
|
||||
RouteConfig.AccessGrants.withIcon(AccessGrantsIcon),
|
||||
RouteConfig.Users.withIcon(TeamIcon),
|
||||
];
|
||||
|
||||
@ -67,7 +67,7 @@ export default class NavigationArea extends Vue {
|
||||
* Indicates if current route is onboarding tour.
|
||||
*/
|
||||
private get isOnboardingTour(): boolean {
|
||||
return this.$route.name === RouteConfig.OnboardingTour.name;
|
||||
return this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -11,34 +11,7 @@
|
||||
<CloseImage class="tour-area__info-bar__close-img" @click="disableInfoBar"/>
|
||||
</div>
|
||||
<div class="tour-area__content">
|
||||
<ProgressBar
|
||||
:is-paywall-enabled="isPaywallEnabled"
|
||||
:is-add-payment-step="isAddPaymentState"
|
||||
:is-create-project-step="isCreateProjectState"
|
||||
:is-create-api-key-step="isCreatApiKeyState"
|
||||
:is-upload-data-step="isUploadDataState"
|
||||
/>
|
||||
<OverviewStep
|
||||
v-if="isDefaultState && isPaywallEnabled"
|
||||
@setAddPaymentState="setAddPaymentState"
|
||||
/>
|
||||
<OverviewStepNoPaywall
|
||||
v-if="isDefaultState && !isPaywallEnabled"
|
||||
@setCreateProjectState="setCreateProjectState"
|
||||
/>
|
||||
<AddPaymentStep
|
||||
v-if="isAddPaymentState"
|
||||
@setProjectState="setCreateProjectState"
|
||||
/>
|
||||
<CreateProjectStep
|
||||
v-if="isCreateProjectState"
|
||||
@setApiKeyState="setCreateApiKeyState"
|
||||
/>
|
||||
<CreateApiKeyStep
|
||||
v-if="isCreatApiKeyState"
|
||||
@setUploadDataState="setUploadDataState"
|
||||
/>
|
||||
<UploadDataStep v-if="isUploadDataState"/>
|
||||
<router-view/>
|
||||
<img
|
||||
v-if="isAddPaymentState"
|
||||
class="tour-area__content__tardigrade"
|
||||
@ -52,36 +25,16 @@
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import ProgressBar from '@/components/onboardingTour/ProgressBar.vue';
|
||||
import AddPaymentStep from '@/components/onboardingTour/steps/AddPaymentStep.vue';
|
||||
import CreateApiKeyStep from '@/components/onboardingTour/steps/CreateApiKeyStep.vue';
|
||||
import CreateProjectStep from '@/components/onboardingTour/steps/CreateProjectStep.vue';
|
||||
import OverviewStep from '@/components/onboardingTour/steps/OverviewStep.vue';
|
||||
import OverviewStepNoPaywall from '@/components/onboardingTour/steps/OverviewStepNoPaywall.vue';
|
||||
import UploadDataStep from '@/components/onboardingTour/steps/UploadDataStep.vue';
|
||||
|
||||
import CheckedImage from '@/../static/images/common/checked.svg';
|
||||
import CloseImage from '@/../static/images/onboardingTour/close.svg';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { TourState } from '@/utils/constants/onboardingTourEnums';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
OverviewStepNoPaywall,
|
||||
UploadDataStep,
|
||||
CreateApiKeyStep,
|
||||
CreateProjectStep,
|
||||
AddPaymentStep,
|
||||
ProgressBar,
|
||||
OverviewStep,
|
||||
CheckedImage,
|
||||
CloseImage,
|
||||
},
|
||||
})
|
||||
|
||||
export default class OnboardingTourArea extends Vue {
|
||||
public areaState: number = TourState.DEFAULT;
|
||||
public isInfoBarVisible: boolean = true;
|
||||
|
||||
/**
|
||||
@ -89,7 +42,7 @@ export default class OnboardingTourArea extends Vue {
|
||||
* Sets area to needed state.
|
||||
*/
|
||||
public mounted(): void {
|
||||
if (this.userHasProject && this.userHasApiKeys) {
|
||||
if (this.userHasProject && this.userHasAccessGrants) {
|
||||
try {
|
||||
this.$router.push(RouteConfig.ProjectDashboard.path);
|
||||
} catch (error) {
|
||||
@ -99,22 +52,8 @@ export default class OnboardingTourArea extends Vue {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.userHasProject && !this.userHasApiKeys) {
|
||||
if (this.$route.name === RouteConfig.AccessGrant.name) {
|
||||
this.disableInfoBar();
|
||||
this.setCreateApiKeyState();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.$store.state.paymentsModule.creditCards.length > 0) {
|
||||
this.disableInfoBar();
|
||||
this.setCreateProjectState();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.$store.getters.isTransactionProcessing || this.$store.getters.isBalancePositive) {
|
||||
this.setAddPaymentState();
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,67 +65,10 @@ export default class OnboardingTourArea extends Vue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if area is in default state.
|
||||
* Sets area's state to creating access grant step.
|
||||
*/
|
||||
public get isDefaultState(): boolean {
|
||||
return this.areaState === TourState.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if area is in adding payment method state.
|
||||
*/
|
||||
public get isAddPaymentState(): boolean {
|
||||
return this.areaState === TourState.ADDING_PAYMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if area is in creating project state.
|
||||
*/
|
||||
public get isCreateProjectState(): boolean {
|
||||
return this.areaState === TourState.PROJECT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if area is in api key state.
|
||||
*/
|
||||
public get isCreatApiKeyState(): boolean {
|
||||
return this.areaState === TourState.API_KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if area is in upload data state.
|
||||
*/
|
||||
public get isUploadDataState(): boolean {
|
||||
return this.areaState === TourState.UPLOAD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets area's state to adding payment method state.
|
||||
*/
|
||||
public setAddPaymentState(): void {
|
||||
this.areaState = TourState.ADDING_PAYMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets area's state to creating project state.
|
||||
*/
|
||||
public setCreateProjectState(): void {
|
||||
this.disableInfoBar();
|
||||
this.areaState = TourState.PROJECT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets area's state to creating api key state.
|
||||
*/
|
||||
public setCreateApiKeyState(): void {
|
||||
this.areaState = TourState.API_KEY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets area's state to upload data state.
|
||||
*/
|
||||
public setUploadDataState(): void {
|
||||
this.areaState = TourState.UPLOAD;
|
||||
public setCreateAccessGrantStep(): void {
|
||||
this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant).path);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,6 +78,13 @@ export default class OnboardingTourArea extends Vue {
|
||||
this.isInfoBarVisible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if area is on adding payment method step.
|
||||
*/
|
||||
public get isAddPaymentState(): boolean {
|
||||
return this.$route.name === RouteConfig.PaymentStep.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if user has at least one project.
|
||||
*/
|
||||
@ -204,10 +93,10 @@ export default class OnboardingTourArea extends Vue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if user has at least one API key.
|
||||
* Indicates if user has at least one access grant.
|
||||
*/
|
||||
private get userHasApiKeys(): boolean {
|
||||
return this.$store.state.apiKeysModule.page.apiKeys.length > 0;
|
||||
private get userHasAccessGrants(): boolean {
|
||||
return this.$store.state.accessGrantsModule.page.accessGrants.length > 0;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -246,7 +135,10 @@ export default class OnboardingTourArea extends Vue {
|
||||
}
|
||||
|
||||
&__content {
|
||||
padding: 0 100px 80px 100px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 110px 0 80px 0;
|
||||
position: relative;
|
||||
|
||||
&__tardigrade {
|
||||
@ -257,24 +149,4 @@ export default class OnboardingTourArea extends Vue {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1550px) {
|
||||
|
||||
.tour-area {
|
||||
|
||||
&__content {
|
||||
padding: 0 50px 80px 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1000px) {
|
||||
|
||||
.tour-area {
|
||||
|
||||
&__content {
|
||||
padding: 0 25px 80px 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -1,187 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="progress-bar-container">
|
||||
<div class="progress-bar-container__progress-area">
|
||||
<div
|
||||
v-if="isPaywallEnabled"
|
||||
class="progress-bar-container__progress-area__circle"
|
||||
:class="{ 'completed-step': isAddPaymentStep || isCreateProjectStep || isCreateApiKeyStep || isUploadDataStep }"
|
||||
>
|
||||
<CheckedImage/>
|
||||
</div>
|
||||
<div
|
||||
v-if="isPaywallEnabled"
|
||||
class="progress-bar-container__progress-area__bar"
|
||||
:class="{ 'completed-step': isCreateProjectStep || isCreateApiKeyStep || isUploadDataStep }"
|
||||
/>
|
||||
<div
|
||||
class="progress-bar-container__progress-area__circle"
|
||||
:class="{ 'completed-step': isCreateProjectStep || isCreateApiKeyStep || isUploadDataStep }"
|
||||
>
|
||||
<CheckedImage/>
|
||||
</div>
|
||||
<div
|
||||
class="progress-bar-container__progress-area__bar"
|
||||
:class="{ 'completed-step': isCreateApiKeyStep || isUploadDataStep }"
|
||||
/>
|
||||
<div
|
||||
class="progress-bar-container__progress-area__circle"
|
||||
:class="{ 'completed-step': isCreateApiKeyStep || isUploadDataStep }"
|
||||
>
|
||||
<CheckedImage/>
|
||||
</div>
|
||||
<div
|
||||
class="progress-bar-container__progress-area__bar"
|
||||
:class="{ 'completed-step': isUploadDataStep }"
|
||||
/>
|
||||
<div
|
||||
class="progress-bar-container__progress-area__circle"
|
||||
:class="{ 'completed-step': isUploadDataStep }"
|
||||
>
|
||||
<CheckedImage/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress-bar-container__titles-area" :class="{ 'titles-area-no-paywall': !isPaywallEnabled }">
|
||||
<span
|
||||
v-if="isPaywallEnabled"
|
||||
class="progress-bar-container__titles-area__title"
|
||||
:class="{ 'completed-font-color': isAddPaymentStep || isCreateProjectStep || isCreateApiKeyStep || isUploadDataStep }"
|
||||
>
|
||||
Add Payment
|
||||
</span>
|
||||
<span
|
||||
class="progress-bar-container__titles-area__title name-your-project-title"
|
||||
:class="{ 'completed-font-color': isCreateProjectStep || isCreateApiKeyStep || isUploadDataStep, 'title-no-paywall': !isPaywallEnabled }"
|
||||
>
|
||||
Name Your Project
|
||||
</span>
|
||||
<span
|
||||
class="progress-bar-container__titles-area__title api-key-title"
|
||||
:class="{ 'completed-font-color': isCreateApiKeyStep || isUploadDataStep }"
|
||||
>
|
||||
Create an API Key
|
||||
</span>
|
||||
<span
|
||||
class="progress-bar-container__titles-area__title"
|
||||
:class="{ 'completed-font-color': isUploadDataStep }"
|
||||
>
|
||||
Upload Data
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
|
||||
import CheckedImage from '@/../static/images/common/checked.svg';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
CheckedImage,
|
||||
},
|
||||
})
|
||||
|
||||
export default class ProgressBar extends Vue {
|
||||
@Prop({ default: false })
|
||||
public readonly isPaywallEnabled: boolean;
|
||||
@Prop({ default: false })
|
||||
public readonly isAddPaymentStep: boolean;
|
||||
@Prop({ default: false })
|
||||
public readonly isCreateProjectStep: boolean;
|
||||
@Prop({ default: false })
|
||||
public readonly isCreateApiKeyStep: boolean;
|
||||
@Prop({ default: false })
|
||||
public readonly isUploadDataStep: boolean;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.progress-bar-container {
|
||||
width: 100%;
|
||||
|
||||
&__progress-area {
|
||||
width: calc(100% - 420px);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 25px 210px 6px 210px;
|
||||
|
||||
&__circle {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
background-color: #c5cbdb;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&__bar {
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: #c5cbdb;
|
||||
}
|
||||
}
|
||||
|
||||
&__titles-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 188px 0 188px;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-size: 10px;
|
||||
line-height: 15px;
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.name-your-project-title {
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
.api-key-title {
|
||||
padding: 0 15px 0 0;
|
||||
}
|
||||
|
||||
.completed-step {
|
||||
background-color: #2683ff;
|
||||
}
|
||||
|
||||
.completed-font-color {
|
||||
color: #2683ff;
|
||||
}
|
||||
|
||||
.titles-area-no-paywall {
|
||||
padding: 0 188px 0 178px;
|
||||
}
|
||||
|
||||
.title-no-paywall {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
|
||||
.progress-bar-container {
|
||||
|
||||
&__progress-area {
|
||||
width: calc(100% - 300px);
|
||||
padding: 25px 150px 6px 150px;
|
||||
}
|
||||
|
||||
&__titles-area {
|
||||
padding: 0 128px 0 128px;
|
||||
}
|
||||
}
|
||||
|
||||
.titles-area-no-paywall {
|
||||
padding: 0 128px 0 118px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -5,7 +5,8 @@
|
||||
<div class="payment-step">
|
||||
<h1 class="payment-step__title">Get Started with 50 GB Free</h1>
|
||||
<p class="payment-step__sub-title">
|
||||
Adding a payment method ensures your project won’t be interrupted after your <b>free</b> credit is used.
|
||||
Experience the decentralized cloud for free! If you find our network isn’t for you, <b class="bold">cancel
|
||||
any time before your credit runs out and you won’t be billed.</b>
|
||||
</p>
|
||||
<div class="payment-step__methods-container">
|
||||
<div class="payment-step__methods-container__title-area">
|
||||
@ -32,12 +33,12 @@
|
||||
<AddCardState
|
||||
v-if="isAddCardState"
|
||||
@toggleIsLoading="toggleIsLoading"
|
||||
@setProjectState="setProjectState"
|
||||
@setCreateGrantStep="setCreateGrantStep"
|
||||
/>
|
||||
<AddStorjState
|
||||
v-if="isAddStorjState"
|
||||
@toggleIsLoading="toggleIsLoading"
|
||||
@setProjectState="setProjectState"
|
||||
@setCreateGrantStep="setCreateGrantStep"
|
||||
/>
|
||||
<h1 class="payment-step__title second-title">Transparent Monthly Pricing</h1>
|
||||
<p class="payment-step__sub-title">
|
||||
@ -84,6 +85,7 @@ import { Component, Vue } from 'vue-property-decorator';
|
||||
import AddCardState from '@/components/onboardingTour/steps/paymentStates/AddCardState.vue';
|
||||
import AddStorjState from '@/components/onboardingTour/steps/paymentStates/AddStorjState.vue';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { AddingPaymentState } from '@/utils/constants/onboardingTourEnums';
|
||||
|
||||
@Component({
|
||||
@ -102,6 +104,12 @@ export default class AddPaymentStep extends Vue {
|
||||
* Sets area to needed state.
|
||||
*/
|
||||
public mounted(): void {
|
||||
if (this.userHasProject) {
|
||||
this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant).path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.$store.getters.isTransactionProcessing || this.$store.getters.isBalancePositive) {
|
||||
this.setAddStorjState();
|
||||
}
|
||||
@ -143,10 +151,17 @@ export default class AddPaymentStep extends Vue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets tour area to creating project state.
|
||||
* Sets tour area to creating access grant state.
|
||||
*/
|
||||
public setProjectState(): void {
|
||||
this.$emit('setProjectState');
|
||||
public setCreateGrantStep(): void {
|
||||
this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant).with(RouteConfig.AccessGrantName).path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if user has at least one project.
|
||||
*/
|
||||
private get userHasProject(): boolean {
|
||||
return this.$store.state.projectsModule.projects.length > 0;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -160,15 +175,16 @@ export default class AddPaymentStep extends Vue {
|
||||
|
||||
.payment-step {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
margin-top: 75px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 140px 200px 140px;
|
||||
padding: 0 0 200px 0;
|
||||
max-width: 750px;
|
||||
position: relative;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 32px;
|
||||
line-height: 39px;
|
||||
color: #1b2533;
|
||||
@ -182,6 +198,10 @@ export default class AddPaymentStep extends Vue {
|
||||
margin-bottom: 35px;
|
||||
text-align: center;
|
||||
word-break: break-word;
|
||||
|
||||
.bold {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
&__methods-container {
|
||||
@ -302,18 +322,4 @@ export default class AddPaymentStep extends Vue {
|
||||
border-top: 1px solid #afb7c1;
|
||||
border-bottom: 1px solid #afb7c1;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1550px) {
|
||||
|
||||
.payment-step {
|
||||
padding: 0 70px 200px 70px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
|
||||
.payment-step {
|
||||
padding: 0 25px 200px 25px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,99 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="onboarding-access">
|
||||
<h1 class="onboarding-access__title">Create an Access Grant</h1>
|
||||
<p class="onboarding-access__sub-title">
|
||||
Access Grants are keys that allow access to upload, delete, and view your project’s data.
|
||||
</p>
|
||||
<div
|
||||
class="onboarding-access__content"
|
||||
:class="{
|
||||
'permissions-margin': isPermissionsStep,
|
||||
'passphrase-margin': isPassphraseStep,
|
||||
'result-margin': isResultStep,
|
||||
}"
|
||||
>
|
||||
<ProgressBar/>
|
||||
<router-view/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import ProgressBar from '@/components/accessGrants/ProgressBar.vue';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
ProgressBar,
|
||||
},
|
||||
})
|
||||
export default class CreateAccessGrantStep extends Vue {
|
||||
/**
|
||||
* Indicates if current route is access grant permissions step.
|
||||
*/
|
||||
public get isPermissionsStep(): boolean {
|
||||
return this.$route.name === RouteConfig.AccessGrantPermissions.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is access grant passphrase step.
|
||||
*/
|
||||
public get isPassphraseStep(): boolean {
|
||||
return this.$route.name === RouteConfig.AccessGrantPassphrase.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if current route is access grant result step.
|
||||
*/
|
||||
public get isResultStep(): boolean {
|
||||
return this.$route.name === RouteConfig.AccessGrantResult.name;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.onboarding-access {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-style: normal;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 32px;
|
||||
line-height: 39px;
|
||||
text-align: center;
|
||||
color: #1b2533;
|
||||
margin: 0 0 15px 0;
|
||||
}
|
||||
|
||||
&__sub-title {
|
||||
font-size: 16px;
|
||||
line-height: 21px;
|
||||
color: #000;
|
||||
margin: 0 0 50px 0;
|
||||
}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: -145px;
|
||||
}
|
||||
}
|
||||
|
||||
.permissions-margin {
|
||||
margin-left: -210px;
|
||||
}
|
||||
|
||||
.passphrase-margin {
|
||||
margin-left: -180px;
|
||||
}
|
||||
|
||||
.result-margin {
|
||||
margin-left: -175px;
|
||||
}
|
||||
</style>
|
@ -1,385 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="create-api-key-step">
|
||||
<h1 class="create-api-key-step__title">Create an API Key</h1>
|
||||
<p class="create-api-key-step__sub-title">
|
||||
API keys provide access to the project for creating buckets and uploading objects through the command line
|
||||
interface. This will be your first API key, and you can always create more keys later on.
|
||||
</p>
|
||||
<div class="create-api-key-step__container">
|
||||
<div class="create-api-key-step__container__title-area">
|
||||
<h2 class="create-api-key-step__container__title-area__title">Create API Key</h2>
|
||||
<img
|
||||
v-if="isLoading"
|
||||
class="create-api-key-step__container__title-area__loading-image"
|
||||
src="@/../static/images/account/billing/loading.gif"
|
||||
alt="loading gif"
|
||||
>
|
||||
</div>
|
||||
<HeaderedInput
|
||||
label="API Key Name"
|
||||
placeholder="Enter API Key Name (i.e. Dan’s Key)"
|
||||
class="full-input"
|
||||
width="calc(100% - 4px)"
|
||||
:error="errorMessage"
|
||||
@setData="setApiKeyName"
|
||||
/>
|
||||
<div class="create-api-key-step__container__create-key-area" v-if="isCreatingState">
|
||||
<VButton
|
||||
class="generate-button"
|
||||
width="100%"
|
||||
height="40px"
|
||||
label="Generate API Key"
|
||||
:is-blue-white="true"
|
||||
:on-press="createApiKey"
|
||||
/>
|
||||
</div>
|
||||
<div class="create-api-key-step__container__copy-key-area" v-else>
|
||||
<div class="create-api-key-step__container__copy-key-area__header">
|
||||
<InfoImage/>
|
||||
<span class="create-api-key-step__container__copy-key-area__header__title">
|
||||
API Keys only appear here once. Copy and paste this key to your preferred method of storing secrets.
|
||||
</span>
|
||||
</div>
|
||||
<div class="create-api-key-step__container__copy-key-area__key-container">
|
||||
<span class="create-api-key-step__container__copy-key-area__key-container__key">{{ key }}</span>
|
||||
<div class="create-api-key-step__container__copy-key-area__key-container__copy-button">
|
||||
<VButton
|
||||
width="81px"
|
||||
height="40px"
|
||||
label="Copy"
|
||||
:is-blue-white="true"
|
||||
:on-press="onCopyClick"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="create-api-key-step__container__info" v-if="isCopyState">
|
||||
We don’t record your API Keys, which are only displayed once when generated. If you loose this
|
||||
key, it cannot be recovered – but you can always create new API Keys when needed.
|
||||
</p>
|
||||
<div class="create-api-key-step__container__blur" v-if="isLoading"/>
|
||||
</div>
|
||||
<VButton
|
||||
class="done-button"
|
||||
width="156px"
|
||||
height="48px"
|
||||
label="Done"
|
||||
:on-press="onDoneClick"
|
||||
:is-disabled="isCreatingState"
|
||||
/>
|
||||
<SaveApiKeyModal
|
||||
v-if="isSaveApiKeyModalShown"
|
||||
@confirmSave="onConfirmClick"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import HeaderedInput from '@/components/common/HeaderedInput.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
import SaveApiKeyModal from '@/components/onboardingTour/steps/SaveApiKeyModal.vue';
|
||||
|
||||
import InfoImage from '@/../static/images/onboardingTour/info.svg';
|
||||
|
||||
import { API_KEYS_ACTIONS } from '@/store/modules/apiKeys';
|
||||
import { ApiKey } from '@/types/apiKeys';
|
||||
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { AddingApiKeyState } from '@/utils/constants/onboardingTourEnums';
|
||||
|
||||
const {
|
||||
CREATE,
|
||||
FETCH,
|
||||
} = API_KEYS_ACTIONS;
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
VButton,
|
||||
HeaderedInput,
|
||||
SaveApiKeyModal,
|
||||
InfoImage,
|
||||
},
|
||||
})
|
||||
export default class CreateApiKeyStep extends Vue {
|
||||
private name: string = '';
|
||||
private addingState: number = AddingApiKeyState.CREATE;
|
||||
private readonly FIRST_PAGE = 1;
|
||||
|
||||
public key: string = '';
|
||||
public errorMessage: string = '';
|
||||
public isLoading: boolean = false;
|
||||
|
||||
/**
|
||||
* Indicates if save API key modal is shown.
|
||||
*/
|
||||
public get isSaveApiKeyModalShown(): boolean {
|
||||
return this.$store.state.appStateModule.appState.isSaveApiKeyModalShown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if view is in creating state.
|
||||
*/
|
||||
public get isCreatingState(): boolean {
|
||||
return this.addingState === AddingApiKeyState.CREATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if view is in copy state.
|
||||
*/
|
||||
public get isCopyState(): boolean {
|
||||
return this.addingState === AddingApiKeyState.COPY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates view state to copy state.
|
||||
*/
|
||||
public setCopyState(): void {
|
||||
this.addingState = AddingApiKeyState.COPY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets api key name from input value.
|
||||
*/
|
||||
public setApiKeyName(value: string): void {
|
||||
this.name = value.trim();
|
||||
this.errorMessage = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates api key and refreshes store.
|
||||
*/
|
||||
public async createApiKey(): Promise<void> {
|
||||
if (this.isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.name) {
|
||||
this.errorMessage = 'API Key name can`t be empty';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
let createdApiKey: ApiKey;
|
||||
|
||||
try {
|
||||
createdApiKey = await this.$store.dispatch(CREATE, this.name);
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
this.isLoading = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$notify.success('Successfully created new api key');
|
||||
this.key = createdApiKey.secret;
|
||||
|
||||
this.$segment.track(SegmentEvent.API_KEY_CREATED, {
|
||||
project_id: this.$store.getters.selectedProject.id,
|
||||
});
|
||||
|
||||
try {
|
||||
await this.$store.dispatch(FETCH, this.FIRST_PAGE);
|
||||
} catch (error) {
|
||||
await this.$notify.error(`Unable to fetch API keys. ${error.message}`);
|
||||
}
|
||||
|
||||
this.setCopyState();
|
||||
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies api key secret to buffer.
|
||||
*/
|
||||
public onCopyClick(): void {
|
||||
this.$copyText(this.key);
|
||||
this.$notify.success('Key saved to clipboard');
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles save API key modal visibility.
|
||||
*/
|
||||
public onDoneClick(): void {
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_SAVE_API_KEY_MODAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets tour state to last step.
|
||||
*/
|
||||
public onConfirmClick(): void {
|
||||
this.onDoneClick();
|
||||
this.$emit('setUploadDataState');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
h1,
|
||||
h2,
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.create-api-key-step {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
margin-top: 75px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 200px;
|
||||
|
||||
&__title {
|
||||
font-size: 32px;
|
||||
line-height: 39px;
|
||||
color: #1b2533;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
&__sub-title {
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
color: #354049;
|
||||
margin-bottom: 35px;
|
||||
text-align: center;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&__container {
|
||||
padding: 50px;
|
||||
width: calc(100% - 100px);
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
margin-bottom: 30px;
|
||||
|
||||
&__title-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
font-size: 22px;
|
||||
line-height: 27px;
|
||||
color: #354049;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
&__loading-image {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
&__create-key-area {
|
||||
width: calc(100% - 90px);
|
||||
padding: 40px 45px;
|
||||
margin-top: 30px;
|
||||
background-color: #0c2546;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
&__copy-key-area {
|
||||
width: 100%;
|
||||
margin-top: 30px;
|
||||
|
||||
&__header {
|
||||
padding: 10px;
|
||||
width: calc(100% - 20px);
|
||||
background-color: #ce3030;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
border-radius: 8px 8px 0 0;
|
||||
|
||||
&__title {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&__key-container {
|
||||
background-color: #0c2546;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20px 25px;
|
||||
width: calc(100% - 50px);
|
||||
border-radius: 0 0 8px 8px;
|
||||
|
||||
&__key {
|
||||
font-size: 15px;
|
||||
line-height: 23px;
|
||||
color: #fff;
|
||||
margin-right: 50px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
&__copy-button {
|
||||
min-width: 85px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__info {
|
||||
width: 100%;
|
||||
margin-top: 30px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
text-align: center;
|
||||
color: #354049;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&__blur {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: rgba(229, 229, 229, 0.2);
|
||||
z-index: 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.full-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.info-svg {
|
||||
min-width: 18px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1650px) {
|
||||
|
||||
.create-api-key-step {
|
||||
padding: 0 100px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1450px) {
|
||||
|
||||
.create-api-key-step {
|
||||
padding: 0 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
|
||||
.create-api-key-step {
|
||||
padding: 0 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,280 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="new-project-step">
|
||||
<h1 class="new-project-step__title">Name Your Project</h1>
|
||||
<p class="new-project-step__sub-title">
|
||||
Projects are where buckets are created for storing data. Within a Project, usage is tracked at the bucket
|
||||
level and aggregated for billing.
|
||||
</p>
|
||||
<div class="new-project-step__container">
|
||||
<div class="new-project-step__container__title-area">
|
||||
<h2 class="new-project-step__container__title-area__title">Project Details</h2>
|
||||
<img
|
||||
v-if="isLoading"
|
||||
class="new-project-step__container__title-area__loading-image"
|
||||
src="@/../static/images/account/billing/loading.gif"
|
||||
alt="loading gif"
|
||||
>
|
||||
</div>
|
||||
<HeaderedInput
|
||||
label="Project Name"
|
||||
additional-label="Up To 20 Characters"
|
||||
placeholder="Enter Project Name"
|
||||
class="full-input project-name-input"
|
||||
width="100%"
|
||||
is-limit-shown="true"
|
||||
:current-limit="projectName.length"
|
||||
:max-symbols="20"
|
||||
:error="nameError"
|
||||
@setData="setProjectName"
|
||||
/>
|
||||
<HeaderedInput
|
||||
label="Description"
|
||||
placeholder="Enter Project Description"
|
||||
additional-label="Optional"
|
||||
class="full-input"
|
||||
is-multiline="true"
|
||||
is-limit-shown="true"
|
||||
:current-limit="description.length"
|
||||
:max-symbols="100"
|
||||
height="60px"
|
||||
width="calc(100% - 42px)"
|
||||
@setData="setProjectDescription"
|
||||
/>
|
||||
<div class="new-project-step__container__blur" v-if="isLoading"/>
|
||||
</div>
|
||||
<VButton
|
||||
class="create-project-button"
|
||||
width="156px"
|
||||
height="48px"
|
||||
label="Create Project"
|
||||
:on-press="createProjectClick"
|
||||
:is-disabled="!projectName"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import HeaderedInput from '@/components/common/HeaderedInput.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
import { API_KEYS_ACTIONS } from '@/store/modules/apiKeys';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { ProjectFields } from '@/types/projects';
|
||||
import { PM_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
VButton,
|
||||
HeaderedInput,
|
||||
},
|
||||
})
|
||||
export default class CreateProjectStep extends Vue {
|
||||
private description: string = '';
|
||||
|
||||
public projectName: string = '';
|
||||
public isLoading: boolean = false;
|
||||
public nameError: string = '';
|
||||
|
||||
/**
|
||||
* Sets project name from input value.
|
||||
*/
|
||||
public setProjectName(value: string): void {
|
||||
this.projectName = value;
|
||||
this.nameError = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets project description from input value.
|
||||
*/
|
||||
public setProjectDescription(value: string): void {
|
||||
this.description = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates project and refreshes store.
|
||||
*/
|
||||
public async createProjectClick(): Promise<void> {
|
||||
if (this.isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
this.projectName = this.projectName.trim();
|
||||
|
||||
const project = new ProjectFields(
|
||||
this.projectName,
|
||||
this.description,
|
||||
this.$store.getters.user.id,
|
||||
);
|
||||
|
||||
try {
|
||||
project.checkName();
|
||||
} catch (error) {
|
||||
this.isLoading = false;
|
||||
this.nameError = error.message;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let createdProjectId: string = '';
|
||||
|
||||
try {
|
||||
const createdProject = await this.$store.dispatch(PROJECTS_ACTIONS.CREATE, project);
|
||||
createdProjectId = createdProject.id;
|
||||
this.$segment.track(SegmentEvent.PROJECT_CREATED, {
|
||||
project_id: createdProjectId,
|
||||
});
|
||||
} catch (error) {
|
||||
this.isLoading = false;
|
||||
await this.$notify.error(error.message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.SELECT, createdProjectId);
|
||||
|
||||
try {
|
||||
await this.fetchProjectMembers();
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PAYMENTS_HISTORY);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_BALANCE);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, createdProjectId);
|
||||
} catch (error) {
|
||||
await this.$notify.error(`Unable to create project. ${error.message}`);
|
||||
}
|
||||
|
||||
this.clearApiKeys();
|
||||
|
||||
this.clearBucketUsage();
|
||||
|
||||
await this.$notify.success('Project created successfully!');
|
||||
|
||||
this.isLoading = false;
|
||||
|
||||
this.$emit('setApiKeyState');
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears project members store and fetches new.
|
||||
*/
|
||||
private async fetchProjectMembers(): Promise<void> {
|
||||
await this.$store.dispatch(PM_ACTIONS.CLEAR);
|
||||
const fistPage = 1;
|
||||
await this.$store.dispatch(PM_ACTIONS.FETCH, fistPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears api keys store.
|
||||
*/
|
||||
private clearApiKeys(): void {
|
||||
this.$store.dispatch(API_KEYS_ACTIONS.CLEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears bucket usage store.
|
||||
*/
|
||||
private clearBucketUsage(): void {
|
||||
this.$store.dispatch(BUCKET_ACTIONS.CLEAR);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
h1,
|
||||
h2,
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.new-project-step {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
margin-top: 75px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 200px;
|
||||
|
||||
&__title {
|
||||
font-size: 32px;
|
||||
line-height: 39px;
|
||||
color: #1b2533;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
&__sub-title {
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
color: #354049;
|
||||
margin-bottom: 35px;
|
||||
text-align: center;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&__container {
|
||||
padding: 50px;
|
||||
width: calc(100% - 100px);
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
margin-bottom: 30px;
|
||||
|
||||
&__title-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
font-size: 22px;
|
||||
line-height: 27px;
|
||||
color: #354049;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
&__loading-image {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
&__blur {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: rgba(229, 229, 229, 0.2);
|
||||
z-index: 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.full-input {
|
||||
width: 100%;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1450px) {
|
||||
|
||||
.new-project-step {
|
||||
padding: 0 150px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
|
||||
.new-project-step {
|
||||
padding: 0 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -8,27 +8,103 @@ import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
import FourthStepIcon from '@/../static/images/common/four.svg';
|
||||
import FirstStepIcon from '@/../static/images/common/one.svg';
|
||||
import ThirdStepIcon from '@/../static/images/common/three.svg';
|
||||
import SecondStepIcon from '@/../static/images/common/two.svg';
|
||||
import { RouteConfig } from '@/router';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { ProjectFields } from '@/types/projects';
|
||||
import { PM_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
VButton,
|
||||
FirstStepIcon,
|
||||
ThirdStepIcon,
|
||||
SecondStepIcon,
|
||||
FourthStepIcon,
|
||||
},
|
||||
})
|
||||
export default class OverviewStep extends Vue {
|
||||
public isLoading: boolean = false;
|
||||
|
||||
/**
|
||||
* Lifecycle hook after initial render.
|
||||
* Sets area to needed state.
|
||||
*/
|
||||
public mounted(): void {
|
||||
if (this.userHasProject || this.$store.state.paymentsModule.creditCards.length > 0) {
|
||||
this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant).path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.$store.getters.isTransactionProcessing || this.$store.getters.isBalancePositive) {
|
||||
this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.PaymentStep).path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds button click logic.
|
||||
* Sets tour state to adding payment method state.
|
||||
* Redirects to next step (adding payment method).
|
||||
*/
|
||||
public onClick(): void {
|
||||
this.$emit('setAddPaymentState');
|
||||
public onAddPaymentClick(): void {
|
||||
this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.PaymentStep).path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds button click logic.
|
||||
* Creates untitled project and redirects to next step (creating access grant).
|
||||
*/
|
||||
public async onCreateGrantClick(): Promise<void> {
|
||||
if (this.isLoading) return;
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
try {
|
||||
const FIRST_PAGE = 1;
|
||||
const UNTITLED_PROJECT_NAME = 'Untitled Project';
|
||||
const UNTITLED_PROJECT_DESCRIPTION = '___';
|
||||
const project = new ProjectFields(
|
||||
UNTITLED_PROJECT_NAME,
|
||||
UNTITLED_PROJECT_DESCRIPTION,
|
||||
this.$store.getters.user.id,
|
||||
);
|
||||
const createdProject = await this.$store.dispatch(PROJECTS_ACTIONS.CREATE, project);
|
||||
const createdProjectId = createdProject.id;
|
||||
|
||||
this.$segment.track(SegmentEvent.PROJECT_CREATED, {
|
||||
project_id: createdProjectId,
|
||||
});
|
||||
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.SELECT, createdProjectId);
|
||||
await this.$store.dispatch(PM_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(PM_ACTIONS.FETCH, FIRST_PAGE);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PAYMENTS_HISTORY);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_BALANCE);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, createdProjectId);
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.CLEAR);
|
||||
|
||||
this.isLoading = false;
|
||||
|
||||
await this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant).with(RouteConfig.AccessGrantName).path);
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if paywall is enabled.
|
||||
*/
|
||||
public get isPaywallEnabled(): boolean {
|
||||
return this.$store.state.paymentsModule.isPaywallEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if user has at least one project.
|
||||
*/
|
||||
private get userHasProject(): boolean {
|
||||
return this.$store.state.projectsModule.projects.length > 0;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -1,34 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template src="./overviewStepNoPaywall.html"></template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
import FirstStepIcon from '@/../static/images/common/one.svg';
|
||||
import ThirdStepIcon from '@/../static/images/common/three.svg';
|
||||
import SecondStepIcon from '@/../static/images/common/two.svg';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
VButton,
|
||||
FirstStepIcon,
|
||||
ThirdStepIcon,
|
||||
SecondStepIcon,
|
||||
},
|
||||
})
|
||||
export default class OverviewStepNoPaywall extends Vue {
|
||||
/**
|
||||
* Holds button click logic.
|
||||
* Sets tour state to adding project state.
|
||||
*/
|
||||
public onClick(): void {
|
||||
this.$emit('setCreateProjectState');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss" src="./overviewStepNoPaywall.scss"></style>
|
@ -1,116 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="save-api-modal">
|
||||
<div class="save-api-modal__container">
|
||||
<OrangeExclamation/>
|
||||
<h1 class="save-api-modal__container__title">Is Your API Key Saved?</h1>
|
||||
<p class="save-api-modal__container__message">
|
||||
API Keys are only displayed once when generated. If you haven’t saved your key, go back to copy and
|
||||
paste the API key to your preferred method of storing secrets (i.e. TextEdit, Keybase, etc.)
|
||||
</p>
|
||||
<div class="save-api-modal__container__buttons-area">
|
||||
<VButton
|
||||
class="back-button"
|
||||
width="186px"
|
||||
height="45px"
|
||||
label="Go Back"
|
||||
:on-press="onBackClick"
|
||||
:is-blue-white="true"
|
||||
/>
|
||||
<VButton
|
||||
width="186px"
|
||||
height="45px"
|
||||
label="Yes, it's Saved!"
|
||||
:on-press="onConfirmClick"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
import OrangeExclamation from '@/../static/images/onboardingTour/orange-exclamation.svg';
|
||||
|
||||
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
OrangeExclamation,
|
||||
VButton,
|
||||
},
|
||||
})
|
||||
|
||||
export default class SaveApiKeyModal extends Vue {
|
||||
/**
|
||||
* Toggles modal visibility.
|
||||
*/
|
||||
public onBackClick(): void {
|
||||
this.$store.dispatch(APP_STATE_ACTIONS.TOGGLE_SAVE_API_KEY_MODAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proceeds to tour's last step.
|
||||
*/
|
||||
public onConfirmClick(): void {
|
||||
this.$emit('confirmSave');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.save-api-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(9, 21, 35, 0.85);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: 'font_regular', sans-serif;
|
||||
|
||||
&__container {
|
||||
background-color: #fff;
|
||||
z-index: 1;
|
||||
padding: 35px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
max-width: 460px;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 22px;
|
||||
line-height: 27px;
|
||||
color: #000;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
&__message {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
color: #000;
|
||||
word-break: break-word;
|
||||
text-align: center;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
&__buttons-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.back-button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
@ -1,250 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<div class="upload-data-area">
|
||||
<div class="upload-data-area__container">
|
||||
<h1 class="upload-data-area__container__title">Upload Data</h1>
|
||||
<p class="upload-data-area__container__sub-title">
|
||||
From here, you’ll set up Tardigrade to store data for your project using our S3 Gateway, Uplink CLI, or
|
||||
select from our growing library of connectors to build apps on Tardigrade.
|
||||
</p>
|
||||
<div class="upload-data-area__container__docs-area">
|
||||
<div class="upload-data-area__container__docs-area__option">
|
||||
<h2 class="upload-data-area__container__docs-area__option__title">
|
||||
Migrate Data from your Existing AWS buckets
|
||||
</h2>
|
||||
<img src="@/../static/images/onboardingTour/s3.png" alt="s3 gateway image">
|
||||
<h3 class="upload-data-area__container__docs-area__option__sub-title">
|
||||
S3 Gateway
|
||||
</h3>
|
||||
<p class="upload-data-area__container__docs-area__option__info">
|
||||
Make the switch with Tardigrade’s S3 Gateway.
|
||||
</p>
|
||||
<a
|
||||
class="upload-data-area__container__docs-area__option__link"
|
||||
href="https://documentation.tardigrade.io/api-reference/s3-gateway"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
S3 Gateway Docs
|
||||
</a>
|
||||
</div>
|
||||
<div class="upload-data-area__container__docs-area__option uplink-option">
|
||||
<h2 class="upload-data-area__container__docs-area__option__title">
|
||||
Upload Data from Your Local Environment
|
||||
</h2>
|
||||
<img src="@/../static/images/onboardingTour/uplinkcli.png" alt="uplink cli image">
|
||||
<h3 class="upload-data-area__container__docs-area__option__sub-title">
|
||||
Uplink CLI
|
||||
</h3>
|
||||
<p class="upload-data-area__container__docs-area__option__info">
|
||||
Start uploading data from the command line.
|
||||
</p>
|
||||
<a
|
||||
class="upload-data-area__container__docs-area__option__link"
|
||||
href="https://documentation.tardigrade.io/getting-started/uploading-your-first-object/set-up-uplink-cli"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Uplink CLI Docs
|
||||
</a>
|
||||
</div>
|
||||
<div class="upload-data-area__container__docs-area__option">
|
||||
<h2 class="upload-data-area__container__docs-area__option__title">
|
||||
Use Tardigrade for your app’s storage layer
|
||||
</h2>
|
||||
<img src="@/../static/images/onboardingTour/connectors.png" alt="connectors image">
|
||||
<h3 class="upload-data-area__container__docs-area__option__sub-title">
|
||||
App Connectors
|
||||
</h3>
|
||||
<p class="upload-data-area__container__docs-area__option__info">
|
||||
Integrate Tardigrade into your existing stack.
|
||||
</p>
|
||||
<a
|
||||
class="upload-data-area__container__docs-area__option__link"
|
||||
href="https://tardigrade.io/connectors/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
App Connectors
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<VButton
|
||||
class="go-to-button"
|
||||
width="276px"
|
||||
height="40px"
|
||||
label="Go to Dashboard"
|
||||
:on-press="onButtonClick"
|
||||
/>
|
||||
<span class="upload-data-area__support-info">
|
||||
Need help?
|
||||
<a
|
||||
class="upload-data-area__support-info__link"
|
||||
href="https://support.tardigrade.io/hc/en-us"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Contact support
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
VButton,
|
||||
},
|
||||
})
|
||||
|
||||
export default class UploadDataStep extends Vue {
|
||||
/**
|
||||
* Holds button click logic.
|
||||
* Ends onboarding tour and redirects to project dashboard.
|
||||
*/
|
||||
public onButtonClick(): void {
|
||||
this.$router.push(RouteConfig.ProjectDashboard.path);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.upload-data-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
font-family: 'font_regular', sans-serif;
|
||||
margin-top: 25px;
|
||||
|
||||
&__container {
|
||||
padding: 60px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: rgba(255, 255, 255, 0.4);
|
||||
border-radius: 8px;
|
||||
margin-bottom: 50px;
|
||||
|
||||
&__title {
|
||||
font-size: 32px;
|
||||
line-height: 39px;
|
||||
color: #1b2533;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
&__sub-title {
|
||||
font-size: 16px;
|
||||
line-height: 19px;
|
||||
color: #354049;
|
||||
margin-bottom: 35px;
|
||||
text-align: center;
|
||||
word-break: break-word;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
&__docs-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
&__option {
|
||||
padding: 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
border: 1px solid rgba(144, 155, 168, 0.4);
|
||||
border-radius: 8px;
|
||||
|
||||
&__title {
|
||||
font-size: 10px;
|
||||
line-height: 15px;
|
||||
text-align: center;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: #909ba8;
|
||||
margin-bottom: 25px;
|
||||
max-width: 181px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&__sub-title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
color: #354049;
|
||||
margin: 25px 0 5px 0;
|
||||
}
|
||||
|
||||
&__info {
|
||||
font-size: 14px;
|
||||
line-height: 17px;
|
||||
text-align: center;
|
||||
color: #61666b;
|
||||
max-width: 181px;
|
||||
word-break: break-word;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
&__link {
|
||||
width: 181px;
|
||||
height: 40px;
|
||||
border: 1px solid #2683ff;
|
||||
border-radius: 6px;
|
||||
background-color: #fff;
|
||||
color: #2683ff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
background-color: #2683ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__support-info {
|
||||
margin-top: 50px;
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
color: #909ba8;
|
||||
|
||||
&__link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.uplink-option {
|
||||
margin: 0 45px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1350px) {
|
||||
|
||||
.uplink-option {
|
||||
margin: 0 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -2,50 +2,49 @@
|
||||
<!--See LICENSE for copying information.-->
|
||||
|
||||
<div class="overview-area">
|
||||
<h1 class="overview-area__title">Welcome to Storj</h1>
|
||||
<h1 class="overview-area__title">
|
||||
Welcome to Storj.
|
||||
<br/>
|
||||
Let’s Get Started.
|
||||
</h1>
|
||||
<p class="overview-area__sub-title">
|
||||
You’re just a few steps away from uploading your first object to the 100% secure, decentralized cloud. After
|
||||
adding payment, you’ll create a project, API key, get set up with Storj, and start uploading objects.
|
||||
Follow the docs to start storing data using method below.
|
||||
</p>
|
||||
<div class="overview-area__steps-area">
|
||||
<div class="overview-area__steps-area__step">
|
||||
<FirstStepIcon class="overview-area__steps-area__step__icon"/>
|
||||
<img class="overview-step-image" src="@/../static/images/onboardingTour/card.png" alt="card image">
|
||||
<h2 class="overview-area__steps-area__step__title">Add Payment</h2>
|
||||
<span class="overview-area__steps-area__step__subtitle">
|
||||
Get 50 GB free to try Storj. Cancel anytime.
|
||||
</span>
|
||||
</div>
|
||||
<div class="overview-area__steps-area__step second-step">
|
||||
<SecondStepIcon class="overview-area__steps-area__step__icon"/>
|
||||
<img class="overview-step-image" src="@/../static/images/onboardingTour/project.jpg" alt="project image">
|
||||
<h2 class="overview-area__steps-area__step__title">Name Your Project</h2>
|
||||
<span class="overview-area__steps-area__step__subtitle">
|
||||
Projects are where buckets are created for storing data.
|
||||
</span>
|
||||
</div>
|
||||
<div class="overview-area__steps-area__step third-step">
|
||||
<ThirdStepIcon class="overview-area__steps-area__step__icon"/>
|
||||
<img class="overview-step-image" src="@/../static/images/onboardingTour/api-key.jpg" alt="api keys image">
|
||||
<h2 class="overview-area__steps-area__step__title">Create an API Key</h2>
|
||||
<span class="overview-area__steps-area__step__subtitle">
|
||||
Generate access to your project to upload data.
|
||||
</span>
|
||||
</div>
|
||||
<div class="overview-area__steps-area__step">
|
||||
<FourthStepIcon class="overview-area__steps-area__step__icon"/>
|
||||
<img class="overview-step-image" src="@/../static/images/onboardingTour/uplink.jpg" alt="uplink image">
|
||||
<h2 class="overview-area__steps-area__step__title">Upload Data</h2>
|
||||
<span class="overview-area__steps-area__step__subtitle">
|
||||
Store your data on the secure, decentralized cloud.
|
||||
</span>
|
||||
<img class="overview-area__steps-area__step__image" src="@/../static/images/onboardingTour/cli.png" alt="cli image">
|
||||
<h2 class="overview-area__steps-area__step__title">CLI Tool</h2>
|
||||
<p class="overview-area__steps-area__step__info">
|
||||
Quickly upload data directly through the command line interface.
|
||||
</p>
|
||||
<a
|
||||
class="overview-area__steps-area__step__link"
|
||||
href="https://documentation.storj.io/setup/cli"
|
||||
target="_blank"
|
||||
ref="noopener noreferrer"
|
||||
>
|
||||
CLI Docs >
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-area__divider"/>
|
||||
<p class="overview-area__next-label">Next</p>
|
||||
<VButton
|
||||
class="get-started-button"
|
||||
label="Get Started"
|
||||
width="251px"
|
||||
height="56px"
|
||||
:on-press="onClick"
|
||||
v-if="isPaywallEnabled"
|
||||
class="overview-area__cta"
|
||||
label="Add a Payment Method"
|
||||
width="252px"
|
||||
height="48px"
|
||||
:is-disabled="isLoading"
|
||||
:on-press="onAddPaymentClick"
|
||||
/>
|
||||
<VButton
|
||||
v-else
|
||||
class="overview-area__cta"
|
||||
label="Create an Access Grant"
|
||||
width="252px"
|
||||
height="48px"
|
||||
:is-disabled="isLoading"
|
||||
:on-press="onCreateGrantClick"
|
||||
/>
|
||||
</div>
|
||||
|
@ -8,8 +8,7 @@ h2 {
|
||||
}
|
||||
|
||||
.overview-area {
|
||||
width: auto;
|
||||
padding: 75px;
|
||||
padding: 60px 75px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@ -17,47 +16,38 @@ h2 {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
background-color: #fff;
|
||||
border-radius: 6px;
|
||||
margin-top: 25px;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 32px;
|
||||
line-height: 39px;
|
||||
color: #1b2533;
|
||||
margin-bottom: 25px;
|
||||
margin: 0 0 15px 0;
|
||||
font-weight: bold;
|
||||
font-size: 32px;
|
||||
line-height: 47px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__sub-title {
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
color: #354049;
|
||||
margin-bottom: 60px;
|
||||
margin: 0 0 60px 0;
|
||||
text-align: center;
|
||||
max-width: 815px;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&__steps-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 50px;
|
||||
margin-bottom: 60px;
|
||||
|
||||
&__step {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
max-width: 190px;
|
||||
width: 190px;
|
||||
|
||||
&__icon {
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
left: 80px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
@ -65,51 +55,50 @@ h2 {
|
||||
margin: 15px 0 5px 0;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
&__info {
|
||||
font-weight: 300;
|
||||
font-size: 14px;
|
||||
line-height: 17px;
|
||||
text-align: center;
|
||||
color: #61666b;
|
||||
color: #1b2533;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&__link {
|
||||
margin-top: 30px;
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
color: #0068dc;
|
||||
justify-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__divider {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: rgba(118, 131, 148, 0.4);
|
||||
}
|
||||
|
||||
&__next-label {
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
color: #768394;
|
||||
margin: 30px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.second-step {
|
||||
margin: 0 25px 0 50px;
|
||||
}
|
||||
|
||||
.third-step {
|
||||
margin: 0 50px 0 25px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1450px) {
|
||||
@media screen and (max-width: 1050px) {
|
||||
|
||||
.overview-area {
|
||||
padding: 75px 30px;
|
||||
}
|
||||
|
||||
.second-step {
|
||||
margin: 0 10px 0 20px;
|
||||
}
|
||||
|
||||
.third-step {
|
||||
margin: 0 20px 0 10px;
|
||||
padding: 60px 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
|
||||
.overview-area {
|
||||
|
||||
&__steps-area {
|
||||
flex-direction: column;
|
||||
|
||||
&__step {
|
||||
margin: 0 0 30px 0;
|
||||
}
|
||||
}
|
||||
padding: 30px 20px;
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
<!--Copyright (C) 2020 Storj Labs, Inc.-->
|
||||
<!--See LICENSE for copying information.-->
|
||||
|
||||
<div class="overview-area">
|
||||
<h1 class="overview-area__title">Welcome to Storj</h1>
|
||||
<p class="overview-area__sub-title">
|
||||
You’re just a few steps away from uploading your first object to the 100% secure, decentralized cloud. Simply
|
||||
add a payment method any time before your credit runs out to keep using Storj.
|
||||
</p>
|
||||
<div class="overview-area__steps-area">
|
||||
<div class="overview-area__steps-area__step">
|
||||
<FirstStepIcon class="overview-area__steps-area__step__icon"/>
|
||||
<img class="overview-step-image" src="@/../static/images/onboardingTour/project.jpg" alt="project image">
|
||||
<h2 class="overview-area__steps-area__step__title">Name Your Project</h2>
|
||||
<span class="overview-area__steps-area__step__subtitle">
|
||||
Projects are where buckets are created for storing data.
|
||||
</span>
|
||||
</div>
|
||||
<div class="overview-area__steps-area__step second-step">
|
||||
<SecondStepIcon class="overview-area__steps-area__step__icon"/>
|
||||
<img class="overview-step-image" src="@/../static/images/onboardingTour/api-key.jpg" alt="api keys image">
|
||||
<h2 class="overview-area__steps-area__step__title">Create an API Key</h2>
|
||||
<span class="overview-area__steps-area__step__subtitle">
|
||||
Generate access to your project to upload data.
|
||||
</span>
|
||||
</div>
|
||||
<div class="overview-area__steps-area__step">
|
||||
<ThirdStepIcon class="overview-area__steps-area__step__icon"/>
|
||||
<img class="overview-step-image" src="@/../static/images/onboardingTour/uplink.jpg" alt="uplink image">
|
||||
<h2 class="overview-area__steps-area__step__title">Upload Data</h2>
|
||||
<span class="overview-area__steps-area__step__subtitle">
|
||||
Store your data on the secure, decentralized cloud.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<VButton
|
||||
class="get-started-button"
|
||||
label="Get Started"
|
||||
width="251px"
|
||||
height="56px"
|
||||
:on-press="onClick"
|
||||
/>
|
||||
</div>
|
@ -1,107 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
p,
|
||||
h1,
|
||||
h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.overview-area {
|
||||
width: auto;
|
||||
padding: 75px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-family: 'font_regular', sans-serif;
|
||||
background-color: #fff;
|
||||
border-radius: 6px;
|
||||
margin-top: 25px;
|
||||
|
||||
&__title {
|
||||
font-family: 'font_bold', sans-serif;
|
||||
font-size: 32px;
|
||||
line-height: 39px;
|
||||
color: #1b2533;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
&__sub-title {
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
color: #354049;
|
||||
margin-bottom: 60px;
|
||||
text-align: center;
|
||||
max-width: 815px;
|
||||
}
|
||||
|
||||
&__steps-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 50px;
|
||||
|
||||
&__step {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
max-width: 190px;
|
||||
width: 190px;
|
||||
|
||||
&__icon {
|
||||
position: absolute;
|
||||
top: -15px;
|
||||
left: 80px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
color: #354049;
|
||||
margin: 15px 0 5px 0;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-family: 'font_regular', sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 17px;
|
||||
text-align: center;
|
||||
color: #61666b;
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.second-step {
|
||||
margin: 0 50px 0 50px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1450px) {
|
||||
|
||||
.overview-area {
|
||||
padding: 75px 30px;
|
||||
}
|
||||
|
||||
.second-step {
|
||||
margin: 0 20px 0 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
|
||||
.overview-area {
|
||||
|
||||
&__steps-area {
|
||||
flex-direction: column;
|
||||
|
||||
&__step {
|
||||
margin: 0 0 30px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,15 +16,14 @@
|
||||
Your card is secured by 128-bit SSL and AES-256 encryption. Your information is secure.
|
||||
</span>
|
||||
</div>
|
||||
<div class="add-card-state__button" :class="{ loading: isLoading }" @click="onConfirmAddStripe">
|
||||
<img
|
||||
v-if="isLoading"
|
||||
class="add-card-state__button__loading-image"
|
||||
src="@/../static/images/account/billing/loading.gif"
|
||||
alt="loading gif"
|
||||
>
|
||||
<span class="add-card-state__button__label">{{ isLoading ? 'Adding' : 'Add Payment' }}</span>
|
||||
</div>
|
||||
<p class="add-card-state__next-label">Next</p>
|
||||
<VButton
|
||||
label="Create an Access Grant"
|
||||
width="252px"
|
||||
height="48px"
|
||||
:is-disabled="isLoading"
|
||||
:on-press="onCreateGrantClick"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -32,10 +31,16 @@
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import StripeCardInput from '@/components/account/billing/paymentMethods/StripeCardInput.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
import LockImage from '@/../static/images/account/billing/lock.svg';
|
||||
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { ProjectFields } from '@/types/projects';
|
||||
import { PM_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
|
||||
|
||||
const {
|
||||
@ -52,25 +57,67 @@ interface StripeForm {
|
||||
components: {
|
||||
StripeCardInput,
|
||||
LockImage,
|
||||
VButton,
|
||||
},
|
||||
})
|
||||
|
||||
export default class AddCardState extends Vue {
|
||||
public isLoading: boolean = false;
|
||||
private readonly TOGGLE_IS_LOADING: string = 'toggleIsLoading';
|
||||
private readonly SET_CREATE_GRANT_STEP: string = 'setCreateGrantStep';
|
||||
|
||||
public isLoading: boolean = false;
|
||||
public $refs!: {
|
||||
stripeCardInput: StripeCardInput & StripeForm;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides card information to Stripe.
|
||||
* Provides card information to Stripe, creates untitled project and redirects to next step.
|
||||
*/
|
||||
public async onConfirmAddStripe(): Promise<void> {
|
||||
await this.$refs.stripeCardInput.onSubmit();
|
||||
public async onCreateGrantClick(): Promise<void> {
|
||||
if (this.isLoading) return;
|
||||
|
||||
this.$segment.track(SegmentEvent.PAYMENT_METHOD_ADDED, {
|
||||
project_id: this.$store.getters.selectedProject.id,
|
||||
});
|
||||
this.isLoading = true;
|
||||
|
||||
this.$emit(this.TOGGLE_IS_LOADING);
|
||||
|
||||
try {
|
||||
await this.$refs.stripeCardInput.onSubmit();
|
||||
|
||||
const FIRST_PAGE = 1;
|
||||
const UNTITLED_PROJECT_NAME = 'Untitled Project';
|
||||
const UNTITLED_PROJECT_DESCRIPTION = '___';
|
||||
const project = new ProjectFields(
|
||||
UNTITLED_PROJECT_NAME,
|
||||
UNTITLED_PROJECT_DESCRIPTION,
|
||||
this.$store.getters.user.id,
|
||||
);
|
||||
const createdProject = await this.$store.dispatch(PROJECTS_ACTIONS.CREATE, project);
|
||||
const createdProjectId = createdProject.id;
|
||||
|
||||
this.$segment.track(SegmentEvent.PROJECT_CREATED, {
|
||||
project_id: createdProjectId,
|
||||
});
|
||||
this.$segment.track(SegmentEvent.PAYMENT_METHOD_ADDED, {
|
||||
project_id: createdProjectId,
|
||||
});
|
||||
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.SELECT, createdProjectId);
|
||||
await this.$store.dispatch(PM_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(PM_ACTIONS.FETCH, FIRST_PAGE);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PAYMENTS_HISTORY);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_BALANCE);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, createdProjectId);
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.CLEAR);
|
||||
|
||||
this.setDefaultState();
|
||||
|
||||
this.$emit(this.SET_CREATE_GRANT_STEP);
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
this.setDefaultState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,11 +126,6 @@ export default class AddCardState extends Vue {
|
||||
* @param token from Stripe
|
||||
*/
|
||||
public async addCard(token: string) {
|
||||
if (this.isLoading) return;
|
||||
|
||||
this.isLoading = true;
|
||||
this.$emit('toggleIsLoading');
|
||||
|
||||
try {
|
||||
await this.$store.dispatch(ADD_CREDIT_CARD, token);
|
||||
} catch (error) {
|
||||
@ -98,11 +140,8 @@ export default class AddCardState extends Vue {
|
||||
await this.$store.dispatch(GET_CREDIT_CARDS);
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
this.setDefaultState();
|
||||
}
|
||||
|
||||
this.setDefaultState();
|
||||
|
||||
this.$emit('setProjectState');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,7 +149,7 @@ export default class AddCardState extends Vue {
|
||||
*/
|
||||
private setDefaultState(): void {
|
||||
this.isLoading = false;
|
||||
this.$emit('toggleIsLoading');
|
||||
this.$emit(this.TOGGLE_IS_LOADING);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -147,7 +186,6 @@ export default class AddCardState extends Vue {
|
||||
padding: 15px 35px;
|
||||
background-color: #cef0e3;
|
||||
border-radius: 0 0 8px 8px;
|
||||
margin-bottom: 45px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@ -160,34 +198,12 @@ export default class AddCardState extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 156px;
|
||||
height: 48px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
background-color: #2683ff;
|
||||
|
||||
&__loading-image {
|
||||
margin-right: 5px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 23px;
|
||||
color: #fff;
|
||||
word-break: keep-all;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #0059d0;
|
||||
}
|
||||
&__next-label {
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
color: #768394;
|
||||
margin: 35px 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,11 +34,12 @@
|
||||
</div>
|
||||
<div class="add-storj-state__container__blur" v-if="isLoading"/>
|
||||
</div>
|
||||
<p class="add-storj-state__next-label">Next</p>
|
||||
<VButton
|
||||
width="222px"
|
||||
width="252px"
|
||||
height="48px"
|
||||
label="Name Your Project"
|
||||
:on-press="createProject"
|
||||
label="Create an Acess Grant"
|
||||
:on-press="createAccessGrant"
|
||||
:is-disabled="isButtonDisabled"
|
||||
/>
|
||||
</div>
|
||||
@ -52,6 +53,13 @@ import PayingStep from '@/components/onboardingTour/steps/paymentStates/tokenSub
|
||||
import VerifiedStep from '@/components/onboardingTour/steps/paymentStates/tokenSubSteps/VerifiedStep.vue';
|
||||
import VerifyingStep from '@/components/onboardingTour/steps/paymentStates/tokenSubSteps/VerifyingStep.vue';
|
||||
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { ProjectFields } from '@/types/projects';
|
||||
import { PM_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
|
||||
import { AddingStorjState } from '@/utils/constants/onboardingTourEnums';
|
||||
|
||||
@Component({
|
||||
@ -64,6 +72,9 @@ import { AddingStorjState } from '@/utils/constants/onboardingTourEnums';
|
||||
})
|
||||
|
||||
export default class AddStorjState extends Vue {
|
||||
private readonly TOGGLE_IS_LOADING: string = 'toggleIsLoading';
|
||||
private readonly SET_CREATE_GRANT_STEP: string = 'setCreateGrantStep';
|
||||
|
||||
public isLoading: boolean = false;
|
||||
public addingTokenState: number = AddingStorjState.DEFAULT;
|
||||
|
||||
@ -86,6 +97,78 @@ export default class AddStorjState extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create untitled project and starts creating access grant process.
|
||||
*/
|
||||
public async createAccessGrant(): Promise<void> {
|
||||
if (this.isLoading) return;
|
||||
|
||||
this.toggleIsLoading();
|
||||
|
||||
try {
|
||||
const FIRST_PAGE = 1;
|
||||
const UNTITLED_PROJECT_NAME = 'Untitled Project';
|
||||
const UNTITLED_PROJECT_DESCRIPTION = '___';
|
||||
const project = new ProjectFields(
|
||||
UNTITLED_PROJECT_NAME,
|
||||
UNTITLED_PROJECT_DESCRIPTION,
|
||||
this.$store.getters.user.id,
|
||||
);
|
||||
const createdProject = await this.$store.dispatch(PROJECTS_ACTIONS.CREATE, project);
|
||||
const createdProjectId = createdProject.id;
|
||||
|
||||
this.$segment.track(SegmentEvent.PROJECT_CREATED, {
|
||||
project_id: createdProjectId,
|
||||
});
|
||||
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.SELECT, createdProjectId);
|
||||
await this.$store.dispatch(PM_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(PM_ACTIONS.FETCH, FIRST_PAGE);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PAYMENTS_HISTORY);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_BALANCE);
|
||||
await this.$store.dispatch(PAYMENTS_ACTIONS.GET_PROJECT_USAGE_AND_CHARGES_CURRENT_ROLLUP);
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.GET_LIMITS, createdProjectId);
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.CLEAR);
|
||||
|
||||
this.toggleIsLoading();
|
||||
|
||||
this.$emit(this.SET_CREATE_GRANT_STEP);
|
||||
} catch (error) {
|
||||
await this.$notify.error(error.message);
|
||||
this.toggleIsLoading();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets area to default state.
|
||||
*/
|
||||
public setDefaultState(): void {
|
||||
this.addingTokenState = AddingStorjState.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets area to verifying state.
|
||||
*/
|
||||
public setVerifyingState(): void {
|
||||
this.addingTokenState = AddingStorjState.VERIFYING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets area to verified state.
|
||||
*/
|
||||
public setVerifiedState(): void {
|
||||
this.addingTokenState = AddingStorjState.VERIFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles area's loading state.
|
||||
*/
|
||||
public toggleIsLoading(): void {
|
||||
this.isLoading = !this.isLoading;
|
||||
this.$emit(this.TOGGLE_IS_LOADING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if area is in default state.
|
||||
*/
|
||||
@ -113,42 +196,6 @@ export default class AddStorjState extends Vue {
|
||||
public get isButtonDisabled(): boolean {
|
||||
return !this.$store.getters.canUserCreateFirstProject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets area to default state.
|
||||
*/
|
||||
public setDefaultState(): void {
|
||||
this.addingTokenState = AddingStorjState.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets area to verifying state.
|
||||
*/
|
||||
public setVerifyingState(): void {
|
||||
this.addingTokenState = AddingStorjState.VERIFYING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets area to verified state.
|
||||
*/
|
||||
public setVerifiedState(): void {
|
||||
this.addingTokenState = AddingStorjState.VERIFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles area's loading state.
|
||||
*/
|
||||
public toggleIsLoading(): void {
|
||||
this.isLoading = !this.isLoading;
|
||||
this.$emit('toggleIsLoading');
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts creating project process.
|
||||
*/
|
||||
public createProject(): void {
|
||||
this.$emit('setProjectState');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -172,7 +219,6 @@ export default class AddStorjState extends Vue {
|
||||
padding: 20px 45px 45px 45px;
|
||||
background-color: #fff;
|
||||
border-radius: 0 0 8px 8px;
|
||||
margin-bottom: 35px;
|
||||
position: relative;
|
||||
|
||||
&__bonus-info {
|
||||
@ -218,5 +264,13 @@ export default class AddStorjState extends Vue {
|
||||
z-index: 100;
|
||||
}
|
||||
}
|
||||
|
||||
&__next-label {
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
line-height: 26px;
|
||||
color: #768394;
|
||||
margin: 35px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -20,7 +20,7 @@
|
||||
@onChangeTokenValue="onChangeTokenValue"
|
||||
/>
|
||||
<VButton
|
||||
width="100%"
|
||||
width="calc(100% - 4px)"
|
||||
height="48px"
|
||||
label="Continue to Coin Payments"
|
||||
:on-press="onConfirmAddSTORJ"
|
||||
@ -145,7 +145,7 @@ export default class PayingStep extends Vue {
|
||||
}
|
||||
|
||||
&__form {
|
||||
width: 100%;
|
||||
width: calc(100% - 2px);
|
||||
margin-bottom: 20px;
|
||||
|
||||
/deep/ .selected-container,
|
||||
|
@ -5,8 +5,8 @@
|
||||
<VerifyingImage/>
|
||||
<h2 class="verifying-step__title">Verifying Payment</h2>
|
||||
<span class="verifying-step__sub-title">
|
||||
Verification may take up to an hour. In the meantime, see how easy it is to get started visiting documentation
|
||||
page, or check coin payment status.
|
||||
Verification may take up to a few hours. In the meantime, see how easy it is to get started visiting
|
||||
documentation page, or check coin payment status.
|
||||
</span>
|
||||
<div class="verifying-step__buttons-area">
|
||||
<a
|
||||
|
@ -65,7 +65,7 @@ import HeaderedInput from '@/components/common/HeaderedInput.vue';
|
||||
import VButton from '@/components/common/VButton.vue';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { API_KEYS_ACTIONS } from '@/store/modules/apiKeys';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
@ -200,7 +200,7 @@ export default class NewProjectPopup extends Vue {
|
||||
* Clears api keys store.
|
||||
*/
|
||||
private clearApiKeys(): void {
|
||||
this.$store.dispatch(API_KEYS_ACTIONS.CLEAR);
|
||||
this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CLEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,7 +58,7 @@ import CloseCrossIcon from '@/../static/images/common/closeCross.svg';
|
||||
import DeleteProjectIcon from '@/../static/images/project/deleteProject.svg';
|
||||
import ErrorIcon from '@/../static/images/register/ErrorInfo.svg';
|
||||
|
||||
import { API_KEYS_ACTIONS } from '@/store/modules/apiKeys';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import {
|
||||
@ -146,7 +146,7 @@ export default class DeleteProjectPopup extends Vue {
|
||||
private async selectProject(): Promise<void> {
|
||||
if (this.$store.state.projectsModule.projects.length === 0) {
|
||||
await this.$store.dispatch(PM_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(API_KEYS_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.CLEAR);
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.CLEAR);
|
||||
|
||||
return;
|
||||
@ -155,7 +155,7 @@ export default class DeleteProjectPopup extends Vue {
|
||||
// TODO: reuse select project functionality
|
||||
await this.$store.dispatch(PROJECTS_ACTIONS.SELECT, this.$store.state.projectsModule.projects[0].id);
|
||||
await this.$store.dispatch(PM_ACTIONS.FETCH, 1);
|
||||
await this.$store.dispatch(API_KEYS_ACTIONS.FETCH, 1);
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.FETCH, 1);
|
||||
await this.$store.dispatch(BUCKET_ACTIONS.FETCH, 1);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,14 @@
|
||||
|
||||
<template>
|
||||
<div class="dashboard-area">
|
||||
<h1 class="dashboard-area__title">{{projectName}} Dashboard</h1>
|
||||
<div class="dashboard-area__header-wrapper">
|
||||
<h1 class="dashboard-area__title">{{projectName}} Dashboard</h1>
|
||||
<VInfo
|
||||
class="dashboard-area__tooltip__wrapper"
|
||||
bold-text="Expect a delay of a few hours between network activity and the latest dashboard stats.">
|
||||
<InfoIcon class="dashboard-area__tooltip__icon"/>
|
||||
</VInfo>
|
||||
</div>
|
||||
<ProjectUsage/>
|
||||
<ProjectSummary/>
|
||||
<BucketArea/>
|
||||
@ -13,10 +20,13 @@
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
|
||||
import VInfo from '@/components/common/VInfo.vue';
|
||||
import BucketArea from '@/components/project/buckets/BucketArea.vue';
|
||||
import ProjectSummary from '@/components/project/summary/ProjectSummary.vue';
|
||||
import ProjectUsage from '@/components/project/usage/ProjectUsage.vue';
|
||||
|
||||
import InfoIcon from '@/../static/images/common/infoTooltipSm.svg';
|
||||
|
||||
import { RouteConfig } from '@/router';
|
||||
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { SegmentEvent } from '@/utils/constants/analyticsEventNames';
|
||||
@ -25,8 +35,10 @@ import { MetaUtils } from '@/utils/meta';
|
||||
@Component({
|
||||
components: {
|
||||
BucketArea,
|
||||
InfoIcon,
|
||||
ProjectUsage,
|
||||
ProjectSummary,
|
||||
VInfo,
|
||||
},
|
||||
})
|
||||
export default class ProjectDashboard extends Vue {
|
||||
@ -36,7 +48,7 @@ export default class ProjectDashboard extends Vue {
|
||||
*/
|
||||
public mounted(): void {
|
||||
if (!this.$store.getters.selectedProject.id) {
|
||||
this.$router.push(RouteConfig.OnboardingTour.path);
|
||||
this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.OverviewStep).path);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -79,5 +91,34 @@ export default class ProjectDashboard extends Vue {
|
||||
color: #384b65;
|
||||
margin: 0 0 30px 0;
|
||||
}
|
||||
|
||||
&__header-wrapper {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&__tooltip {
|
||||
|
||||
&__wrapper {
|
||||
margin: 7px 0 0 10px;
|
||||
|
||||
/deep/ .info__message-box {
|
||||
background-image: url('../../../static/images/tooltipMessageBg.png');
|
||||
min-width: 300px;
|
||||
text-align: left;
|
||||
left: 195px;
|
||||
bottom: 15px;
|
||||
padding: 10px 10px 10px 35px;
|
||||
|
||||
&__text {
|
||||
|
||||
&__bold-text {
|
||||
font-family: 'font_medium', sans-serif;
|
||||
color: #354049;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -18,8 +18,8 @@
|
||||
background-color="#f5f6fa"
|
||||
title-color="#1b2533"
|
||||
value-color="#000"
|
||||
title="API Keys"
|
||||
:value="apiKeysAmount"
|
||||
title="Access Grants"
|
||||
:value="accessGrantsAmount"
|
||||
/>
|
||||
<SummaryItem
|
||||
class="right-indent"
|
||||
@ -80,10 +80,10 @@ export default class ProjectSummary extends Vue {
|
||||
}
|
||||
|
||||
/**
|
||||
* apiKeysAmount returns API keys amount for selected project.
|
||||
* accessGrantsAmount returns access grants' amount for selected project.
|
||||
*/
|
||||
public get apiKeysAmount(): number {
|
||||
return this.$store.state.apiKeysModule.page.totalCount;
|
||||
public get accessGrantsAmount(): number {
|
||||
return this.$store.state.accessGrantsModule.page.totalCount;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,9 +18,11 @@ import AccountBilling from '@/components/account/billing/BillingArea.vue';
|
||||
import DetailedHistory from '@/components/account/billing/depositAndBillingHistory/DetailedHistory.vue';
|
||||
import CreditsHistory from '@/components/account/billing/freeCredits/CreditsHistory.vue';
|
||||
import SettingsArea from '@/components/account/SettingsArea.vue';
|
||||
import ApiKeysArea from '@/components/apiKeys/ApiKeysArea.vue';
|
||||
import Page404 from '@/components/errors/Page404.vue';
|
||||
import OnboardingTourArea from '@/components/onboardingTour/OnboardingTourArea.vue';
|
||||
import AddPaymentStep from '@/components/onboardingTour/steps/AddPaymentStep.vue';
|
||||
import CreateAccessGrantStep from '@/components/onboardingTour/steps/CreateAccessGrantStep.vue';
|
||||
import OverviewStep from '@/components/onboardingTour/steps/OverviewStep.vue';
|
||||
import CreateProject from '@/components/project/CreateProject.vue';
|
||||
import EditProjectDetails from '@/components/project/EditProjectDetails.vue';
|
||||
import ProjectDashboard from '@/components/project/ProjectDashboard.vue';
|
||||
@ -47,18 +49,19 @@ export abstract class RouteConfig {
|
||||
public static Account = new NavigationLink('/account', 'Account');
|
||||
public static ProjectDashboard = new NavigationLink('/project-dashboard', 'Dashboard');
|
||||
public static Users = new NavigationLink('/project-members', 'Users');
|
||||
public static ApiKeys = new NavigationLink('/api-keys', 'API Keys');
|
||||
public static OnboardingTour = new NavigationLink('/onboarding-tour', 'Onboarding Tour');
|
||||
public static CreateProject = new NavigationLink('/create-project', 'Create Project');
|
||||
public static EditProjectDetails = new NavigationLink('/edit-project-details', 'Edit Project Details');
|
||||
public static AccessGrants = new NavigationLink('/access-grants', 'Access Grants');
|
||||
|
||||
// child paths
|
||||
// account child paths
|
||||
public static Settings = new NavigationLink('settings', 'Settings');
|
||||
public static Billing = new NavigationLink('billing', 'Billing');
|
||||
public static BillingHistory = new NavigationLink('billing-history', 'Billing History');
|
||||
public static DepositHistory = new NavigationLink('deposit-history', 'Deposit History');
|
||||
public static CreditsHistory = new NavigationLink('credits-history', 'Credits History');
|
||||
|
||||
// access grant child paths
|
||||
public static CreateAccessGrant = new NavigationLink('create-grant', 'Create Access Grant');
|
||||
public static NameStep = new NavigationLink('name', 'Name Access Grant');
|
||||
public static PermissionsStep = new NavigationLink('permissions', 'Access Grant Permissions');
|
||||
@ -68,6 +71,15 @@ export abstract class RouteConfig {
|
||||
public static CLIStep = new NavigationLink('cli', 'Access Grant In CLI');
|
||||
public static UploadStep = new NavigationLink('upload', 'Access Grant Upload Data');
|
||||
|
||||
// onboarding tour child paths
|
||||
public static OverviewStep = new NavigationLink('overview', 'Onboarding Overview');
|
||||
public static PaymentStep = new NavigationLink('payment', 'Onboarding Payment');
|
||||
public static AccessGrant = new NavigationLink('access', 'Onboarding Access Grant');
|
||||
public static AccessGrantName = new NavigationLink('name', 'Onboarding Name Access Grant');
|
||||
public static AccessGrantPermissions = new NavigationLink('permissions', 'Onboarding Access Grant Permissions');
|
||||
public static AccessGrantPassphrase = new NavigationLink('create-passphrase', 'Onboarding Access Grant Create Passphrase');
|
||||
public static AccessGrantResult = new NavigationLink('result', 'Onboarding Access Grant Result');
|
||||
|
||||
// TODO: disabled until implementation
|
||||
// public static Referral = new NavigationLink('referral', 'Referral');
|
||||
|
||||
@ -165,15 +177,50 @@ export const router = new Router({
|
||||
name: RouteConfig.Users.name,
|
||||
component: ProjectMembersArea,
|
||||
},
|
||||
{
|
||||
path: RouteConfig.ApiKeys.path,
|
||||
name: RouteConfig.ApiKeys.name,
|
||||
component: ApiKeysArea,
|
||||
},
|
||||
{
|
||||
path: RouteConfig.OnboardingTour.path,
|
||||
name: RouteConfig.OnboardingTour.name,
|
||||
component: OnboardingTourArea,
|
||||
children: [
|
||||
{
|
||||
path: RouteConfig.OverviewStep.path,
|
||||
name: RouteConfig.OverviewStep.name,
|
||||
component: OverviewStep,
|
||||
},
|
||||
{
|
||||
path: RouteConfig.PaymentStep.path,
|
||||
name: RouteConfig.PaymentStep.name,
|
||||
component: AddPaymentStep,
|
||||
},
|
||||
{
|
||||
path: RouteConfig.AccessGrant.path,
|
||||
name: RouteConfig.AccessGrant.name,
|
||||
component: CreateAccessGrantStep,
|
||||
children: [
|
||||
{
|
||||
path: RouteConfig.AccessGrantName.path,
|
||||
name: RouteConfig.AccessGrantName.name,
|
||||
component: NameStep,
|
||||
},
|
||||
{
|
||||
path: RouteConfig.AccessGrantPermissions.path,
|
||||
name: RouteConfig.AccessGrantPermissions.name,
|
||||
component: PermissionsStep,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
path: RouteConfig.AccessGrantPassphrase.path,
|
||||
name: RouteConfig.AccessGrantPassphrase.name,
|
||||
component: CreatePassphraseStep,
|
||||
},
|
||||
{
|
||||
path: RouteConfig.AccessGrantResult.path,
|
||||
name: RouteConfig.AccessGrantResult.name,
|
||||
component: ResultStep,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: RouteConfig.CreateProject.path,
|
||||
@ -258,6 +305,18 @@ router.beforeEach((to, from, next) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (navigateToDefaultSubTab(to.matched, RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant))) {
|
||||
next(RouteConfig.OnboardingTour.with(RouteConfig.AccessGrant).with(RouteConfig.NameStep).path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (navigateToDefaultSubTab(to.matched, RouteConfig.OnboardingTour)) {
|
||||
next(RouteConfig.OnboardingTour.with(RouteConfig.OverviewStep).path);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (to.name === 'default') {
|
||||
next(RouteConfig.ProjectDashboard.path);
|
||||
|
||||
|
@ -1,14 +1,6 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
export enum TourState {
|
||||
DEFAULT = 1,
|
||||
ADDING_PAYMENT,
|
||||
PROJECT,
|
||||
API_KEY,
|
||||
UPLOAD,
|
||||
}
|
||||
|
||||
export enum AddingPaymentState {
|
||||
ADD_CARD = 1,
|
||||
ADD_STORJ,
|
||||
@ -19,8 +11,3 @@ export enum AddingStorjState {
|
||||
VERIFYING,
|
||||
VERIFIED,
|
||||
}
|
||||
|
||||
export enum AddingApiKeyState {
|
||||
CREATE = 1,
|
||||
COPY,
|
||||
}
|
||||
|
@ -52,12 +52,10 @@ import NoPaywallInfoBar from '@/components/noPaywallInfoBar/NoPaywallInfoBar.vue
|
||||
import { ErrorUnauthorized } from '@/api/errors/ErrorUnauthorized';
|
||||
import { RouteConfig } from '@/router';
|
||||
import { ACCESS_GRANTS_ACTIONS } from '@/store/modules/accessGrants';
|
||||
import { API_KEYS_ACTIONS } from '@/store/modules/apiKeys';
|
||||
import { BUCKET_ACTIONS } from '@/store/modules/buckets';
|
||||
import { PAYMENTS_ACTIONS } from '@/store/modules/payments';
|
||||
import { PROJECTS_ACTIONS } from '@/store/modules/projects';
|
||||
import { USER_ACTIONS } from '@/store/modules/users';
|
||||
import { ApiKeysPage } from '@/types/apiKeys';
|
||||
import { Project } from '@/types/projects';
|
||||
import { User } from '@/types/users';
|
||||
import { Size } from '@/utils/bytesSize';
|
||||
@ -166,7 +164,7 @@ export default class DashboardArea extends Vue {
|
||||
await this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.LOADED);
|
||||
|
||||
try {
|
||||
await this.$router.push(RouteConfig.OnboardingTour.path);
|
||||
await this.$router.push(RouteConfig.OnboardingTour.with(RouteConfig.OverviewStep).path);
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
@ -176,30 +174,10 @@ export default class DashboardArea extends Vue {
|
||||
|
||||
this.selectProject(projects);
|
||||
|
||||
let apiKeysPage: ApiKeysPage = new ApiKeysPage();
|
||||
|
||||
try {
|
||||
apiKeysPage = await this.$store.dispatch(API_KEYS_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||
} catch (error) {
|
||||
await this.$notify.error(`Unable to fetch api keys. ${error.message}`);
|
||||
}
|
||||
|
||||
if (projects.length === 1 && projects[0].ownerId === user.id && apiKeysPage.apiKeys.length === 0) {
|
||||
await this.$store.dispatch(APP_STATE_ACTIONS.CHANGE_STATE, AppState.LOADED);
|
||||
|
||||
try {
|
||||
await this.$router.push(RouteConfig.OnboardingTour.path);
|
||||
} catch (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.$store.dispatch(ACCESS_GRANTS_ACTIONS.FETCH, this.FIRST_PAGE);
|
||||
} catch (error) {
|
||||
await this.$notify.error(`Unable to fetch api keys. ${error.message}`);
|
||||
await this.$notify.error(`Unable to fetch access grants. ${error.message}`);
|
||||
}
|
||||
|
||||
try {
|
||||
@ -234,7 +212,7 @@ export default class DashboardArea extends Vue {
|
||||
* Indicates if no paywall info bar is shown.
|
||||
*/
|
||||
public get isNoPaywallInfoBarShown(): boolean {
|
||||
const isOnboardingTour: boolean = this.$route.name === RouteConfig.OnboardingTour.name;
|
||||
const isOnboardingTour: boolean = this.$route.path.includes(RouteConfig.OnboardingTour.path);
|
||||
|
||||
return !this.isPaywallEnabled && !isOnboardingTour &&
|
||||
this.$store.state.paymentsModule.balance.coins === 0 &&
|
||||
|
4
web/satellite/static/images/common/infoTooltipSm.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="15" height="15" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect class="team-header-svg-rect" x="0.5" y="0.5" width="19" height="19" rx="9.5" stroke="#AFB7C1"/>
|
||||
<path class="team-header-svg-path" d="M7 7.25177C7.00959 6.23527 7.28777 5.44177 7.83453 4.87129C8.38129 4.29043 9.1199 4 10.0504 4C10.952 4 11.6667 4.22819 12.1942 4.68458C12.7314 5.14097 13 5.79444 13 6.64498C13 7.03913 12.9376 7.38661 12.8129 7.68741C12.6882 7.98821 12.5396 8.24234 12.3669 8.44979C12.1942 8.65724 11.9592 8.90099 11.6619 9.18105C11.2686 9.54408 10.9712 9.876 10.7698 10.1768C10.5779 10.4672 10.482 10.8303 10.482 11.2659H9.04317C9.04317 10.851 9.10072 10.488 9.21583 10.1768C9.33094 9.86563 9.46523 9.6115 9.61871 9.41443C9.78177 9.20698 10.0024 8.96841 10.2806 8.69873C10.6067 8.37718 10.8465 8.09712 11 7.85856C11.1535 7.61999 11.2302 7.31919 11.2302 6.95615C11.2302 6.55163 11.1103 6.25082 10.8705 6.05375C10.6403 5.8463 10.3141 5.74257 9.89209 5.74257C9.45084 5.74257 9.10552 5.87223 8.85611 6.13154C8.60671 6.38048 8.47242 6.75389 8.45324 7.25177H7ZM9.73381 12.7595C10.0216 12.7595 10.2566 12.8633 10.4388 13.0707C10.6307 13.2782 10.7266 13.5427 10.7266 13.8642C10.7266 14.1961 10.6307 14.471 10.4388 14.6888C10.2566 14.8963 10.0216 15 9.73381 15C9.45564 15 9.22062 14.8911 9.02878 14.6733C8.84652 14.4554 8.7554 14.1858 8.7554 13.8642C8.7554 13.5427 8.84652 13.2782 9.02878 13.0707C9.22062 12.8633 9.45564 12.7595 9.73381 12.7595Z" fill="#354049"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 6.8 KiB |
BIN
web/satellite/static/images/onboardingTour/cli.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.8 KiB |
BIN
web/satellite/static/images/onboardingTour/developer.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
web/satellite/static/images/onboardingTour/filezilla.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
web/satellite/static/images/onboardingTour/gateway.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
@ -1,3 +0,0 @@
|
||||
<svg class="info-svg" width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 -7.86805e-07C4.02944 -1.22135e-06 1.22135e-06 4.02944 7.86805e-07 9C3.52265e-07 13.9706 4.02944 18 9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 -3.52265e-07 9 -7.86805e-07ZM10 13C10 13.5523 9.55229 14 9 14C8.44772 14 8 13.5523 8 13C8 12.4477 8.44772 12 9 12C9.55229 12 10 12.4477 10 13ZM10 9C10 9.55228 9.55228 10 9 10C8.44771 10 8 9.55228 8 9L8 5C8 4.44771 8.44772 4 9 4C9.55229 4 10 4.44772 10 5L10 9Z" fill="white"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 602 B |
@ -1,3 +0,0 @@
|
||||
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 24C1.15877e-06 10.7452 10.7452 -1.15877e-06 24 0C37.2548 2.09815e-06 48 10.7452 48 24C48 37.2548 37.2548 48 24 48C10.7452 48 -2.09815e-06 37.2548 0 24ZM26.6669 24.0003C26.6669 25.473 25.473 26.6669 24.0003 26.6669C22.5275 26.6669 21.3336 25.473 21.3336 24.0003L21.3336 13.3336C21.3336 11.8609 22.5275 10.6669 24.0003 10.6669C25.473 10.6669 26.6669 11.8609 26.6669 13.3336L26.6669 24.0003ZM24.0003 37.3335C25.473 37.3335 26.6669 36.1396 26.6669 34.6668C26.6669 33.194 25.473 32.0001 24.0003 32.0001C22.5275 32.0001 21.3336 33.194 21.3336 34.6668C21.3336 36.1396 22.5275 37.3335 24.0003 37.3335Z" fill="#F4B000"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 771 B |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 540 B |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 1.0 KiB |
BIN
web/satellite/static/images/tooltipMessageBg.png
Normal file
After Width: | Height: | Size: 716 B |
@ -28,7 +28,7 @@ const store = new Vuex.Store({ modules: { projectsModule } });
|
||||
|
||||
const expectedLinks: NavigationLink[] = [
|
||||
RouteConfig.ProjectDashboard,
|
||||
RouteConfig.ApiKeys,
|
||||
RouteConfig.AccessGrants,
|
||||
RouteConfig.Users,
|
||||
];
|
||||
|
||||
@ -37,11 +37,14 @@ describe('NavigationArea', () => {
|
||||
const router = new Router({
|
||||
mode: 'history',
|
||||
routes: [{
|
||||
path: '/',
|
||||
path: '/onboarding-tour',
|
||||
name: RouteConfig.OnboardingTour.name,
|
||||
component: OnboardingTourArea,
|
||||
}],
|
||||
});
|
||||
|
||||
router.push('/onboarding-tour');
|
||||
|
||||
const wrapper = shallowMount(NavigationArea, {
|
||||
store,
|
||||
localVue,
|
||||
@ -67,6 +70,8 @@ describe('NavigationArea', () => {
|
||||
const projects = await store.dispatch('fetchProjects');
|
||||
store.commit(PROJECTS_MUTATIONS.SELECT_PROJECT, projects[0].id);
|
||||
|
||||
router.push('/');
|
||||
|
||||
const wrapper = shallowMount(NavigationArea, {
|
||||
store,
|
||||
localVue,
|
||||
|
@ -11,10 +11,10 @@ exports[`NavigationArea snapshot not changed with project 1`] = `
|
||||
<h1 class="navigation-area__item-container__link__title">Dashboard</h1>
|
||||
</div>
|
||||
</router-link-stub>
|
||||
<router-link-stub to="/api-keys" tag="a" ariacurrentvalue="page" event="click" aria-label="API Keys" class="navigation-area__item-container">
|
||||
<router-link-stub to="/access-grants" tag="a" ariacurrentvalue="page" event="click" aria-label="Access Grants" class="navigation-area__item-container">
|
||||
<div class="navigation-area__item-container__link">
|
||||
<anonymous-stub></anonymous-stub>
|
||||
<h1 class="navigation-area__item-container__link__title">API Keys</h1>
|
||||
<h1 class="navigation-area__item-container__link__title">Access Grants</h1>
|
||||
</div>
|
||||
</router-link-stub>
|
||||
<router-link-stub to="/project-members" tag="a" ariacurrentvalue="page" event="click" aria-label="Users" class="navigation-area__item-container">
|
||||
|
@ -1,76 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import ProgressBar from '@/components/onboardingTour/ProgressBar.vue';
|
||||
|
||||
import { mount } from '@vue/test-utils';
|
||||
|
||||
describe('ProgressBar.vue', () => {
|
||||
it('renders correctly if paywall is enabled', (): void => {
|
||||
const wrapper = mount(ProgressBar, {
|
||||
propsData: {
|
||||
isPaywallEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders correctly if paywall is disabled', (): void => {
|
||||
const wrapper = mount(ProgressBar, {
|
||||
propsData: {
|
||||
isPaywallEnabled: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders correctly if add payment step is completed', (): void => {
|
||||
const wrapper = mount(ProgressBar, {
|
||||
propsData: {
|
||||
isAddPaymentStep: true,
|
||||
isPaywallEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.findAll('.completed-step').length).toBe(1);
|
||||
expect(wrapper.findAll('.completed-font-color').length).toBe(1);
|
||||
});
|
||||
|
||||
it('renders correctly if create project step is completed', (): void => {
|
||||
const wrapper = mount(ProgressBar, {
|
||||
propsData: {
|
||||
isCreateProjectStep: true,
|
||||
isPaywallEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.findAll('.completed-step').length).toBe(3);
|
||||
expect(wrapper.findAll('.completed-font-color').length).toBe(2);
|
||||
});
|
||||
|
||||
it('renders correctly if create api key step is completed', (): void => {
|
||||
const wrapper = mount(ProgressBar, {
|
||||
propsData: {
|
||||
isCreateApiKeyStep: true,
|
||||
isPaywallEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.findAll('.completed-step').length).toBe(5);
|
||||
expect(wrapper.findAll('.completed-font-color').length).toBe(3);
|
||||
});
|
||||
|
||||
it('renders correctly if upload data step is completed', (): void => {
|
||||
const wrapper = mount(ProgressBar, {
|
||||
propsData: {
|
||||
isUploadDataStep: true,
|
||||
isPaywallEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.findAll('.completed-step').length).toBe(7);
|
||||
expect(wrapper.findAll('.completed-font-color').length).toBe(4);
|
||||
});
|
||||
});
|
@ -1,61 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ProgressBar.vue renders correctly if paywall is disabled 1`] = `
|
||||
<div class="progress-bar-container">
|
||||
<div class="progress-bar-container__progress-area">
|
||||
<!---->
|
||||
<!---->
|
||||
<div class="progress-bar-container__progress-area__circle"><svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.61854 0.302314C8.02258 -0.100771 8.67764 -0.100771 9.08163 0.302314C9.48569 0.705397 9.48569 1.35893 9.08163 1.76202L4.20463 6.62768C3.8006 7.03077 3.14555 7.03077 2.74152 6.62768L0.303018 4.19485C-0.101006 3.79177 -0.101006 3.13823 0.303018 2.73515C0.707044 2.33206 1.3621 2.33206 1.76612 2.73515L3.47307 4.43813L7.61854 0.302314Z" fill="white"></path>
|
||||
</svg></div>
|
||||
<div class="progress-bar-container__progress-area__bar"></div>
|
||||
<div class="progress-bar-container__progress-area__circle"><svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.61854 0.302314C8.02258 -0.100771 8.67764 -0.100771 9.08163 0.302314C9.48569 0.705397 9.48569 1.35893 9.08163 1.76202L4.20463 6.62768C3.8006 7.03077 3.14555 7.03077 2.74152 6.62768L0.303018 4.19485C-0.101006 3.79177 -0.101006 3.13823 0.303018 2.73515C0.707044 2.33206 1.3621 2.33206 1.76612 2.73515L3.47307 4.43813L7.61854 0.302314Z" fill="white"></path>
|
||||
</svg></div>
|
||||
<div class="progress-bar-container__progress-area__bar"></div>
|
||||
<div class="progress-bar-container__progress-area__circle"><svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.61854 0.302314C8.02258 -0.100771 8.67764 -0.100771 9.08163 0.302314C9.48569 0.705397 9.48569 1.35893 9.08163 1.76202L4.20463 6.62768C3.8006 7.03077 3.14555 7.03077 2.74152 6.62768L0.303018 4.19485C-0.101006 3.79177 -0.101006 3.13823 0.303018 2.73515C0.707044 2.33206 1.3621 2.33206 1.76612 2.73515L3.47307 4.43813L7.61854 0.302314Z" fill="white"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div class="progress-bar-container__titles-area titles-area-no-paywall">
|
||||
<!----> <span class="progress-bar-container__titles-area__title name-your-project-title title-no-paywall">
|
||||
Name Your Project
|
||||
</span> <span class="progress-bar-container__titles-area__title api-key-title">
|
||||
Create an API Key
|
||||
</span> <span class="progress-bar-container__titles-area__title">
|
||||
Upload Data
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ProgressBar.vue renders correctly if paywall is enabled 1`] = `
|
||||
<div class="progress-bar-container">
|
||||
<div class="progress-bar-container__progress-area">
|
||||
<div class="progress-bar-container__progress-area__circle"><svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.61854 0.302314C8.02258 -0.100771 8.67764 -0.100771 9.08163 0.302314C9.48569 0.705397 9.48569 1.35893 9.08163 1.76202L4.20463 6.62768C3.8006 7.03077 3.14555 7.03077 2.74152 6.62768L0.303018 4.19485C-0.101006 3.79177 -0.101006 3.13823 0.303018 2.73515C0.707044 2.33206 1.3621 2.33206 1.76612 2.73515L3.47307 4.43813L7.61854 0.302314Z" fill="white"></path>
|
||||
</svg></div>
|
||||
<div class="progress-bar-container__progress-area__bar"></div>
|
||||
<div class="progress-bar-container__progress-area__circle"><svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.61854 0.302314C8.02258 -0.100771 8.67764 -0.100771 9.08163 0.302314C9.48569 0.705397 9.48569 1.35893 9.08163 1.76202L4.20463 6.62768C3.8006 7.03077 3.14555 7.03077 2.74152 6.62768L0.303018 4.19485C-0.101006 3.79177 -0.101006 3.13823 0.303018 2.73515C0.707044 2.33206 1.3621 2.33206 1.76612 2.73515L3.47307 4.43813L7.61854 0.302314Z" fill="white"></path>
|
||||
</svg></div>
|
||||
<div class="progress-bar-container__progress-area__bar"></div>
|
||||
<div class="progress-bar-container__progress-area__circle"><svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.61854 0.302314C8.02258 -0.100771 8.67764 -0.100771 9.08163 0.302314C9.48569 0.705397 9.48569 1.35893 9.08163 1.76202L4.20463 6.62768C3.8006 7.03077 3.14555 7.03077 2.74152 6.62768L0.303018 4.19485C-0.101006 3.79177 -0.101006 3.13823 0.303018 2.73515C0.707044 2.33206 1.3621 2.33206 1.76612 2.73515L3.47307 4.43813L7.61854 0.302314Z" fill="white"></path>
|
||||
</svg></div>
|
||||
<div class="progress-bar-container__progress-area__bar"></div>
|
||||
<div class="progress-bar-container__progress-area__circle"><svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.61854 0.302314C8.02258 -0.100771 8.67764 -0.100771 9.08163 0.302314C9.48569 0.705397 9.48569 1.35893 9.08163 1.76202L4.20463 6.62768C3.8006 7.03077 3.14555 7.03077 2.74152 6.62768L0.303018 4.19485C-0.101006 3.79177 -0.101006 3.13823 0.303018 2.73515C0.707044 2.33206 1.3621 2.33206 1.76612 2.73515L3.47307 4.43813L7.61854 0.302314Z" fill="white"></path>
|
||||
</svg></div>
|
||||
</div>
|
||||
<div class="progress-bar-container__titles-area"><span class="progress-bar-container__titles-area__title">
|
||||
Add Payment
|
||||
</span> <span class="progress-bar-container__titles-area__title name-your-project-title">
|
||||
Name Your Project
|
||||
</span> <span class="progress-bar-container__titles-area__title api-key-title">
|
||||
Create an API Key
|
||||
</span> <span class="progress-bar-container__titles-area__title">
|
||||
Upload Data
|
||||
</span></div>
|
||||
</div>
|
||||
`;
|
@ -9,13 +9,7 @@ exports[`OnboardingTourArea.vue renders correctly 1`] = `
|
||||
<closeimage-stub class="tour-area__info-bar__close-img"></closeimage-stub>
|
||||
</div>
|
||||
<div class="tour-area__content">
|
||||
<progressbar-stub ispaywallenabled="true"></progressbar-stub>
|
||||
<overviewstep-stub></overviewstep-stub>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
<router-view-stub name="default"></router-view-stub>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
|
@ -6,6 +6,7 @@ import Vuex from 'vuex';
|
||||
import OnboardingTourArea from '@/components/onboardingTour/OnboardingTourArea.vue';
|
||||
|
||||
import { PaymentsHttpApi } from '@/api/payments';
|
||||
import { router } from '@/router';
|
||||
import { makePaymentsModule } from '@/store/modules/payments';
|
||||
import { makeProjectsModule } from '@/store/modules/projects';
|
||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||
@ -27,6 +28,7 @@ describe('OnboardingTourArea.vue', () => {
|
||||
const wrapper = shallowMount(OnboardingTourArea, {
|
||||
store,
|
||||
localVue,
|
||||
router,
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
@ -7,14 +7,19 @@ import AddPaymentStep from '@/components/onboardingTour/steps/AddPaymentStep.vue
|
||||
|
||||
import { PaymentsHttpApi } from '@/api/payments';
|
||||
import { makePaymentsModule } from '@/store/modules/payments';
|
||||
import { makeProjectsModule } from '@/store/modules/projects';
|
||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||
|
||||
import { ProjectsApiMock } from '../../mock/api/projects';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
const projectsApi = new ProjectsApiMock();
|
||||
const projectsModule = makeProjectsModule(projectsApi);
|
||||
const paymentsApi = new PaymentsHttpApi();
|
||||
const paymentsModule = makePaymentsModule(paymentsApi);
|
||||
|
||||
const store = new Vuex.Store({ modules: { paymentsModule }});
|
||||
const store = new Vuex.Store({ modules: { projectsModule, paymentsModule }});
|
||||
|
||||
describe('AddPaymentStep.vue', () => {
|
||||
it('renders correctly', async (): Promise<void> => {
|
||||
|
@ -1,61 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import sinon from 'sinon';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
import CreateApiKeyStep from '@/components/onboardingTour/steps/CreateApiKeyStep.vue';
|
||||
|
||||
import { makeApiKeysModule } from '@/store/modules/apiKeys';
|
||||
import { appStateModule } from '@/store/modules/appState';
|
||||
import { makeProjectsModule } from '@/store/modules/projects';
|
||||
import { ApiKeysPage } from '@/types/apiKeys';
|
||||
import { Project } from '@/types/projects';
|
||||
import { NotificatorPlugin } from '@/utils/plugins/notificator';
|
||||
import { SegmentioPlugin } from '@/utils/plugins/segment';
|
||||
import { createLocalVue, mount } from '@vue/test-utils';
|
||||
|
||||
import { ApiKeysMock } from '../../mock/api/apiKeys';
|
||||
import { ProjectsApiMock } from '../../mock/api/projects';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
const notificationPlugin = new NotificatorPlugin();
|
||||
const segmentioPlugin = new SegmentioPlugin();
|
||||
const projectsApi = new ProjectsApiMock();
|
||||
const projectsModule = makeProjectsModule(projectsApi);
|
||||
const apiKeysApi = new ApiKeysMock();
|
||||
const apiKeysModule = makeApiKeysModule(apiKeysApi);
|
||||
apiKeysApi.setMockApiKeysPage(new ApiKeysPage());
|
||||
const project = new Project('id', 'projectName', 'projectDescription', 'test', 'testOwnerId', true);
|
||||
projectsApi.setMockProjects([project]);
|
||||
|
||||
localVue.use(Vuex);
|
||||
localVue.use(notificationPlugin);
|
||||
localVue.use(segmentioPlugin);
|
||||
|
||||
const store = new Vuex.Store({ modules: { projectsModule, apiKeysModule, appStateModule }});
|
||||
|
||||
describe('CreateApiKeyStep.vue', () => {
|
||||
it('renders correctly', (): void => {
|
||||
const wrapper = mount(CreateApiKeyStep, {
|
||||
store,
|
||||
localVue,
|
||||
});
|
||||
|
||||
expect(wrapper.findAll('.disabled').length).toBe(1);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('create api key works correctly correctly', async (): Promise<void> => {
|
||||
const wrapper = mount(CreateApiKeyStep, {
|
||||
store,
|
||||
localVue,
|
||||
});
|
||||
|
||||
await wrapper.vm.setApiKeyName('testName');
|
||||
await wrapper.vm.createApiKey();
|
||||
|
||||
expect(wrapper.findAll('.disabled').length).toBe(0);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -1,54 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import sinon from 'sinon';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
import CreateProjectStep from '@/components/onboardingTour/steps/CreateProjectStep.vue';
|
||||
|
||||
import { PaymentsHttpApi } from '@/api/payments';
|
||||
import { makePaymentsModule } from '@/store/modules/payments';
|
||||
import { makeProjectsModule } from '@/store/modules/projects';
|
||||
import { createLocalVue, mount, shallowMount } from '@vue/test-utils';
|
||||
|
||||
import { ProjectsApiMock } from '../../mock/api/projects';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
const paymentsApi = new PaymentsHttpApi();
|
||||
const paymentsModule = makePaymentsModule(paymentsApi);
|
||||
const projectsApi = new ProjectsApiMock();
|
||||
const projectsModule = makeProjectsModule(projectsApi);
|
||||
|
||||
const store = new Vuex.Store({ modules: { paymentsModule, projectsModule }});
|
||||
|
||||
describe('CreateProjectStep.vue', () => {
|
||||
it('renders correctly', (): void => {
|
||||
const wrapper = shallowMount(CreateProjectStep, {
|
||||
store,
|
||||
localVue,
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('click works correctly', async (): Promise<void> => {
|
||||
const clickSpy = sinon.spy();
|
||||
const wrapper = mount(CreateProjectStep, {
|
||||
store,
|
||||
localVue,
|
||||
});
|
||||
|
||||
wrapper.vm.createProjectClick = clickSpy;
|
||||
|
||||
expect(wrapper.findAll('.disabled').length).toBe(1);
|
||||
|
||||
await wrapper.vm.setProjectName('test');
|
||||
|
||||
expect(wrapper.findAll('.disabled').length).toBe(0);
|
||||
|
||||
await wrapper.find('.create-project-button').trigger('click');
|
||||
|
||||
expect(clickSpy.callCount).toBe(1);
|
||||
});
|
||||
});
|
@ -1,18 +1,41 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import Vuex from 'vuex';
|
||||
|
||||
import OverviewStep from '@/components/onboardingTour/steps/OverviewStep.vue';
|
||||
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { PaymentsHttpApi } from '@/api/payments';
|
||||
import { router } from '@/router';
|
||||
import { makePaymentsModule, PAYMENTS_MUTATIONS } from '@/store/modules/payments';
|
||||
import { makeProjectsModule } from '@/store/modules/projects';
|
||||
import { createLocalVue, mount } from '@vue/test-utils';
|
||||
|
||||
describe('OverviewStep.vue', () => {
|
||||
import { ProjectsApiMock } from '../../mock/api/projects';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
const projectsApi = new ProjectsApiMock();
|
||||
const projectsModule = makeProjectsModule(projectsApi);
|
||||
const paymentsApi = new PaymentsHttpApi();
|
||||
const paymentsModule = makePaymentsModule(paymentsApi);
|
||||
|
||||
const store = new Vuex.Store({ modules: { projectsModule, paymentsModule }});
|
||||
|
||||
describe('OverviewStep.vue', (): void => {
|
||||
it('renders correctly', async (): Promise<void> => {
|
||||
const wrapper = mount(OverviewStep);
|
||||
const wrapper = mount(OverviewStep, {
|
||||
localVue,
|
||||
router,
|
||||
store,
|
||||
});
|
||||
|
||||
await store.commit(PAYMENTS_MUTATIONS.SET_PAYWALL_ENABLED_STATUS, true);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
await wrapper.find('.get-started-button').trigger('click');
|
||||
await store.commit(PAYMENTS_MUTATIONS.SET_PAYWALL_ENABLED_STATUS, false);
|
||||
|
||||
expect(wrapper.emitted()).toHaveProperty('setAddPaymentState');
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -1,14 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import SaveApiKeyModal from '@/components/onboardingTour/steps/SaveApiKeyModal.vue';
|
||||
|
||||
import { mount } from '@vue/test-utils';
|
||||
|
||||
describe('SaveApiKeyModal.vue', () => {
|
||||
it('renders correctly', (): void => {
|
||||
const wrapper = mount(SaveApiKeyModal);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -1,18 +0,0 @@
|
||||
// Copyright (C) 2020 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
import UploadDataStep from '@/components/onboardingTour/steps/UploadDataStep.vue';
|
||||
|
||||
import { createLocalVue, mount } from '@vue/test-utils';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
|
||||
describe('UploadDataStep.vue', () => {
|
||||
it('renders correctly', (): void => {
|
||||
const wrapper = mount(UploadDataStep, {
|
||||
localVue,
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
@ -4,8 +4,8 @@ exports[`AddPaymentStep.vue renders correctly 1`] = `
|
||||
<div class="payment-step">
|
||||
<h1 class="payment-step__title">Get Started with 50 GB Free</h1>
|
||||
<p class="payment-step__sub-title">
|
||||
Adding a payment method ensures your project won’t be interrupted after your <b>free</b> credit is used.
|
||||
</p>
|
||||
Experience the decentralized cloud for free! If you find our network isn’t for you, <b class="bold">cancel
|
||||
any time before your credit runs out and you won’t be billed.</b></p>
|
||||
<div class="payment-step__methods-container">
|
||||
<div class="payment-step__methods-container__title-area">
|
||||
<h2 class="payment-step__methods-container__title-area__title">Payment Method</h2>
|
||||
@ -44,8 +44,8 @@ exports[`AddPaymentStep.vue renders correctly 2`] = `
|
||||
<div class="payment-step">
|
||||
<h1 class="payment-step__title">Get Started with 50 GB Free</h1>
|
||||
<p class="payment-step__sub-title">
|
||||
Adding a payment method ensures your project won’t be interrupted after your <b>free</b> credit is used.
|
||||
</p>
|
||||
Experience the decentralized cloud for free! If you find our network isn’t for you, <b class="bold">cancel
|
||||
any time before your credit runs out and you won’t be billed.</b></p>
|
||||
<div class="payment-step__methods-container">
|
||||
<div class="payment-step__methods-container__title-area">
|
||||
<h2 class="payment-step__methods-container__title-area__title">Payment Method</h2>
|
||||
|
@ -1,85 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CreateApiKeyStep.vue create api key works correctly correctly 1`] = `
|
||||
<div class="create-api-key-step">
|
||||
<h1 class="create-api-key-step__title">Create an API Key</h1>
|
||||
<p class="create-api-key-step__sub-title">
|
||||
API keys provide access to the project for creating buckets and uploading objects through the command line
|
||||
interface. This will be your first API key, and you can always create more keys later on.
|
||||
</p>
|
||||
<div class="create-api-key-step__container">
|
||||
<div class="create-api-key-step__container__title-area">
|
||||
<h2 class="create-api-key-step__container__title-area__title">Create API Key</h2>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="input-container full-input">
|
||||
<div class="label-container">
|
||||
<div class="label-container__main">
|
||||
<!---->
|
||||
<h3 class="label-container__main__label">API Key Name</h3>
|
||||
<h3 class="label-container__main__label add-label"></h3>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<!----> <input id="API Key Name" placeholder="Enter API Key Name (i.e. Dan’s Key)" type="text" class="headered-input" style="height: 48px;">
|
||||
</div>
|
||||
<div class="create-api-key-step__container__copy-key-area">
|
||||
<div class="create-api-key-step__container__copy-key-area__header"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" class="info-svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 -7.86805e-07C4.02944 -1.22135e-06 1.22135e-06 4.02944 7.86805e-07 9C3.52265e-07 13.9706 4.02944 18 9 18C13.9706 18 18 13.9706 18 9C18 4.02944 13.9706 -3.52265e-07 9 -7.86805e-07ZM10 13C10 13.5523 9.55229 14 9 14C8.44772 14 8 13.5523 8 13C8 12.4477 8.44772 12 9 12C9.55229 12 10 12.4477 10 13ZM10 9C10 9.55228 9.55228 10 9 10C8.44771 10 8 9.55228 8 9L8 5C8 4.44771 8.44772 4 9 4C9.55229 4 10 4.44772 10 5L10 9Z" fill="white"></path>
|
||||
</svg> <span class="create-api-key-step__container__copy-key-area__header__title">
|
||||
API Keys only appear here once. Copy and paste this key to your preferred method of storing secrets.
|
||||
</span></div>
|
||||
<div class="create-api-key-step__container__copy-key-area__key-container"><span class="create-api-key-step__container__copy-key-area__key-container__key">testKey</span>
|
||||
<div class="create-api-key-step__container__copy-key-area__key-container__copy-button">
|
||||
<div class="container blue-white" style="width: 81px; height: 40px;"><span class="label">Copy</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="create-api-key-step__container__info">
|
||||
We don’t record your API Keys, which are only displayed once when generated. If you loose this
|
||||
key, it cannot be recovered – but you can always create new API Keys when needed.
|
||||
</p>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="done-button container" style="width: 156px; height: 48px;"><span class="label">Done</span></div>
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`CreateApiKeyStep.vue renders correctly 1`] = `
|
||||
<div class="create-api-key-step">
|
||||
<h1 class="create-api-key-step__title">Create an API Key</h1>
|
||||
<p class="create-api-key-step__sub-title">
|
||||
API keys provide access to the project for creating buckets and uploading objects through the command line
|
||||
interface. This will be your first API key, and you can always create more keys later on.
|
||||
</p>
|
||||
<div class="create-api-key-step__container">
|
||||
<div class="create-api-key-step__container__title-area">
|
||||
<h2 class="create-api-key-step__container__title-area__title">Create API Key</h2>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="input-container full-input">
|
||||
<div class="label-container">
|
||||
<div class="label-container__main">
|
||||
<!---->
|
||||
<h3 class="label-container__main__label">API Key Name</h3>
|
||||
<h3 class="label-container__main__label add-label"></h3>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
<!----> <input id="API Key Name" placeholder="Enter API Key Name (i.e. Dan’s Key)" type="text" class="headered-input" style="height: 48px;">
|
||||
</div>
|
||||
<div class="create-api-key-step__container__create-key-area">
|
||||
<div class="generate-button container blue-white" style="width: 100%; height: 40px;"><span class="label">Generate API Key</span></div>
|
||||
</div>
|
||||
<!---->
|
||||
<!---->
|
||||
</div>
|
||||
<div class="done-button container disabled" style="width: 156px; height: 48px;"><span class="label">Done</span></div>
|
||||
<!---->
|
||||
</div>
|
||||
`;
|
@ -1,21 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CreateProjectStep.vue renders correctly 1`] = `
|
||||
<div class="new-project-step">
|
||||
<h1 class="new-project-step__title">Name Your Project</h1>
|
||||
<p class="new-project-step__sub-title">
|
||||
Projects are where buckets are created for storing data. Within a Project, usage is tracked at the bucket
|
||||
level and aggregated for billing.
|
||||
</p>
|
||||
<div class="new-project-step__container">
|
||||
<div class="new-project-step__container__title-area">
|
||||
<h2 class="new-project-step__container__title-area__title">Project Details</h2>
|
||||
<!---->
|
||||
</div>
|
||||
<headeredinput-stub label="Project Name" placeholder="Enter Project Name" height="48px" width="100%" error="" maxsymbols="20" initvalue="" additionallabel="Up To 20 Characters" currentlimit="0" islimitshown="true" class="full-input project-name-input"></headeredinput-stub>
|
||||
<headeredinput-stub label="Description" placeholder="Enter Project Description" height="60px" width="calc(100% - 42px)" error="" maxsymbols="100" initvalue="" additionallabel="Optional" currentlimit="0" islimitshown="true" ismultiline="true" class="full-input"></headeredinput-stub>
|
||||
<!---->
|
||||
</div>
|
||||
<vbutton-stub label="Create Project" width="156px" height="48px" isdisabled="true" onpress="function () { [native code] }" class="create-project-button"></vbutton-stub>
|
||||
</div>
|
||||
`;
|
@ -2,45 +2,52 @@
|
||||
|
||||
exports[`OverviewStep.vue renders correctly 1`] = `
|
||||
<div class="overview-area">
|
||||
<h1 class="overview-area__title">Welcome to Storj</h1>
|
||||
<h1 class="overview-area__title">
|
||||
Welcome to Storj.
|
||||
<br>
|
||||
Let’s Get Started.
|
||||
</h1>
|
||||
<p class="overview-area__sub-title">
|
||||
You’re just a few steps away from uploading your first object to the 100% secure, decentralized cloud. After
|
||||
adding payment, you’ll create a project, API key, get set up with Storj, and start uploading objects.
|
||||
Follow the docs to start storing data using method below.
|
||||
</p>
|
||||
<div class="overview-area__steps-area">
|
||||
<div class="overview-area__steps-area__step"><svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg" class="overview-area__steps-area__step__icon">
|
||||
<circle cx="15" cy="15" r="15" fill="#519CFF"></circle>
|
||||
<path d="M17.0916 9.36364H14.7791L11.8984 11.1875V13.3693L14.5632 11.6989H14.6314V21H17.0916V9.36364Z" fill="white"></path>
|
||||
</svg> <img src="@/../static/images/onboardingTour/card.png" alt="card image" class="overview-step-image">
|
||||
<h2 class="overview-area__steps-area__step__title">Add Payment</h2> <span class="overview-area__steps-area__step__subtitle">
|
||||
Get 50 GB free to try Storj. Cancel anytime.
|
||||
</span>
|
||||
</div>
|
||||
<div class="overview-area__steps-area__step second-step"><svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg" class="overview-area__steps-area__step__icon">
|
||||
<circle cx="15" cy="15" r="15" fill="#519CFF"></circle>
|
||||
<path d="M11.4041 21H19.6996V18.9886H14.8132V18.9091L16.5121 17.2443C18.9041 15.0625 19.5462 13.9716 19.5462 12.6477C19.5462 10.6307 17.8984 9.20455 15.4041 9.20455C12.9609 9.20455 11.2848 10.6648 11.2905 12.9489H13.6257C13.62 11.8352 14.3246 11.1534 15.3871 11.1534C16.4098 11.1534 17.1712 11.7898 17.1712 12.8125C17.1712 13.7386 16.603 14.375 15.5462 15.392L11.4041 19.2273V21Z" fill="white"></path>
|
||||
</svg> <img src="@/../static/images/onboardingTour/project.jpg" alt="project image" class="overview-step-image">
|
||||
<h2 class="overview-area__steps-area__step__title">Name Your Project</h2> <span class="overview-area__steps-area__step__subtitle">
|
||||
Projects are where buckets are created for storing data.
|
||||
</span>
|
||||
</div>
|
||||
<div class="overview-area__steps-area__step third-step"><svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg" class="overview-area__steps-area__step__icon">
|
||||
<circle cx="15" cy="15" r="15" fill="#519CFF"></circle>
|
||||
<path d="M15.4709 21.1591C18.0845 21.1591 19.9538 19.7216 19.9482 17.733C19.9538 16.2841 19.0334 15.25 17.3232 15.0341V14.9432C18.6243 14.7102 19.522 13.7898 19.5163 12.483C19.522 10.6477 17.9141 9.20455 15.505 9.20455C13.1186 9.20455 11.3232 10.6023 11.2891 12.6136H13.647C13.6754 11.7273 14.4879 11.1534 15.4936 11.1534C16.4879 11.1534 17.1527 11.7557 17.147 12.6307C17.1527 13.5455 16.3743 14.1648 15.255 14.1648H14.1697V15.9716H15.255C16.5732 15.9716 17.397 16.6307 17.3913 17.5682C17.397 18.4943 16.6016 19.1307 15.4766 19.1307C14.3913 19.1307 13.5788 18.5625 13.5334 17.7102H11.0561C11.0959 19.7443 12.9141 21.1591 15.4709 21.1591Z" fill="white"></path>
|
||||
</svg> <img src="@/../static/images/onboardingTour/api-key.jpg" alt="api keys image" class="overview-step-image">
|
||||
<h2 class="overview-area__steps-area__step__title">Create an API Key</h2> <span class="overview-area__steps-area__step__subtitle">
|
||||
Generate access to your project to upload data.
|
||||
</span>
|
||||
</div>
|
||||
<div class="overview-area__steps-area__step"><svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg" class="overview-area__steps-area__step__icon">
|
||||
<circle cx="15" cy="15" r="15" fill="#2582FF"></circle>
|
||||
<path d="M10.8452 18.9545H16.4304V21H18.7827V18.9545H20.2259V16.983H18.7827V9.36364H15.7031L10.8452 17.017V18.9545ZM16.4759 16.983H13.3224V16.892L16.3849 12.0455H16.4759V16.983Z" fill="white"></path>
|
||||
</svg> <img src="@/../static/images/onboardingTour/uplink.jpg" alt="uplink image" class="overview-step-image">
|
||||
<h2 class="overview-area__steps-area__step__title">Upload Data</h2> <span class="overview-area__steps-area__step__subtitle">
|
||||
Store your data on the secure, decentralized cloud.
|
||||
</span>
|
||||
<div class="overview-area__steps-area__step"><img src="@/../static/images/onboardingTour/cli.png" alt="cli image" class="overview-area__steps-area__step__image">
|
||||
<h2 class="overview-area__steps-area__step__title">CLI Tool</h2>
|
||||
<p class="overview-area__steps-area__step__info">
|
||||
Quickly upload data directly through the command line interface.
|
||||
</p> <a href="https://documentation.storj.io/setup/cli" target="_blank" class="overview-area__steps-area__step__link">
|
||||
CLI Docs >
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="get-started-button container" style="width: 251px; height: 56px;"><span class="label">Get Started</span></div>
|
||||
<div class="overview-area__divider"></div>
|
||||
<p class="overview-area__next-label">Next</p>
|
||||
<div class="overview-area__cta container" style="width: 252px; height: 48px;"><span class="label">Add a Payment Method</span></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`OverviewStep.vue renders correctly 2`] = `
|
||||
<div class="overview-area">
|
||||
<h1 class="overview-area__title">
|
||||
Welcome to Storj.
|
||||
<br>
|
||||
Let’s Get Started.
|
||||
</h1>
|
||||
<p class="overview-area__sub-title">
|
||||
Follow the docs to start storing data using method below.
|
||||
</p>
|
||||
<div class="overview-area__steps-area">
|
||||
<div class="overview-area__steps-area__step"><img src="@/../static/images/onboardingTour/cli.png" alt="cli image" class="overview-area__steps-area__step__image">
|
||||
<h2 class="overview-area__steps-area__step__title">CLI Tool</h2>
|
||||
<p class="overview-area__steps-area__step__info">
|
||||
Quickly upload data directly through the command line interface.
|
||||
</p> <a href="https://documentation.storj.io/setup/cli" target="_blank" class="overview-area__steps-area__step__link">
|
||||
CLI Docs >
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-area__divider"></div>
|
||||
<p class="overview-area__next-label">Next</p>
|
||||
<div class="overview-area__cta container" style="width: 252px; height: 48px;"><span class="label">Create an Access Grant</span></div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -1,19 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SaveApiKeyModal.vue renders correctly 1`] = `
|
||||
<div class="save-api-modal">
|
||||
<div class="save-api-modal__container"><svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 24C1.15877e-06 10.7452 10.7452 -1.15877e-06 24 0C37.2548 2.09815e-06 48 10.7452 48 24C48 37.2548 37.2548 48 24 48C10.7452 48 -2.09815e-06 37.2548 0 24ZM26.6669 24.0003C26.6669 25.473 25.473 26.6669 24.0003 26.6669C22.5275 26.6669 21.3336 25.473 21.3336 24.0003L21.3336 13.3336C21.3336 11.8609 22.5275 10.6669 24.0003 10.6669C25.473 10.6669 26.6669 11.8609 26.6669 13.3336L26.6669 24.0003ZM24.0003 37.3335C25.473 37.3335 26.6669 36.1396 26.6669 34.6668C26.6669 33.194 25.473 32.0001 24.0003 32.0001C22.5275 32.0001 21.3336 33.194 21.3336 34.6668C21.3336 36.1396 22.5275 37.3335 24.0003 37.3335Z" fill="#F4B000"></path>
|
||||
</svg>
|
||||
<h1 class="save-api-modal__container__title">Is Your API Key Saved?</h1>
|
||||
<p class="save-api-modal__container__message">
|
||||
API Keys are only displayed once when generated. If you haven’t saved your key, go back to copy and
|
||||
paste the API key to your preferred method of storing secrets (i.e. TextEdit, Keybase, etc.)
|
||||
</p>
|
||||
<div class="save-api-modal__container__buttons-area">
|
||||
<div class="back-button container blue-white" style="width: 186px; height: 45px;"><span class="label">Go Back</span></div>
|
||||
<div class="container" style="width: 186px; height: 45px;"><span class="label">Yes, it's Saved!</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -1,59 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`UploadDataStep.vue renders correctly 1`] = `
|
||||
<div class="upload-data-area">
|
||||
<div class="upload-data-area__container">
|
||||
<h1 class="upload-data-area__container__title">Upload Data</h1>
|
||||
<p class="upload-data-area__container__sub-title">
|
||||
From here, you’ll set up Tardigrade to store data for your project using our S3 Gateway, Uplink CLI, or
|
||||
select from our growing library of connectors to build apps on Tardigrade.
|
||||
</p>
|
||||
<div class="upload-data-area__container__docs-area">
|
||||
<div class="upload-data-area__container__docs-area__option">
|
||||
<h2 class="upload-data-area__container__docs-area__option__title">
|
||||
Migrate Data from your Existing AWS buckets
|
||||
</h2> <img src="@/../static/images/onboardingTour/s3.png" alt="s3 gateway image">
|
||||
<h3 class="upload-data-area__container__docs-area__option__sub-title">
|
||||
S3 Gateway
|
||||
</h3>
|
||||
<p class="upload-data-area__container__docs-area__option__info">
|
||||
Make the switch with Tardigrade’s S3 Gateway.
|
||||
</p> <a href="https://documentation.tardigrade.io/api-reference/s3-gateway" target="_blank" rel="noopener noreferrer" class="upload-data-area__container__docs-area__option__link">
|
||||
S3 Gateway Docs
|
||||
</a>
|
||||
</div>
|
||||
<div class="upload-data-area__container__docs-area__option uplink-option">
|
||||
<h2 class="upload-data-area__container__docs-area__option__title">
|
||||
Upload Data from Your Local Environment
|
||||
</h2> <img src="@/../static/images/onboardingTour/uplinkcli.png" alt="uplink cli image">
|
||||
<h3 class="upload-data-area__container__docs-area__option__sub-title">
|
||||
Uplink CLI
|
||||
</h3>
|
||||
<p class="upload-data-area__container__docs-area__option__info">
|
||||
Start uploading data from the command line.
|
||||
</p> <a href="https://documentation.tardigrade.io/getting-started/uploading-your-first-object/set-up-uplink-cli" target="_blank" rel="noopener noreferrer" class="upload-data-area__container__docs-area__option__link">
|
||||
Uplink CLI Docs
|
||||
</a>
|
||||
</div>
|
||||
<div class="upload-data-area__container__docs-area__option">
|
||||
<h2 class="upload-data-area__container__docs-area__option__title">
|
||||
Use Tardigrade for your app’s storage layer
|
||||
</h2> <img src="@/../static/images/onboardingTour/connectors.png" alt="connectors image">
|
||||
<h3 class="upload-data-area__container__docs-area__option__sub-title">
|
||||
App Connectors
|
||||
</h3>
|
||||
<p class="upload-data-area__container__docs-area__option__info">
|
||||
Integrate Tardigrade into your existing stack.
|
||||
</p> <a href="https://tardigrade.io/connectors/" target="_blank" rel="noopener noreferrer" class="upload-data-area__container__docs-area__option__link">
|
||||
App Connectors
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="go-to-button container" style="width: 276px; height: 40px;"><span class="label">Go to Dashboard</span></div> <span class="upload-data-area__support-info">
|
||||
Need help?
|
||||
<a href="https://support.tardigrade.io/hc/en-us" target="_blank" rel="noopener noreferrer" class="upload-data-area__support-info__link">
|
||||
Contact support
|
||||
</a></span>
|
||||
</div>
|
||||
`;
|
@ -11,8 +11,7 @@ exports[`AddCardState.vue renders correctly 1`] = `
|
||||
Your card is secured by 128-bit SSL and AES-256 encryption. Your information is secure.
|
||||
</span>
|
||||
</div>
|
||||
<div class="add-card-state__button">
|
||||
<!----> <span class="add-card-state__button__label">Add Payment</span>
|
||||
</div>
|
||||
<p class="add-card-state__next-label">Next</p>
|
||||
<vbutton-stub label="Create an Access Grant" width="252px" height="48px" onpress="function () { [native code] }"></vbutton-stub>
|
||||
</div>
|
||||
`;
|
||||
|
@ -20,7 +20,8 @@ exports[`AddStorjState.vue renders correctly 1`] = `
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<vbutton-stub label="Name Your Project" width="222px" height="48px" isdisabled="true" onpress="function () { [native code] }"></vbutton-stub>
|
||||
<p class="add-storj-state__next-label">Next</p>
|
||||
<vbutton-stub label="Create an Acess Grant" width="252px" height="48px" isdisabled="true" onpress="function () { [native code] }"></vbutton-stub>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -44,7 +45,8 @@ exports[`AddStorjState.vue renders correctly with completed transaction 1`] = `
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<vbutton-stub label="Name Your Project" width="222px" height="48px" onpress="function () { [native code] }"></vbutton-stub>
|
||||
<p class="add-storj-state__next-label">Next</p>
|
||||
<vbutton-stub label="Create an Acess Grant" width="252px" height="48px" onpress="function () { [native code] }"></vbutton-stub>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -68,6 +70,7 @@ exports[`AddStorjState.vue renders correctly with pending transaction 1`] = `
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<vbutton-stub label="Name Your Project" width="222px" height="48px" isdisabled="true" onpress="function () { [native code] }"></vbutton-stub>
|
||||
<p class="add-storj-state__next-label">Next</p>
|
||||
<vbutton-stub label="Create an Acess Grant" width="252px" height="48px" isdisabled="true" onpress="function () { [native code] }"></vbutton-stub>
|
||||
</div>
|
||||
`;
|
||||
|
@ -9,6 +9,6 @@ exports[`PayingStep.vue renders correctly 1`] = `
|
||||
<!---->
|
||||
</div>
|
||||
<tokendepositselection-stub class="paying-step__form"></tokendepositselection-stub>
|
||||
<vbutton-stub label="Continue to Coin Payments" width="100%" height="48px" isbluewhite="true" onpress="function () { [native code] }"></vbutton-stub>
|
||||
<vbutton-stub label="Continue to Coin Payments" width="calc(100% - 4px)" height="48px" isbluewhite="true" onpress="function () { [native code] }"></vbutton-stub>
|
||||
</div>
|
||||
`;
|
||||
|
@ -4,8 +4,8 @@ exports[`VerifyingStep.vue renders correctly 1`] = `
|
||||
<div class="verifying-step">
|
||||
<verifyingimage-stub></verifyingimage-stub>
|
||||
<h2 class="verifying-step__title">Verifying Payment</h2> <span class="verifying-step__sub-title">
|
||||
Verification may take up to an hour. In the meantime, see how easy it is to get started visiting documentation
|
||||
page, or check coin payment status.
|
||||
Verification may take up to a few hours. In the meantime, see how easy it is to get started visiting
|
||||
documentation page, or check coin payment status.
|
||||
</span>
|
||||
<div class="verifying-step__buttons-area"><a href="https://documentation.storj.io" target="_blank" rel="noopener noreferrer" class="verifying-step__buttons-area__how-to-button">
|
||||
Documentation
|
||||
|
@ -2,7 +2,12 @@
|
||||
|
||||
exports[`ProjectDashboard.vue renders correctly 1`] = `
|
||||
<div class="dashboard-area">
|
||||
<h1 class="dashboard-area__title">test Dashboard</h1>
|
||||
<div class="dashboard-area__header-wrapper">
|
||||
<h1 class="dashboard-area__title">test Dashboard</h1>
|
||||
<vinfo-stub text="" boldtext="Expect a delay of a few hours between network activity and the latest dashboard stats." class="dashboard-area__tooltip__wrapper">
|
||||
<infoicon-stub class="dashboard-area__tooltip__icon"></infoicon-stub>
|
||||
</vinfo-stub>
|
||||
</div>
|
||||
<projectusage-stub></projectusage-stub>
|
||||
<projectsummary-stub></projectsummary-stub>
|
||||
<bucketarea-stub></bucketarea-stub>
|
||||
|
@ -5,7 +5,7 @@ import Vuex from 'vuex';
|
||||
|
||||
import ProjectSummary from '@/components/project/summary/ProjectSummary.vue';
|
||||
|
||||
import { makeApiKeysModule } from '@/store/modules/apiKeys';
|
||||
import { makeAccessGrantsModule } from '@/store/modules/accessGrants';
|
||||
import { makeBucketsModule } from '@/store/modules/buckets';
|
||||
import { makePaymentsModule } from '@/store/modules/payments';
|
||||
import { makeProjectMembersModule } from '@/store/modules/projectMembers';
|
||||
@ -13,7 +13,7 @@ import { makeProjectsModule } from '@/store/modules/projects';
|
||||
import { NotificatorPlugin } from '@/utils/plugins/notificator';
|
||||
import { createLocalVue, mount } from '@vue/test-utils';
|
||||
|
||||
import { ApiKeysMock } from '../../mock/api/apiKeys';
|
||||
import { AccessGrantsMock } from '../../mock/api/accessGrants';
|
||||
import { BucketsMock } from '../../mock/api/buckets';
|
||||
import { PaymentsMock } from '../../mock/api/payments';
|
||||
import { ProjectMembersApiMock } from '../../mock/api/projectMembers';
|
||||
@ -35,12 +35,12 @@ const paymentsApi = new PaymentsMock();
|
||||
const paymentsModule = makePaymentsModule(paymentsApi);
|
||||
const bucketsApi = new BucketsMock();
|
||||
const bucketUsageModule = makeBucketsModule(bucketsApi);
|
||||
const apiKeysApi = new ApiKeysMock();
|
||||
const apiKeysModule = makeApiKeysModule(apiKeysApi);
|
||||
const accessGrantsApi = new AccessGrantsMock();
|
||||
const accessGrantsModule = makeAccessGrantsModule(accessGrantsApi);
|
||||
const projectMembersApi = new ProjectMembersApiMock();
|
||||
const projectMembersModule = makeProjectMembersModule(projectMembersApi);
|
||||
|
||||
const store = new Vuex.Store({ modules: { projectsModule, paymentsModule, bucketUsageModule, projectMembersModule, apiKeysModule }});
|
||||
const store = new Vuex.Store({ modules: { projectsModule, paymentsModule, bucketUsageModule, projectMembersModule, accessGrantsModule }});
|
||||
|
||||
describe('ProjectSummary.vue', (): void => {
|
||||
it('renders correctly', (): void => {
|
||||
|
@ -9,7 +9,7 @@ exports[`ProjectSummary.vue renders correctly 1`] = `
|
||||
<p class="summary-item__value" style="color: rgb(0, 0, 0);">0</p>
|
||||
</div>
|
||||
<div class="summary-item right-indent" style="background-color: rgb(245, 246, 250);">
|
||||
<h1 class="summary-item__title" style="color: rgb(27, 37, 51);">API Keys</h1>
|
||||
<h1 class="summary-item__title" style="color: rgb(27, 37, 51);">Access Grants</h1>
|
||||
<p class="summary-item__value" style="color: rgb(0, 0, 0);">0</p>
|
||||
</div>
|
||||
<div class="summary-item right-indent" style="background-color: rgb(177, 193, 217);">
|
||||
|
@ -4,7 +4,7 @@
|
||||
import Vuex from 'vuex';
|
||||
|
||||
import { RouteConfig, router } from '@/router';
|
||||
import { makeApiKeysModule } from '@/store/modules/apiKeys';
|
||||
import { makeAccessGrantsModule } from '@/store/modules/accessGrants';
|
||||
import { appStateModule } from '@/store/modules/appState';
|
||||
import { makeBucketsModule } from '@/store/modules/buckets';
|
||||
import { makeNotificationsModule } from '@/store/modules/notifications';
|
||||
@ -12,7 +12,6 @@ import { makePaymentsModule } from '@/store/modules/payments';
|
||||
import { makeProjectMembersModule } from '@/store/modules/projectMembers';
|
||||
import { makeProjectsModule } from '@/store/modules/projects';
|
||||
import { makeUsersModule } from '@/store/modules/users';
|
||||
import { APP_STATE_MUTATIONS } from '@/store/mutationConstants';
|
||||
import { User } from '@/types/users';
|
||||
import { APP_STATE_ACTIONS } from '@/utils/constants/actionNames';
|
||||
import { AppState } from '@/utils/constants/appStateEnum';
|
||||
@ -21,6 +20,7 @@ import { SegmentioPlugin } from '@/utils/plugins/segment';
|
||||
import DashboardArea from '@/views/DashboardArea.vue';
|
||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||
|
||||
import { AccessGrantsMock } from '../mock/api/accessGrants';
|
||||
import { ApiKeysMock } from '../mock/api/apiKeys';
|
||||
import { BucketsMock } from '../mock/api/buckets';
|
||||
import { PaymentsMock } from '../mock/api/payments';
|
||||
@ -43,7 +43,7 @@ projectsApi.setMockProjects([]);
|
||||
|
||||
const usersModule = makeUsersModule(usersApi);
|
||||
const projectsModule = makeProjectsModule(projectsApi);
|
||||
const apiKeysModule = makeApiKeysModule(new ApiKeysMock());
|
||||
const accessGrantsModule = makeAccessGrantsModule(new AccessGrantsMock());
|
||||
const teamMembersModule = makeProjectMembersModule(new ProjectMembersApiMock());
|
||||
const bucketsModule = makeBucketsModule(new BucketsMock());
|
||||
const notificationsModule = makeNotificationsModule();
|
||||
@ -53,7 +53,7 @@ const store = new Vuex.Store({
|
||||
modules: {
|
||||
notificationsModule,
|
||||
bucketsModule,
|
||||
apiKeysModule,
|
||||
accessGrantsModule,
|
||||
usersModule,
|
||||
projectsModule,
|
||||
appStateModule,
|
||||
@ -114,7 +114,7 @@ describe('Dashboard', () => {
|
||||
|
||||
it('loads routes correctly when authorithed without project with unavailable routes', async () => {
|
||||
const unavailableWithoutProject = [
|
||||
RouteConfig.ApiKeys.path,
|
||||
RouteConfig.AccessGrants.path,
|
||||
RouteConfig.Users.path,
|
||||
RouteConfig.ProjectDashboard.path,
|
||||
];
|
||||
|