Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
2e34ce90
Unverified
Commit
2e34ce90
authored
May 27, 2023
by
boojack
Committed by
GitHub
May 27, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chore: upgrade version `0.13.1` (#1754)
parent
93d608f0
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
48 additions
and
303 deletions
+48
-303
e2e-test.yml
.github/workflows/e2e-test.yml
+0
-66
resource.go
server/resource.go
+7
-5
version.go
server/version/version.go
+2
-2
04__resource_public_id.sql
store/db/migration/prod/0.12/04__resource_public_id.sql
+0
-1
memo.go
store/memo.go
+5
-0
001-setup.spec.ts
web/e2e-tests/001-setup.spec.ts
+0
-13
002-basic.spec.ts
web/e2e-tests/002-basic.spec.ts
+0
-37
fixtures.ts
web/e2e-tests/fixtures.ts
+0
-2
utils.ts
web/e2e-tests/utils.ts
+0
-52
package.json
web/package.json
+0
-1
playwright.config.ts
web/playwright.config.ts
+0
-19
pnpm-lock.yaml
web/pnpm-lock.yaml
+0
-20
AskAIDialog.tsx
web/src/components/AskAIDialog.tsx
+29
-53
Memo.tsx
web/src/components/Memo.tsx
+1
-1
MobileHeader.tsx
web/src/components/MobileHeader.tsx
+1
-1
global.css
web/src/css/global.css
+3
-30
No files found.
.github/workflows/e2e-test.yml
deleted
100644 → 0
View file @
93d608f0
name
:
"
E2E
Test"
on
:
push
:
branches
:
[
main
]
pull_request
:
branches
:
[
main
]
jobs
:
build
:
name
:
Build and Run Memos With E2E Test
runs-on
:
ubuntu-latest
steps
:
-
name
:
Checkout code
uses
:
actions/checkout@v3
-
name
:
Build Docker image
id
:
docker_build
uses
:
docker/build-push-action@v3
with
:
context
:
./
file
:
./Dockerfile
platforms
:
linux/amd64
push
:
false
tags
:
neosmemo/memos:e2e
labels
:
neosmemo/memos:e2e
-
name
:
Run Docker container
run
:
docker run -d -p 5230:5230 neosmemo/memos:e2e
-
uses
:
pnpm/action-setup@v2.2.4
with
:
version
:
8.0.0
-
uses
:
actions/setup-node@v3
with
:
node-version
:
18
cache
:
"
pnpm"
cache-dependency-path
:
./web/pnpm-lock.yaml
-
name
:
Install dependencies
working-directory
:
web
run
:
pnpm install
-
name
:
Install Playwright Browsers
working-directory
:
web
run
:
npx playwright install --with-deps
-
name
:
Run Playwright tests
working-directory
:
web
run
:
npx playwright test
-
uses
:
actions/upload-artifact@v3
if
:
always()
with
:
name
:
playwright-report
path
:
web/playwright-report/
retention-days
:
30
-
uses
:
actions/upload-artifact@v3
if
:
always()
with
:
name
:
playwright-screenshot
path
:
web/playwright-screenshot/
retention-days
:
30
-
name
:
Stop Docker container
run
:
docker stop $(docker ps -q)
server/resource.go
View file @
2e34ce90
...
@@ -123,6 +123,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -123,6 +123,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to unmarshal storage service id"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to unmarshal storage service id"
)
.
SetInternal
(
err
)
}
}
}
}
publicID
:=
common
.
GenUUID
()
publicID
:=
common
.
GenUUID
()
if
storageServiceID
==
api
.
DatabaseStorage
{
if
storageServiceID
==
api
.
DatabaseStorage
{
fileBytes
,
err
:=
io
.
ReadAll
(
sourceFile
)
fileBytes
,
err
:=
io
.
ReadAll
(
sourceFile
)
...
@@ -326,12 +327,13 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
...
@@ -326,12 +327,13 @@ func (s *Server) registerResourceRoutes(g *echo.Group) {
if
err
:=
os
.
Remove
(
resource
.
InternalPath
);
err
!=
nil
{
if
err
:=
os
.
Remove
(
resource
.
InternalPath
);
err
!=
nil
{
log
.
Warn
(
fmt
.
Sprintf
(
"failed to delete local file with path %s"
,
resource
.
InternalPath
),
zap
.
Error
(
err
))
log
.
Warn
(
fmt
.
Sprintf
(
"failed to delete local file with path %s"
,
resource
.
InternalPath
),
zap
.
Error
(
err
))
}
}
}
thumbnailPath
:=
path
.
Join
(
s
.
Profile
.
Data
,
thumbnailImagePath
,
resource
.
PublicID
)
ext
:=
filepath
.
Ext
(
resource
.
Filename
)
thumbnailPath
:=
path
.
Join
(
s
.
Profile
.
Data
,
thumbnailImagePath
,
fmt
.
Sprintf
(
"%d-%s%s"
,
resource
.
ID
,
resource
.
PublicID
,
ext
))
if
err
:=
os
.
Remove
(
thumbnailPath
);
err
!=
nil
{
if
err
:=
os
.
Remove
(
thumbnailPath
);
err
!=
nil
{
log
.
Warn
(
fmt
.
Sprintf
(
"failed to delete local thumbnail with path %s"
,
thumbnailPath
),
zap
.
Error
(
err
))
log
.
Warn
(
fmt
.
Sprintf
(
"failed to delete local thumbnail with path %s"
,
thumbnailPath
),
zap
.
Error
(
err
))
}
}
}
resourceDelete
:=
&
api
.
ResourceDelete
{
resourceDelete
:=
&
api
.
ResourceDelete
{
ID
:
resourceID
,
ID
:
resourceID
,
...
@@ -434,7 +436,7 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
...
@@ -434,7 +436,7 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) {
if
c
.
QueryParam
(
"thumbnail"
)
==
"1"
&&
common
.
HasPrefixes
(
resource
.
Type
,
"image/png"
,
"image/jpeg"
)
{
if
c
.
QueryParam
(
"thumbnail"
)
==
"1"
&&
common
.
HasPrefixes
(
resource
.
Type
,
"image/png"
,
"image/jpeg"
)
{
ext
:=
filepath
.
Ext
(
filename
)
ext
:=
filepath
.
Ext
(
filename
)
thumbnailPath
:=
path
.
Join
(
s
.
Profile
.
Data
,
thumbnailImagePath
,
resource
.
PublicID
+
ext
)
thumbnailPath
:=
path
.
Join
(
s
.
Profile
.
Data
,
thumbnailImagePath
,
fmt
.
Sprintf
(
"%d-%s%s"
,
resource
.
ID
,
resource
.
PublicID
,
ext
)
)
thumbnailBlob
,
err
:=
getOrGenerateThumbnailImage
(
blob
,
thumbnailPath
)
thumbnailBlob
,
err
:=
getOrGenerateThumbnailImage
(
blob
,
thumbnailPath
)
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Warn
(
fmt
.
Sprintf
(
"failed to get or generate local thumbnail with path %s"
,
thumbnailPath
),
zap
.
Error
(
err
))
log
.
Warn
(
fmt
.
Sprintf
(
"failed to get or generate local thumbnail with path %s"
,
thumbnailPath
),
zap
.
Error
(
err
))
...
...
server/version/version.go
View file @
2e34ce90
...
@@ -9,10 +9,10 @@ import (
...
@@ -9,10 +9,10 @@ import (
// Version is the service current released version.
// Version is the service current released version.
// Semantic versioning: https://semver.org/
// Semantic versioning: https://semver.org/
var
Version
=
"0.13.
0
"
var
Version
=
"0.13.
1
"
// DevVersion is the service current development version.
// DevVersion is the service current development version.
var
DevVersion
=
"0.13.
0
"
var
DevVersion
=
"0.13.
1
"
func
GetCurrentVersion
(
mode
string
)
string
{
func
GetCurrentVersion
(
mode
string
)
string
{
if
mode
==
"dev"
||
mode
==
"demo"
{
if
mode
==
"dev"
||
mode
==
"demo"
{
...
...
store/db/migration/prod/0.12/04__resource_public_id.sql
View file @
2e34ce90
...
@@ -3,7 +3,6 @@ ALTER TABLE
...
@@ -3,7 +3,6 @@ ALTER TABLE
ADD
ADD
COLUMN
public_id
TEXT
NOT
NULL
DEFAULT
''
;
COLUMN
public_id
TEXT
NOT
NULL
DEFAULT
''
;
-- TODO(steven): remove this in next release.
CREATE
UNIQUE
INDEX
resource_id_public_id_unique_index
ON
resource
(
id
,
public_id
);
CREATE
UNIQUE
INDEX
resource_id_public_id_unique_index
ON
resource
(
id
,
public_id
);
UPDATE
UPDATE
...
...
store/memo.go
View file @
2e34ce90
...
@@ -6,6 +6,7 @@ import (
...
@@ -6,6 +6,7 @@ import (
"fmt"
"fmt"
"strconv"
"strconv"
"strings"
"strings"
"time"
"github.com/usememos/memos/common"
"github.com/usememos/memos/common"
)
)
...
@@ -90,6 +91,10 @@ func (s *Store) CreateMemo(ctx context.Context, create *MemoMessage) (*MemoMessa
...
@@ -90,6 +91,10 @@ func (s *Store) CreateMemo(ctx context.Context, create *MemoMessage) (*MemoMessa
}
}
defer
tx
.
Rollback
()
defer
tx
.
Rollback
()
if
create
.
CreatedTs
==
0
{
create
.
CreatedTs
=
time
.
Now
()
.
Unix
()
}
query
:=
`
query
:=
`
INSERT INTO memo (
INSERT INTO memo (
creator_id,
creator_id,
...
...
web/e2e-tests/001-setup.spec.ts
deleted
100644 → 0
View file @
93d608f0
import
{
test
}
from
"@playwright/test"
;
import
{
signUp
}
from
"./utils"
;
test
.
use
({
locale
:
"en-US"
,
timezoneId
:
"Europe/Berlin"
,
});
test
.
describe
(
"Sign up a host account"
,
async
()
=>
{
test
(
"Sign Up"
,
async
({
page
})
=>
{
await
signUp
(
page
,
"admin"
,
"admin"
);
});
});
web/e2e-tests/002-basic.spec.ts
deleted
100644 → 0
View file @
93d608f0
import
{
test
,
expect
}
from
"@playwright/test"
;
import
{
review
,
login
,
writeMemo
}
from
"./utils"
;
import
randomstring
from
"randomstring"
;
test
.
use
({
locale
:
"en-US"
,
timezoneId
:
"Europe/Berlin"
,
});
test
.
beforeEach
(
async
({
page
})
=>
{
await
login
(
page
,
"admin"
,
"admin"
);
});
test
.
describe
(
"Write some memos"
,
async
()
=>
{
test
(
"Write memos"
,
async
({
page
})
=>
{
const
content
=
`
${
randomstring
.
generate
()}
from Write memos`
;
await
writeMemo
(
page
,
content
);
await
expect
(
page
.
getByText
(
content
)).
toBeVisible
();
});
test
(
"Write memos with Tag"
,
async
({
page
})
=>
{
const
tag
=
randomstring
.
generate
(
5
);
const
content
=
`#
${
tag
}
${
randomstring
.
generate
()}
from Write memos with Tag`
;
await
writeMemo
(
page
,
content
);
// 1.memo contentg 2.tags list of memos editor 3.tags list
await
expect
(
page
.
getByText
(
tag
)).
toHaveCount
(
3
);
});
});
test
.
describe
(
"Daily Review"
,
async
()
=>
{
test
(
"Daily Review"
,
async
({
page
})
=>
{
const
content
=
randomstring
.
generate
();
await
writeMemo
(
page
,
content
);
await
review
(
page
);
await
expect
(
page
.
getByText
(
content
)).
toBeVisible
();
});
});
web/e2e-tests/fixtures.ts
deleted
100644 → 0
View file @
93d608f0
const
baseHost
=
"http://localhost:5230"
;
export
{
baseHost
};
web/e2e-tests/utils.ts
deleted
100644 → 0
View file @
93d608f0
import
{
expect
,
Page
}
from
"@playwright/test"
;
import
locale
from
"../src/locales/en.json"
;
import
{
baseHost
}
from
"./fixtures"
;
async
function
screenshot
(
page
:
Page
,
name
:
string
)
{
await
page
.
screenshot
({
path
:
`playwright-screenshot/
${
name
}
.png`
,
fullPage
:
true
});
}
async
function
writeMemo
(
page
:
Page
,
content
:
string
)
{
await
expect
(
page
.
getByRole
(
"button"
,
{
name
:
locale
.
editor
.
save
})).
toBeDisabled
();
await
page
.
getByPlaceholder
(
"Any thoughts..."
).
fill
(
content
);
await
expect
(
page
.
getByRole
(
"button"
,
{
name
:
locale
.
editor
.
save
})).
toBeEnabled
();
await
page
.
getByRole
(
"button"
,
{
name
:
locale
.
editor
.
save
}).
click
();
}
async
function
login
(
page
:
Page
,
username
:
string
,
password
:
string
)
{
page
.
goto
(
`
${
baseHost
}
/`
);
await
screenshot
(
page
,
"explore-page"
);
await
page
.
waitForURL
(
"**/explore"
);
await
screenshot
(
page
,
"explore-page-after-wait"
);
await
page
.
getByRole
(
"link"
,
{
name
:
locale
.
common
[
"sign-in"
]
}).
click
();
await
screenshot
(
page
,
"auth-page"
);
await
page
.
waitForURL
(
"**/auth"
);
await
page
.
locator
(
'input[type="text"]'
).
click
();
await
page
.
locator
(
'input[type="text"]'
).
fill
(
username
);
await
page
.
locator
(
'input[type="password"]'
).
click
();
await
page
.
locator
(
'input[type="password"]'
).
fill
(
password
);
await
page
.
getByRole
(
"button"
,
{
name
:
locale
.
common
[
"sign-in"
]
}).
click
();
await
page
.
waitForTimeout
(
1000
);
await
screenshot
(
page
,
"home-page-login-success"
);
}
async
function
signUp
(
page
:
Page
,
username
:
string
,
password
:
string
)
{
await
page
.
goto
(
`
${
baseHost
}
/`
);
await
page
.
waitForURL
(
"**/auth"
);
await
screenshot
(
page
,
"sign-up-page"
);
await
page
.
locator
(
'input[type="text"]'
).
click
();
await
page
.
locator
(
'input[type="text"]'
).
fill
(
username
);
await
page
.
locator
(
'input[type="password"]'
).
click
();
await
page
.
locator
(
'input[type="password"]'
).
fill
(
password
);
await
page
.
getByRole
(
"button"
,
{
name
:
locale
.
auth
[
"signup-as-host"
]
}).
click
();
await
page
.
waitForTimeout
(
1000
);
await
screenshot
(
page
,
"home-page-sign-up-success"
);
}
async
function
review
(
page
:
Page
)
{
await
page
.
goto
(
`
${
baseHost
}
/`
);
await
page
.
getByRole
(
"link"
,
{
name
:
locale
[
"daily-review"
][
"title"
]
}).
click
();
await
screenshot
(
page
,
"review"
);
}
export
{
writeMemo
,
login
,
signUp
,
review
};
web/package.json
View file @
2e34ce90
...
@@ -35,7 +35,6 @@
...
@@ -35,7 +35,6 @@
"zustand"
:
"^4.3.6"
"zustand"
:
"^4.3.6"
},
},
"devDependencies"
:
{
"devDependencies"
:
{
"@playwright/test"
:
"^1.32.2"
,
"@types/lodash-es"
:
"^4.17.5"
,
"@types/lodash-es"
:
"^4.17.5"
,
"@types/node"
:
"^18.0.3"
,
"@types/node"
:
"^18.0.3"
,
"@types/qs"
:
"^6.9.7"
,
"@types/qs"
:
"^6.9.7"
,
...
...
web/playwright.config.ts
deleted
100644 → 0
View file @
93d608f0
import
{
defineConfig
,
devices
}
from
"@playwright/test"
;
export
default
defineConfig
({
testDir
:
"./e2e-tests"
,
fullyParallel
:
true
,
forbidOnly
:
!!
process
.
env
.
CI
,
retries
:
process
.
env
.
CI
?
2
:
0
,
workers
:
1
,
reporter
:
[[
"html"
,
{
outputFolder
:
"playwright-report"
,
open
:
"never"
}]],
use
:
{
trace
:
"on-first-retry"
,
},
projects
:
[
{
name
:
"chromium"
,
use
:
{
...
devices
[
"Desktop Chrome"
]
},
},
],
});
web/pnpm-lock.yaml
View file @
2e34ce90
...
@@ -78,9 +78,6 @@ dependencies:
...
@@ -78,9 +78,6 @@ dependencies:
version
:
4.3.6(react@18.2.0)
version
:
4.3.6(react@18.2.0)
devDependencies
:
devDependencies
:
'
@playwright/test'
:
specifier
:
^1.32.2
version
:
1.32.2
'
@types/lodash-es'
:
'
@types/lodash-es'
:
specifier
:
^4.17.5
specifier
:
^4.17.5
version
:
4.17.5
version
:
4.17.5
...
@@ -784,17 +781,6 @@ packages:
...
@@ -784,17 +781,6 @@ packages:
'
@nodelib/fs.scandir'
:
2.1.5
'
@nodelib/fs.scandir'
:
2.1.5
fastq
:
1.15.0
fastq
:
1.15.0
/@playwright/test@1.32.2
:
resolution
:
{
integrity
:
sha512-nhaTSDpEdTTttdkDE8Z6K3icuG1DVRxrl98Qq0Lfc63SS9a2sjc9+x8ezysh7MzCKz6Y+nArml3/mmt+gqRmQQ==
}
engines
:
{
node
:
'
>=14'
}
hasBin
:
true
dependencies
:
'
@types/node'
:
18.0.3
playwright-core
:
1.32.2
optionalDependencies
:
fsevents
:
2.3.2
dev
:
true
/@popperjs/core@2.11.7
:
/@popperjs/core@2.11.7
:
resolution
:
{
integrity
:
sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==
}
resolution
:
{
integrity
:
sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==
}
dev
:
false
dev
:
false
...
@@ -2944,12 +2930,6 @@ packages:
...
@@ -2944,12 +2930,6 @@ packages:
dev
:
true
dev
:
true
optional
:
true
optional
:
true
/playwright-core@1.32.2
:
resolution
:
{
integrity
:
sha512-zD7aonO+07kOTthsrCR3YCVnDcqSHIJpdFUtZEMOb6//1Rc7/6mZDRdw+nlzcQiQltOOsiqI3rrSyn/SlyjnJQ==
}
engines
:
{
node
:
'
>=14'
}
hasBin
:
true
dev
:
true
/postcss-import@14.1.0(postcss@8.4.21)
:
/postcss-import@14.1.0(postcss@8.4.21)
:
resolution
:
{
integrity
:
sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==
}
resolution
:
{
integrity
:
sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==
}
engines
:
{
node
:
'
>=10.0.0'
}
engines
:
{
node
:
'
>=10.0.0'
}
...
...
web/src/components/AskAIDialog.tsx
View file @
2e34ce90
import
{
import
{
Button
,
FormControl
,
Input
,
Modal
,
ModalClose
,
ModalDialog
,
Stack
,
Textarea
,
Typography
}
from
"@mui/joy"
;
Button
,
FormControl
,
FormLabel
,
Input
,
Menu
,
MenuItem
,
Modal
,
ModalClose
,
ModalDialog
,
Stack
,
Textarea
,
Typography
,
}
from
"@mui/joy"
;
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
{
useTranslation
}
from
"react-i18next"
;
...
@@ -19,11 +6,11 @@ import * as api from "@/helpers/api";
...
@@ -19,11 +6,11 @@ import * as api from "@/helpers/api";
import
useLoading
from
"@/hooks/useLoading"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
{
marked
}
from
"@/labs/marked"
;
import
{
marked
}
from
"@/labs/marked"
;
import
{
useMessageStore
}
from
"@/store/zustand/message"
;
import
{
useMessageStore
}
from
"@/store/zustand/message"
;
import
{
defaultMessageGroup
,
MessageGroup
,
useMessageGroupStore
}
from
"@/store/zustand/message-group"
;
import
Icon
from
"./Icon"
;
import
Icon
from
"./Icon"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
showSettingDialog
from
"./SettingDialog"
;
import
showSettingDialog
from
"./SettingDialog"
;
import
{
defaultMessageGroup
,
MessageGroup
,
useMessageGroupStore
}
from
"@/store/zustand/message-group"
;
import
Selector
from
"./kit/Selector"
;
import
{
PlusIcon
,
Trash2Icon
}
from
"lucide-react"
;
type
Props
=
DialogProps
;
type
Props
=
DialogProps
;
...
@@ -92,26 +79,21 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
...
@@ -92,26 +79,21 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
});
});
};
};
const
[
anchorEl
,
setAnchorEl
]
=
useState
<
null
|
(
EventTarget
&
Element
)
>
(
null
);
const
handleMessageGroupSelect
=
(
value
:
string
)
=>
{
const
handleMenuOpen
=
(
event
:
React
.
SyntheticEvent
)
=>
{
const
messageGroup
=
messageGroupList
.
find
((
group
)
=>
group
.
messageStorageId
===
value
);
setAnchorEl
(
event
.
currentTarget
);
if
(
messageGroup
)
{
};
setMessageGroup
(
messageGroup
);
const
handleMenuClose
=
()
=>
{
}
setAnchorEl
(
null
);
};
const
handleOptionSelect
=
(
option
:
MessageGroup
)
=>
{
setMessageGroup
(
option
);
setAnchorEl
(
null
);
};
};
const
[
isAddMessageGroupD
lgOpen
,
setIsAddMessageGroupDl
gOpen
]
=
useState
<
boolean
>
(
false
);
const
[
isAddMessageGroupD
ialogOpen
,
setIsAddMessageGroupDialo
gOpen
]
=
useState
<
boolean
>
(
false
);
const
[
groupName
,
setGroupName
]
=
useState
<
string
>
(
""
);
const
[
groupName
,
setGroupName
]
=
useState
<
string
>
(
""
);
const
messageGroupStore
=
useMessageGroupStore
();
const
messageGroupStore
=
useMessageGroupStore
();
const
messageGroupList
=
messageGroupStore
.
groupList
;
const
messageGroupList
=
messageGroupStore
.
groupList
;
const
handleOpenDialog
=
()
=>
{
const
handleOpenDialog
=
()
=>
{
setIsAddMessageGroupD
l
gOpen
(
true
);
setIsAddMessageGroupD
ialo
gOpen
(
true
);
};
};
const
handleRemoveDialog
=
()
=>
{
const
handleRemoveDialog
=
()
=>
{
...
@@ -119,7 +101,7 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
...
@@ -119,7 +101,7 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
};
};
const
handleCloseDialog
=
()
=>
{
const
handleCloseDialog
=
()
=>
{
setIsAddMessageGroupD
l
gOpen
(
false
);
setIsAddMessageGroupD
ialo
gOpen
(
false
);
setGroupName
(
""
);
setGroupName
(
""
);
};
};
...
@@ -142,29 +124,24 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
...
@@ -142,29 +124,24 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
<
div
className=
"dialog-header-container"
>
<
div
className=
"dialog-header-container"
>
<
p
className=
"title-text flex flex-row items-center"
>
<
p
className=
"title-text flex flex-row items-center"
>
<
Icon
.
Bot
className=
"mr-1 w-5 h-auto opacity-80"
/>
<
Icon
.
Bot
className=
"mr-1 w-5 h-auto opacity-80"
/>
{
t
(
"ask-ai.title"
)
}
<
span
className=
"mr-4"
>
{
t
(
"ask-ai.title"
)
}
</
span
>
<
span
className=
"button-group"
style=
{
{
marginLeft
:
"10px"
}
}
>
<
span
className=
"flex flex-row justify-start items-center"
>
<
Button
color=
{
"primary"
}
onClick=
{
handleMenuOpen
}
>
<
Selector
<
div
className=
"button-len-max-150"
>
{
messageGroup
.
name
}
</
div
>
className=
"w-32"
</
Button
>
dataSource=
{
messageGroupList
.
map
((
item
)
=>
({
text
:
item
.
name
,
value
:
item
.
messageStorageId
}))
}
<
Button
color=
{
"success"
}
onClick=
{
handleOpenDialog
}
>
value=
{
messageGroup
.
messageStorageId
}
<
PlusIcon
size=
{
"13px"
}
/>
handleValueChanged=
{
handleMessageGroupSelect
}
</
Button
>
/>
<
Button
color=
{
"danger"
}
onClick=
{
handleRemoveDialog
}
>
<
button
className=
"btn-text px-1 ml-1"
onClick=
{
handleOpenDialog
}
>
<
Trash2Icon
size=
{
"13px"
}
/>
<
Icon
.
Plus
className=
"w-4 h-auto"
/>
</
Button
>
</
button
>
<
button
className=
"btn-text px-1"
onClick=
{
handleRemoveDialog
}
>
<
Icon
.
Trash2
className=
"w-4 h-auto"
/>
</
button
>
</
span
>
</
span
>
</
p
>
</
p
>
<
Menu
anchorEl=
{
anchorEl
}
open=
{
Boolean
(
anchorEl
)
}
onClose=
{
handleMenuClose
}
>
<
Modal
open=
{
isAddMessageGroupDialogOpen
}
onClose=
{
handleCloseDialog
}
>
<
MenuItem
onClick=
{
()
=>
handleOptionSelect
(
defaultMessageGroup
)
}
>
{
defaultMessageGroup
.
name
}
</
MenuItem
>
{
messageGroupList
.
map
((
messageGroup
,
index
)
=>
(
<
MenuItem
key=
{
index
}
onClick=
{
()
=>
handleOptionSelect
(
messageGroup
)
}
>
{
messageGroup
.
name
}
</
MenuItem
>
))
}
</
Menu
>
<
Modal
open=
{
isAddMessageGroupDlgOpen
}
onClose=
{
handleCloseDialog
}
>
<
ModalDialog
aria
-
labelledby=
"basic-modal-dialog-title"
sx=
{
{
maxWidth
:
500
}
}
>
<
ModalDialog
aria
-
labelledby=
"basic-modal-dialog-title"
sx=
{
{
maxWidth
:
500
}
}
>
<
ModalClose
/>
<
ModalClose
/>
<
Typography
id=
"basic-modal-dialog-title"
component=
"h2"
>
<
Typography
id=
"basic-modal-dialog-title"
component=
"h2"
>
...
@@ -172,19 +149,18 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
...
@@ -172,19 +149,18 @@ const AskAIDialog: React.FC<Props> = (props: Props) => {
</
Typography
>
</
Typography
>
<
Stack
spacing=
{
2
}
>
<
Stack
spacing=
{
2
}
>
<
FormControl
>
<
FormControl
>
<
FormLabel
>
{
t
(
"ask-ai.label-message-group-name-title"
)
}
</
FormLabel
>
<
Input
<
Input
value=
{
groupName
}
value=
{
groupName
}
onChange=
{
(
e
)
=>
setGroupName
(
e
.
target
.
value
)
}
onChange=
{
(
e
)
=>
setGroupName
(
e
.
target
.
value
)
}
placeholder=
{
t
(
"ask-ai.label-message-group-name-title"
)
}
placeholder=
{
t
(
"ask-ai.label-message-group-name-title"
)
}
/>
/>
</
FormControl
>
</
FormControl
>
<
Typography
>
<
div
className=
"w-full flex justify-end gap-x-2"
>
<
Button
onClick=
{
handleCancel
}
style=
{
{
marginRight
:
"10px"
}
}
>
<
Button
variant=
"plain"
onClick=
{
handleCancel
}
>
{
t
(
"common.cancel"
)
}
{
t
(
"common.cancel"
)
}
</
Button
>
</
Button
>
<
Button
onClick=
{
handleAddMessageGroupDlgConfirm
}
>
{
t
(
"common.confirm"
)
}
</
Button
>
<
Button
onClick=
{
handleAddMessageGroupDlgConfirm
}
>
{
t
(
"common.confirm"
)
}
</
Button
>
</
Typography
>
</
div
>
</
Stack
>
</
Stack
>
</
ModalDialog
>
</
ModalDialog
>
</
Modal
>
</
Modal
>
...
...
web/src/components/Memo.tsx
View file @
2e34ce90
...
@@ -282,7 +282,7 @@ const Memo: React.FC<Props> = (props: Props) => {
...
@@ -282,7 +282,7 @@ const Memo: React.FC<Props> = (props: Props) => {
{
showRelatedMemos
&&
relatedMemoList
.
length
>
0
&&
(
{
showRelatedMemos
&&
relatedMemoList
.
length
>
0
&&
(
<>
<>
<
p
className=
"text-sm mt-4 mb-1 pl-4 opacity-50 flex flex-row items-center"
>
<
p
className=
"text-sm
dark:text-gray-300
mt-4 mb-1 pl-4 opacity-50 flex flex-row items-center"
>
<
Icon
.
Link
className=
"w-4 h-auto mr-1"
/>
<
Icon
.
Link
className=
"w-4 h-auto mr-1"
/>
<
span
>
Related memos
</
span
>
<
span
>
Related memos
</
span
>
</
p
>
</
p
>
...
...
web/src/components/MobileHeader.tsx
View file @
2e34ce90
...
@@ -28,7 +28,7 @@ const MobileHeader = (props: Props) => {
...
@@ -28,7 +28,7 @@ const MobileHeader = (props: Props) => {
},
[
filter
,
shortcuts
]);
},
[
filter
,
shortcuts
]);
return
(
return
(
<
div
className=
"sticky top-0 pt-4 pb-1 mb-1 backdrop-blur
-sm
flex md:hidden flex-row justify-between items-center w-full h-auto flex-nowrap shrink-0 z-2"
>
<
div
className=
"sticky top-0 pt-4 pb-1 mb-1 backdrop-blur
bg-zinc-100 dark:bg-zinc-800 bg-opacity-70
flex md:hidden flex-row justify-between items-center w-full h-auto flex-nowrap shrink-0 z-2"
>
<
div
className=
"flex flex-row justify-start items-center mr-2 shrink-0 overflow-hidden"
>
<
div
className=
"flex flex-row justify-start items-center mr-2 shrink-0 overflow-hidden"
>
<
div
<
div
className=
"flex sm:hidden flex-row justify-center items-center w-6 h-6 mr-1 shrink-0 bg-transparent"
className=
"flex sm:hidden flex-row justify-center items-center w-6 h-6 mr-1 shrink-0 bg-transparent"
...
...
web/src/css/global.css
View file @
2e34ce90
html
,
html
,
body
{
body
{
@apply
text-base
w-full
h-full
dark
:
bg-zinc-800
;
@apply
text-base
w-full
h-full
dark
:
bg-zinc-800
;
font-family
:
-apple-system
,
BlinkMacSystemFont
,
"Segoe UI"
,
Roboto
,
"Helvetica Neue"
,
Arial
,
"PingFang SC"
,
"Noto Sans"
,
"Noto Sans CJK SC"
,
font-family
:
-apple-system
,
BlinkMacSystemFont
,
"Segoe UI"
,
Roboto
,
"Helvetica Neue"
,
Arial
,
"PingFang SC"
,
"Noto Sans"
,
"
Microsoft YaHei UI"
,
"Microsoft YaHei"
,
"WenQuanYi Micro Hei"
,
"Apple Color Emoji"
,
"Segoe UI Emoji"
,
"Segoe UI Symbol"
,
"Noto Color
Emoji"
,
"
Noto Sans CJK SC"
,
"Microsoft YaHei UI"
,
"Microsoft YaHei"
,
"WenQuanYi Micro Hei"
,
"Apple Color Emoji"
,
"Segoe UI
Emoji"
,
sans-serif
;
"Segoe UI Symbol"
,
"Noto Color Emoji"
,
sans-serif
;
}
}
#root
{
#root
{
@apply
w-full
h-full;
@apply
w-full
h-full;
}
}
.button-group
{
display
:
flex
;
gap
:
0
;
/* 按钮之间的间距 */
}
.button-group
>
button
:not
(
:first-child
)
:not
(
:last-child
)
{
border-radius
:
0
;
}
.button-group
>
button
:first-child
{
border-top-right-radius
:
0
;
border-bottom-right-radius
:
0
;
}
.button-group
>
button
:last-child
{
border-bottom-left-radius
:
0
;
border-top-left-radius
:
0
;
}
.button-len-max-150
{
max-width
:
150px
;
/* 按钮的最大宽度 */
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment