diff --git a/.github/workflows/frontend-test.yml b/.github/workflows/frontend-test.yml
index 48efbf7..e579ece 100644
--- a/.github/workflows/frontend-test.yml
+++ b/.github/workflows/frontend-test.yml
@@ -28,6 +28,9 @@ jobs:
- name: Run eslint check
run: pnpm lint
working-directory: frontend/web
+ - name: Run type check
+ run: pnpm type-check
+ working-directory: frontend/web
frontend-build:
runs-on: ubuntu-latest
diff --git a/frontend/extension/tsconfig.json b/frontend/extension/tsconfig.json
index 2618f69..6224ea3 100644
--- a/frontend/extension/tsconfig.json
+++ b/frontend/extension/tsconfig.json
@@ -1,18 +1,10 @@
{
"extends": "plasmo/templates/tsconfig.base",
- "exclude": [
- "node_modules"
- ],
- "include": [
- ".plasmo/index.d.ts",
- "./**/*.ts",
- "./**/*.tsx",
- ],
+ "exclude": ["node_modules"],
+ "include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.tsx"],
"compilerOptions": {
"paths": {
- "@/*": [
- "./src/*"
- ],
+ "@/*": ["./src/*"]
},
"baseUrl": "."
}
diff --git a/frontend/web/package.json b/frontend/web/package.json
index 32a1a8f..0c16448 100644
--- a/frontend/web/package.json
+++ b/frontend/web/package.json
@@ -2,10 +2,11 @@
"name": "slash",
"scripts": {
"dev": "vite",
- "build": "tsc && vite build",
+ "build": "vite build",
"serve": "vite preview",
"lint": "eslint --ext .js,.ts,.tsx, src",
"lint-fix": "eslint --ext .js,.ts,.tsx, src --fix",
+ "type-check": "tsc --noEmit --skipLibCheck",
"postinstall": "cd ../../proto && buf generate"
},
"dependencies": {
@@ -33,6 +34,7 @@
},
"devDependencies": {
"@bufbuild/buf": "^1.39.0",
+ "@bufbuild/protobuf": "^2.1.0",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/lodash-es": "^4.17.12",
"@types/react": "^18.3.5",
diff --git a/frontend/web/pnpm-lock.yaml b/frontend/web/pnpm-lock.yaml
index 304e660..3216976 100644
--- a/frontend/web/pnpm-lock.yaml
+++ b/frontend/web/pnpm-lock.yaml
@@ -78,6 +78,9 @@ importers:
'@bufbuild/buf':
specifier: ^1.39.0
version: 1.39.0
+ '@bufbuild/protobuf':
+ specifier: ^2.1.0
+ version: 2.1.0
'@trivago/prettier-plugin-sort-imports':
specifier: ^4.3.0
version: 4.3.0(prettier@3.3.3)
@@ -256,6 +259,9 @@ packages:
engines: {node: '>=12'}
hasBin: true
+ '@bufbuild/protobuf@2.1.0':
+ resolution: {integrity: sha512-+2Mx67Y3skJ4NCD/qNSdBJNWtu6x6Qr53jeNg+QcwiL6mt0wK+3jwHH2x1p7xaYH6Ve2JKOVn0OxU35WsmqI9A==}
+
'@emotion/babel-plugin@11.12.0':
resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==}
@@ -2588,6 +2594,8 @@ snapshots:
'@bufbuild/buf-win32-arm64': 1.39.0
'@bufbuild/buf-win32-x64': 1.39.0
+ '@bufbuild/protobuf@2.1.0': {}
+
'@emotion/babel-plugin@11.12.0':
dependencies:
'@babel/helper-module-imports': 7.24.7
diff --git a/frontend/web/tsconfig.json b/frontend/web/tsconfig.json
index 4a48a6e..f364b07 100644
--- a/frontend/web/tsconfig.json
+++ b/frontend/web/tsconfig.json
@@ -16,11 +16,10 @@
"noEmit": true,
"jsx": "react-jsx",
"paths": {
- "@/*": [
- "./src/*"
- ],
+ "@/*": ["./src/*"]
},
"baseUrl": "."
},
- "include": ["./src"]
+ "include": ["./src"],
+ "exclude": ["node_modules"]
}
diff --git a/proto/gen/apidocs.swagger.yaml b/proto/gen/apidocs.swagger.yaml
index b711767..8a8e8bc 100644
--- a/proto/gen/apidocs.swagger.yaml
+++ b/proto/gen/apidocs.swagger.yaml
@@ -775,7 +775,9 @@ definitions:
expiresAt:
type: string
format: date-time
- description: "expires_at is the expiration time of the access token.\r\nIf expires_at is not set, the access token will never expire."
+ description: |-
+ expires_at is the expiration time of the access token.
+ If expires_at is not set, the access token will never expire.
apiv1Collection:
type: object
properties:
@@ -1141,7 +1143,9 @@ definitions:
description: Current workspace version.
owner:
type: string
- title: "The owner name.\r\nFormat: \"users/{id}\""
+ title: |-
+ The owner name.
+ Format: "users/{id}"
subscription:
$ref: '#/definitions/v1Subscription'
description: The workspace subscription.
diff --git a/proto/gen/store/README.md b/proto/gen/store/README.md
index 498b1f7..70cb699 100644
--- a/proto/gen/store/README.md
+++ b/proto/gen/store/README.md
@@ -6,6 +6,8 @@
- [store/activity.proto](#store_activity-proto)
- [ActivityShorcutCreatePayload](#slash-store-ActivityShorcutCreatePayload)
- [ActivityShorcutViewPayload](#slash-store-ActivityShorcutViewPayload)
+ - [ActivityShorcutViewPayload.ParamsEntry](#slash-store-ActivityShorcutViewPayload-ParamsEntry)
+ - [ActivityShorcutViewPayload.ValueList](#slash-store-ActivityShorcutViewPayload-ValueList)
- [store/common.proto](#store_common-proto)
- [RowStatus](#slash-store-RowStatus)
@@ -81,6 +83,38 @@
| ip | [string](#string) | | |
| referer | [string](#string) | | |
| user_agent | [string](#string) | | |
+| params | [ActivityShorcutViewPayload.ParamsEntry](#slash-store-ActivityShorcutViewPayload-ParamsEntry) | repeated | |
+
+
+
+
+
+
+
+
+### ActivityShorcutViewPayload.ParamsEntry
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| key | [string](#string) | | |
+| value | [ActivityShorcutViewPayload.ValueList](#slash-store-ActivityShorcutViewPayload-ValueList) | | |
+
+
+
+
+
+
+
+
+### ActivityShorcutViewPayload.ValueList
+
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| values | [string](#string) | repeated | |
diff --git a/proto/gen/store/activity.pb.go b/proto/gen/store/activity.pb.go
index 194d71d..0ecf94a 100644
--- a/proto/gen/store/activity.pb.go
+++ b/proto/gen/store/activity.pb.go
@@ -72,10 +72,11 @@ type ActivityShorcutViewPayload struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- ShortcutId int32 `protobuf:"varint,1,opt,name=shortcut_id,json=shortcutId,proto3" json:"shortcut_id,omitempty"`
- Ip string `protobuf:"bytes,2,opt,name=ip,proto3" json:"ip,omitempty"`
- Referer string `protobuf:"bytes,3,opt,name=referer,proto3" json:"referer,omitempty"`
- UserAgent string `protobuf:"bytes,4,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"`
+ ShortcutId int32 `protobuf:"varint,1,opt,name=shortcut_id,json=shortcutId,proto3" json:"shortcut_id,omitempty"`
+ Ip string `protobuf:"bytes,2,opt,name=ip,proto3" json:"ip,omitempty"`
+ Referer string `protobuf:"bytes,3,opt,name=referer,proto3" json:"referer,omitempty"`
+ UserAgent string `protobuf:"bytes,4,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"`
+ Params map[string]*ActivityShorcutViewPayload_ValueList `protobuf:"bytes,5,rep,name=params,proto3" json:"params,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *ActivityShorcutViewPayload) Reset() {
@@ -138,6 +139,60 @@ func (x *ActivityShorcutViewPayload) GetUserAgent() string {
return ""
}
+func (x *ActivityShorcutViewPayload) GetParams() map[string]*ActivityShorcutViewPayload_ValueList {
+ if x != nil {
+ return x.Params
+ }
+ return nil
+}
+
+type ActivityShorcutViewPayload_ValueList struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Values []string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
+}
+
+func (x *ActivityShorcutViewPayload_ValueList) Reset() {
+ *x = ActivityShorcutViewPayload_ValueList{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_store_activity_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ActivityShorcutViewPayload_ValueList) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ActivityShorcutViewPayload_ValueList) ProtoMessage() {}
+
+func (x *ActivityShorcutViewPayload_ValueList) ProtoReflect() protoreflect.Message {
+ mi := &file_store_activity_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ActivityShorcutViewPayload_ValueList.ProtoReflect.Descriptor instead.
+func (*ActivityShorcutViewPayload_ValueList) Descriptor() ([]byte, []int) {
+ return file_store_activity_proto_rawDescGZIP(), []int{1, 1}
+}
+
+func (x *ActivityShorcutViewPayload_ValueList) GetValues() []string {
+ if x != nil {
+ return x.Values
+ }
+ return nil
+}
+
var File_store_activity_proto protoreflect.FileDescriptor
var file_store_activity_proto_rawDesc = []byte{
@@ -147,7 +202,7 @@ var file_store_activity_proto_rawDesc = []byte{
0x68, 0x6f, 0x72, 0x63, 0x75, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x5f,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63,
- 0x75, 0x74, 0x49, 0x64, 0x22, 0x86, 0x01, 0x0a, 0x1a, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74,
+ 0x75, 0x74, 0x49, 0x64, 0x22, 0xe6, 0x02, 0x0a, 0x1a, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74,
0x79, 0x53, 0x68, 0x6f, 0x72, 0x63, 0x75, 0x74, 0x56, 0x69, 0x65, 0x77, 0x50, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x5f,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x63,
@@ -155,7 +210,21 @@ var file_store_activity_proto_rawDesc = []byte{
0x52, 0x02, 0x69, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, 0x12, 0x1d,
0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x42, 0x9e, 0x01,
+ 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x4b, 0x0a,
+ 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e,
+ 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69,
+ 0x76, 0x69, 0x74, 0x79, 0x53, 0x68, 0x6f, 0x72, 0x63, 0x75, 0x74, 0x56, 0x69, 0x65, 0x77, 0x50,
+ 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74,
+ 0x72, 0x79, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x6c, 0x0a, 0x0b, 0x50, 0x61,
+ 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x47, 0x0a, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x73, 0x6c, 0x61,
+ 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74,
+ 0x79, 0x53, 0x68, 0x6f, 0x72, 0x63, 0x75, 0x74, 0x56, 0x69, 0x65, 0x77, 0x50, 0x61, 0x79, 0x6c,
+ 0x6f, 0x61, 0x64, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x23, 0x0a, 0x09, 0x56, 0x61, 0x6c, 0x75,
+ 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18,
+ 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x9e, 0x01,
0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x73, 0x74, 0x6f, 0x72,
0x65, 0x42, 0x0d, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f,
0x50, 0x01, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x79,
@@ -181,17 +250,21 @@ func file_store_activity_proto_rawDescGZIP() []byte {
return file_store_activity_proto_rawDescData
}
-var file_store_activity_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_store_activity_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_store_activity_proto_goTypes = []any{
(*ActivityShorcutCreatePayload)(nil), // 0: slash.store.ActivityShorcutCreatePayload
(*ActivityShorcutViewPayload)(nil), // 1: slash.store.ActivityShorcutViewPayload
+ nil, // 2: slash.store.ActivityShorcutViewPayload.ParamsEntry
+ (*ActivityShorcutViewPayload_ValueList)(nil), // 3: slash.store.ActivityShorcutViewPayload.ValueList
}
var file_store_activity_proto_depIdxs = []int32{
- 0, // [0:0] is the sub-list for method output_type
- 0, // [0:0] is the sub-list for method input_type
- 0, // [0:0] is the sub-list for extension type_name
- 0, // [0:0] is the sub-list for extension extendee
- 0, // [0:0] is the sub-list for field type_name
+ 2, // 0: slash.store.ActivityShorcutViewPayload.params:type_name -> slash.store.ActivityShorcutViewPayload.ParamsEntry
+ 3, // 1: slash.store.ActivityShorcutViewPayload.ParamsEntry.value:type_name -> slash.store.ActivityShorcutViewPayload.ValueList
+ 2, // [2:2] is the sub-list for method output_type
+ 2, // [2:2] is the sub-list for method input_type
+ 2, // [2:2] is the sub-list for extension type_name
+ 2, // [2:2] is the sub-list for extension extendee
+ 0, // [0:2] is the sub-list for field type_name
}
func init() { file_store_activity_proto_init() }
@@ -224,6 +297,18 @@ func file_store_activity_proto_init() {
return nil
}
}
+ file_store_activity_proto_msgTypes[3].Exporter = func(v any, i int) any {
+ switch v := v.(*ActivityShorcutViewPayload_ValueList); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -231,7 +316,7 @@ func file_store_activity_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_store_activity_proto_rawDesc,
NumEnums: 0,
- NumMessages: 2,
+ NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},
diff --git a/proto/store/activity.proto b/proto/store/activity.proto
index ee8d849..d3ef1e2 100644
--- a/proto/store/activity.proto
+++ b/proto/store/activity.proto
@@ -13,4 +13,9 @@ message ActivityShorcutViewPayload {
string ip = 2;
string referer = 3;
string user_agent = 4;
+ map params = 5;
+
+ message ValueList {
+ repeated string values = 1;
+ }
}
diff --git a/server/route/frontend/frontend.go b/server/route/frontend/frontend.go
index d2d4cc6..80699ef 100644
--- a/server/route/frontend/frontend.go
+++ b/server/route/frontend/frontend.go
@@ -122,11 +122,16 @@ func (s *FrontendService) createShortcutViewActivity(ctx context.Context, reques
ip := getReadUserIP(request)
referer := request.Header.Get("Referer")
userAgent := request.Header.Get("User-Agent")
+ params := map[string]*storepb.ActivityShorcutViewPayload_ValueList{}
+ for key, values := range request.URL.Query() {
+ params[key] = &storepb.ActivityShorcutViewPayload_ValueList{Values: values}
+ }
payload := &storepb.ActivityShorcutViewPayload{
ShortcutId: shortcut.Id,
Ip: ip,
Referer: referer,
UserAgent: userAgent,
+ Params: params,
}
payloadStr, err := protojson.Marshal(payload)
if err != nil {