From 2e34ce90a118b7b04b45fa93fe7fa177dc28697c Mon Sep 17 00:00:00 2001 From: boojack Date: Sat, 27 May 2023 09:09:41 +0800 Subject: [PATCH] chore: upgrade version `0.13.1` (#1754) --- .github/workflows/e2e-test.yml | 66 --------------- server/resource.go | 12 +-- server/version/version.go | 4 +- .../prod/0.12/04__resource_public_id.sql | 1 - store/memo.go | 5 ++ web/e2e-tests/001-setup.spec.ts | 13 --- web/e2e-tests/002-basic.spec.ts | 37 --------- web/e2e-tests/fixtures.ts | 2 - web/e2e-tests/utils.ts | 52 ------------ web/package.json | 1 - web/playwright.config.ts | 19 ----- web/pnpm-lock.yaml | 20 ----- web/src/components/AskAIDialog.tsx | 82 +++++++------------ web/src/components/Memo.tsx | 2 +- web/src/components/MobileHeader.tsx | 2 +- web/src/css/global.css | 33 +------- 16 files changed, 48 insertions(+), 303 deletions(-) delete mode 100644 .github/workflows/e2e-test.yml delete mode 100644 web/e2e-tests/001-setup.spec.ts delete mode 100644 web/e2e-tests/002-basic.spec.ts delete mode 100644 web/e2e-tests/fixtures.ts delete mode 100644 web/e2e-tests/utils.ts delete mode 100644 web/playwright.config.ts diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml deleted file mode 100644 index 80a454c1..00000000 --- a/.github/workflows/e2e-test.yml +++ /dev/null @@ -1,66 +0,0 @@ -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) diff --git a/server/resource.go b/server/resource.go index 5578c4ba..91426fe2 100644 --- a/server/resource.go +++ b/server/resource.go @@ -123,6 +123,7 @@ func (s *Server) registerResourceRoutes(g *echo.Group) { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to unmarshal storage service id").SetInternal(err) } } + publicID := common.GenUUID() if storageServiceID == api.DatabaseStorage { fileBytes, err := io.ReadAll(sourceFile) @@ -326,11 +327,12 @@ func (s *Server) registerResourceRoutes(g *echo.Group) { 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)) } + } - thumbnailPath := path.Join(s.Profile.Data, thumbnailImagePath, resource.PublicID) - if err := os.Remove(thumbnailPath); err != nil { - log.Warn(fmt.Sprintf("failed to delete local thumbnail with path %s", thumbnailPath), zap.Error(err)) - } + 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 { + log.Warn(fmt.Sprintf("failed to delete local thumbnail with path %s", thumbnailPath), zap.Error(err)) } resourceDelete := &api.ResourceDelete{ @@ -434,7 +436,7 @@ func (s *Server) registerResourcePublicRoutes(g *echo.Group) { if c.QueryParam("thumbnail") == "1" && common.HasPrefixes(resource.Type, "image/png", "image/jpeg") { 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) if err != nil { log.Warn(fmt.Sprintf("failed to get or generate local thumbnail with path %s", thumbnailPath), zap.Error(err)) diff --git a/server/version/version.go b/server/version/version.go index 726786c7..12e94c73 100644 --- a/server/version/version.go +++ b/server/version/version.go @@ -9,10 +9,10 @@ import ( // Version is the service current released version. // Semantic versioning: https://semver.org/ -var Version = "0.13.0" +var Version = "0.13.1" // DevVersion is the service current development version. -var DevVersion = "0.13.0" +var DevVersion = "0.13.1" func GetCurrentVersion(mode string) string { if mode == "dev" || mode == "demo" { diff --git a/store/db/migration/prod/0.12/04__resource_public_id.sql b/store/db/migration/prod/0.12/04__resource_public_id.sql index 4a30f2cd..ef08d02a 100644 --- a/store/db/migration/prod/0.12/04__resource_public_id.sql +++ b/store/db/migration/prod/0.12/04__resource_public_id.sql @@ -3,7 +3,6 @@ ALTER TABLE ADD 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); UPDATE diff --git a/store/memo.go b/store/memo.go index e9abe4a1..fe18f793 100644 --- a/store/memo.go +++ b/store/memo.go @@ -6,6 +6,7 @@ import ( "fmt" "strconv" "strings" + "time" "github.com/usememos/memos/common" ) @@ -90,6 +91,10 @@ func (s *Store) CreateMemo(ctx context.Context, create *MemoMessage) (*MemoMessa } defer tx.Rollback() + if create.CreatedTs == 0 { + create.CreatedTs = time.Now().Unix() + } + query := ` INSERT INTO memo ( creator_id, diff --git a/web/e2e-tests/001-setup.spec.ts b/web/e2e-tests/001-setup.spec.ts deleted file mode 100644 index b7e05017..00000000 --- a/web/e2e-tests/001-setup.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -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"); - }); -}); diff --git a/web/e2e-tests/002-basic.spec.ts b/web/e2e-tests/002-basic.spec.ts deleted file mode 100644 index c82ab684..00000000 --- a/web/e2e-tests/002-basic.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -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(); - }); -}); diff --git a/web/e2e-tests/fixtures.ts b/web/e2e-tests/fixtures.ts deleted file mode 100644 index 2713e151..00000000 --- a/web/e2e-tests/fixtures.ts +++ /dev/null @@ -1,2 +0,0 @@ -const baseHost = "http://localhost:5230"; -export { baseHost }; diff --git a/web/e2e-tests/utils.ts b/web/e2e-tests/utils.ts deleted file mode 100644 index c8ff0f4f..00000000 --- a/web/e2e-tests/utils.ts +++ /dev/null @@ -1,52 +0,0 @@ -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 }; diff --git a/web/package.json b/web/package.json index b17f0df9..35681a4e 100644 --- a/web/package.json +++ b/web/package.json @@ -35,7 +35,6 @@ "zustand": "^4.3.6" }, "devDependencies": { - "@playwright/test": "^1.32.2", "@types/lodash-es": "^4.17.5", "@types/node": "^18.0.3", "@types/qs": "^6.9.7", diff --git a/web/playwright.config.ts b/web/playwright.config.ts deleted file mode 100644 index 619c7075..00000000 --- a/web/playwright.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -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"] }, - }, - ], -}); diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index de6fee09..10a2f3b1 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -78,9 +78,6 @@ dependencies: version: 4.3.6(react@18.2.0) devDependencies: - '@playwright/test': - specifier: ^1.32.2 - version: 1.32.2 '@types/lodash-es': specifier: ^4.17.5 version: 4.17.5 @@ -784,17 +781,6 @@ packages: '@nodelib/fs.scandir': 2.1.5 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: resolution: {integrity: sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==} dev: false @@ -2944,12 +2930,6 @@ packages: dev: 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): resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} engines: {node: '>=10.0.0'} diff --git a/web/src/components/AskAIDialog.tsx b/web/src/components/AskAIDialog.tsx index 0d9f532b..d0a1bfd6 100644 --- a/web/src/components/AskAIDialog.tsx +++ b/web/src/components/AskAIDialog.tsx @@ -1,17 +1,4 @@ -import { - Button, - FormControl, - FormLabel, - Input, - Menu, - MenuItem, - Modal, - ModalClose, - ModalDialog, - Stack, - Textarea, - Typography, -} from "@mui/joy"; +import { Button, FormControl, Input, Modal, ModalClose, ModalDialog, Stack, Textarea, Typography } from "@mui/joy"; import React, { useEffect, useState } from "react"; import { toast } from "react-hot-toast"; import { useTranslation } from "react-i18next"; @@ -19,11 +6,11 @@ import * as api from "@/helpers/api"; import useLoading from "@/hooks/useLoading"; import { marked } from "@/labs/marked"; import { useMessageStore } from "@/store/zustand/message"; +import { defaultMessageGroup, MessageGroup, useMessageGroupStore } from "@/store/zustand/message-group"; import Icon from "./Icon"; import { generateDialog } from "./Dialog"; import showSettingDialog from "./SettingDialog"; -import { defaultMessageGroup, MessageGroup, useMessageGroupStore } from "@/store/zustand/message-group"; -import { PlusIcon, Trash2Icon } from "lucide-react"; +import Selector from "./kit/Selector"; type Props = DialogProps; @@ -92,26 +79,21 @@ const AskAIDialog: React.FC = (props: Props) => { }); }; - const [anchorEl, setAnchorEl] = useState(null); - const handleMenuOpen = (event: React.SyntheticEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleMenuClose = () => { - setAnchorEl(null); - }; - const handleOptionSelect = (option: MessageGroup) => { - setMessageGroup(option); - setAnchorEl(null); + const handleMessageGroupSelect = (value: string) => { + const messageGroup = messageGroupList.find((group) => group.messageStorageId === value); + if (messageGroup) { + setMessageGroup(messageGroup); + } }; - const [isAddMessageGroupDlgOpen, setIsAddMessageGroupDlgOpen] = useState(false); + const [isAddMessageGroupDialogOpen, setIsAddMessageGroupDialogOpen] = useState(false); const [groupName, setGroupName] = useState(""); const messageGroupStore = useMessageGroupStore(); const messageGroupList = messageGroupStore.groupList; const handleOpenDialog = () => { - setIsAddMessageGroupDlgOpen(true); + setIsAddMessageGroupDialogOpen(true); }; const handleRemoveDialog = () => { @@ -119,7 +101,7 @@ const AskAIDialog: React.FC = (props: Props) => { }; const handleCloseDialog = () => { - setIsAddMessageGroupDlgOpen(false); + setIsAddMessageGroupDialogOpen(false); setGroupName(""); }; @@ -142,29 +124,24 @@ const AskAIDialog: React.FC = (props: Props) => {

- {t("ask-ai.title")} - - - - + {t("ask-ai.title")} + + ({ text: item.name, value: item.messageStorageId }))} + value={messageGroup.messageStorageId} + handleValueChanged={handleMessageGroupSelect} + /> + +

- - handleOptionSelect(defaultMessageGroup)}>{defaultMessageGroup.name} - {messageGroupList.map((messageGroup, index) => ( - handleOptionSelect(messageGroup)}> - {messageGroup.name} - - ))} - - + @@ -172,19 +149,18 @@ const AskAIDialog: React.FC = (props: Props) => { - {t("ask-ai.label-message-group-name-title")} setGroupName(e.target.value)} placeholder={t("ask-ai.label-message-group-name-title")} /> - - - +
diff --git a/web/src/components/Memo.tsx b/web/src/components/Memo.tsx index ce0da25b..d2cb2bc3 100644 --- a/web/src/components/Memo.tsx +++ b/web/src/components/Memo.tsx @@ -282,7 +282,7 @@ const Memo: React.FC = (props: Props) => { {showRelatedMemos && relatedMemoList.length > 0 && ( <> -

+

Related memos

diff --git a/web/src/components/MobileHeader.tsx b/web/src/components/MobileHeader.tsx index 3889f90e..e654c08c 100644 --- a/web/src/components/MobileHeader.tsx +++ b/web/src/components/MobileHeader.tsx @@ -28,7 +28,7 @@ const MobileHeader = (props: Props) => { }, [filter, shortcuts]); return ( -
+
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; -}