Skip to content

Commit

Permalink
Merge branch 'main' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
reearth-app[bot] committed Dec 19, 2024
2 parents c09abee + 07186df commit f13da3c
Show file tree
Hide file tree
Showing 55 changed files with 590 additions and 247 deletions.
13 changes: 0 additions & 13 deletions .github/workflows/build_server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,6 @@ jobs:
echo "platforms=$PLATFORMS" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
- name: Fetch reearth-cms-web
uses: dawidd6/action-download-artifact@v6
with:
github_token: ${{secrets.GITHUB_TOKEN}}
workflow: ci_web.yml
workflow_conclusion: success
branch: main
name: reearth-cms-web
path: server
check_artifacts: true
search_artifacts: true
- name: Extract reearth-cms-web
run: tar -xvf server/reearth-cms-web.tar.gz; mv reearth-cms-web server/web; ls
- name: Build and push docker image
uses: docker/build-push-action@v6
with:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/build_worker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ jobs:
- name: Build and push docker image
uses: docker/build-push-action@v6
with:
context: ./worker
context: .
file: ./worker/Dockerfile
platforms: ${{ steps.options.outputs.platforms }}
push: true
build-args: VERSION=${{ steps.options.outputs.version }}
Expand Down
11 changes: 11 additions & 0 deletions server/internal/usecase/gateway/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/reearth/reearth-cms/server/pkg/file"
"github.com/reearth/reearthx/i18n"
"github.com/reearth/reearthx/rerror"
"github.com/samber/lo"
)

var (
Expand Down Expand Up @@ -43,6 +44,16 @@ type IssueUploadAssetParam struct {
Cursor string
}

func init() {
// mime package depends on the OS, so adding the requited mime types to make sure about the results in different OS
lo.Must0(mime.AddExtensionType(".zip", "application/zip"))
lo.Must0(mime.AddExtensionType(".7z", "application/x-7z-compressed"))
lo.Must0(mime.AddExtensionType(".gz", "application/gzip"))
lo.Must0(mime.AddExtensionType(".bz2", "application/x-bzip2"))
lo.Must0(mime.AddExtensionType(".tar", "application/x-tar"))
lo.Must0(mime.AddExtensionType(".rar", "application/vnd.rar"))
}

func (p IssueUploadAssetParam) ContentType() string {
return mime.TypeByExtension(path.Ext(p.Filename))
}
Expand Down
45 changes: 45 additions & 0 deletions server/internal/usecase/gateway/file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package gateway

import (
"testing"
"time"

"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)

func TestIssueUploadAssetParam_ContentType(t *testing.T) {
tests := []struct {
name string
fields IssueUploadAssetParam
want string
}{
{
name: "zip file",
fields: IssueUploadAssetParam{
UUID: uuid.New().String(),
Filename: "filename.zip",
ContentLength: 1,
ExpiresAt: time.Now(),
Cursor: "",
},
want: "application/zip",
},
{
name: "7zip file",
fields: IssueUploadAssetParam{
UUID: uuid.New().String(),
Filename: "filename.7z",
ContentLength: 1,
ExpiresAt: time.Now(),
Cursor: "",
},
want: "application/x-7z-compressed",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, tt.fields.ContentType())
})
}
}
5 changes: 3 additions & 2 deletions web/e2e/common/notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { Page } from "@playwright/test";
import { expect } from "@reearth-cms/e2e/utils";

export async function closeNotification(page: Page, isSuccess = true) {
const text = isSuccess ? /successfully|/i : "input: ";
await expect(page.getByRole("alert").last()).toContainText(text);
const text = isSuccess ? "check-circle" : "close-circle";
await expect(page.getByRole("alert").last().getByRole("img")).toHaveAttribute("aria-label", text);
await page
.locator(".ant-notification-notice")
.last()
.locator(".ant-notification-notice-close")
.click();
await expect(page.getByRole("alert").last()).toBeHidden();
}
3 changes: 0 additions & 3 deletions web/e2e/project/item/fields/asset.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,6 @@ test("Asset field editing has succeeded", async ({ page }) => {
await expect(page.locator(".css-7g0azd").nth(1)).toContainText(uploadFileName_1);
await page.getByRole("button", { name: "plus New" }).click();
await page.getByRole("button", { name: "Save" }).click();
await closeNotification(page, false);
await page.getByRole("button", { name: "delete" }).nth(2).click();
await page.getByRole("button", { name: "Save" }).click();
await closeNotification(page);
await page.getByLabel("Back").click();
await page.getByRole("button", { name: "x2" }).click();
Expand Down
1 change: 1 addition & 0 deletions web/e2e/project/item/fields/geometryObject.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ test("GeometryObject field editing has succeeded", async ({ page }) => {
await page.getByLabel("Description(optional)").click();
await page.getByLabel("Description(optional)").fill("new geometryObject1 description");
await page.getByLabel("Support multiple values").check();
await expect(page.getByLabel("Use as title")).toBeHidden();
await page.getByRole("tab", { name: "Validation" }).click();
await page.getByLabel("Make field required").check();
await page.getByLabel("Set field as unique").check();
Expand Down
2 changes: 2 additions & 0 deletions web/e2e/project/item/fields/group.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ test("Group field creating and updating has succeeded", async ({ page }) => {
await page.getByRole("button", { name: "Save" }).click();
await closeNotification(page);
await page.locator("span").filter({ hasText: "Schema" }).click();
await page.getByRole("tab", { name: "Meta Data" }).click();
await page.getByRole("menuitem", { name: "e2e group name" }).locator("span").click();
await page.getByRole("img", { name: "ellipsis" }).locator("svg").click();
await page.getByLabel("Display name").click();
Expand Down Expand Up @@ -206,6 +207,7 @@ test("Group field editing has succeeded", async ({ page }) => {
await page.getByLabel("Description(optional)").click();
await page.getByLabel("Description(optional)").fill("new group1 description");
await page.getByLabel("Support multiple values").check();
await expect(page.getByLabel("Use as title")).toBeHidden();
await page.getByRole("button", { name: "OK" }).click();
await closeNotification(page);
await page.getByText("Content").click();
Expand Down
3 changes: 1 addition & 2 deletions web/e2e/project/item/fields/markdown.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,7 @@ test("Markdown field editing has succeeded", async ({ page }) => {
await page.getByRole("button", { name: "delete" }).first().click();
await expect(page.getByText("Please input field!")).toBeVisible();
await page.getByRole("button", { name: "plus New" }).click();
await page.getByRole("button", { name: "Save" }).click();
await closeNotification(page, false);
await expect(page.getByRole("button", { name: "Save" })).toBeDisabled();
await page.locator("div:nth-child(1) > .css-1ago99h").click();
await page.getByRole("textbox").fill("text");
await page.getByRole("button", { name: "plus New" }).click();
Expand Down
2 changes: 2 additions & 0 deletions web/e2e/project/item/fields/reference.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ test("One-way reference field creating and updating has succeeded", async ({ pag
await expect(
page.locator("label").filter({ hasText: "Support multiple values" }).locator("span").nth(1),
).toBeDisabled();
await expect(page.getByLabel("Use as title")).toBeHidden();
await page.getByRole("tab", { name: "Validation" }).click();
await page.getByLabel("Make field required").check();
await page.getByLabel("Set field as unique").check();
Expand Down Expand Up @@ -187,6 +188,7 @@ test("Two-way reference field editing has succeeded", async ({ page }) => {
await expect(
page.locator("label").filter({ hasText: "Support multiple values" }).locator("span").nth(1),
).toBeDisabled();
await expect(page.getByLabel("Use as title")).toBeHidden();
await page.getByRole("tab", { name: "Validation" }).click();
await page.getByLabel("Make field required").check();
await expect(
Expand Down
3 changes: 1 addition & 2 deletions web/e2e/project/item/fields/text.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ test("Text field editing has succeeded", async ({ page }) => {
await expect(page.getByText("Please input field!")).toBeVisible();
await page.getByRole("button", { name: "plus New" }).click();
await expect(page.getByText("/ 5")).toBeVisible();
await page.getByRole("button", { name: "Save" }).click();
await closeNotification(page, false);
await expect(page.getByRole("button", { name: "Save" })).toBeDisabled();
await page.getByRole("textbox").nth(0).click();
await page.getByRole("textbox").nth(0).fill("text");
await page.getByRole("button", { name: "plus New" }).click();
Expand Down
3 changes: 1 addition & 2 deletions web/e2e/project/item/fields/textarea.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,7 @@ test("Textarea field editing has succeeded", async ({ page }) => {
await page.getByRole("button", { name: "delete" }).first().click();
await expect(page.getByText("Please input field!")).toBeVisible();
await page.getByRole("button", { name: "plus New" }).click();
await page.getByRole("button", { name: "Save" }).click();
await closeNotification(page, false);
await expect(page.getByRole("button", { name: "Save" })).toBeDisabled();
await page.getByRole("textbox").nth(0).click();
await page.getByRole("textbox").nth(0).fill("text");
await page.getByRole("button", { name: "plus New" }).click();
Expand Down
1 change: 1 addition & 0 deletions web/e2e/project/item/metadata/boolean.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ test("Boolean metadata creating and updating has succeeded", async ({ page }) =>
"boolean1 description",
);
await expect(page.getByLabel("Support multiple values")).not.toBeChecked();
await expect(page.getByLabel("Use as title")).toBeHidden();
await page.getByRole("tab", { name: "Validation" }).click();
await expect(page.getByLabel("Make field required")).toBeDisabled();
await expect(page.getByLabel("Set field as unique")).toBeDisabled();
Expand Down
1 change: 1 addition & 0 deletions web/e2e/project/item/metadata/checkbox.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ test("Checkbox metadata creating and updating has succeeded", async ({ page }) =
"checkbox1 description",
);
await expect(page.getByLabel("Support multiple values")).not.toBeChecked();
await expect(page.getByLabel("Use as title")).toBeHidden();
await page.getByRole("tab", { name: "Validation" }).click();
await expect(page.getByLabel("Make field required")).toBeDisabled();
await expect(page.getByLabel("Set field as unique")).toBeDisabled();
Expand Down
1 change: 1 addition & 0 deletions web/e2e/project/item/metadata/date.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ test("Date metadata creating and updating has succeeded", async ({ page }) => {
"date1 description",
);
await expect(page.getByLabel("Support multiple values")).not.toBeChecked();
await expect(page.getByLabel("Use as title")).toBeHidden();
await page.getByRole("tab", { name: "Validation" }).click();
await expect(page.getByLabel("Make field required")).not.toBeChecked();
await expect(page.getByLabel("Set field as unique")).not.toBeChecked();
Expand Down
3 changes: 2 additions & 1 deletion web/e2e/project/item/metadata/tag.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ test("Tag metadata creating and updating has succeeded", async ({ page }) => {
await expect(page.getByText("Tag1", { exact: true })).toBeVisible();
await expect(page.getByText("Tag2")).toBeVisible();
await expect(page.getByLabel("Support multiple values")).not.toBeChecked();
await expect(page.getByLabel("Use as title")).toBeHidden();
await page.getByRole("tab", { name: "Validation" }).click();
await expect(page.getByLabel("Make field required")).not.toBeChecked();
await expect(page.getByLabel("Set field as unique")).not.toBeChecked();
Expand All @@ -72,13 +73,13 @@ test("Tag metadata creating and updating has succeeded", async ({ page }) => {
await expect(page.getByText("Tag1", { exact: true })).toBeVisible();
await page.getByRole("cell").getByLabel("edit").locator("svg").click();
await page.getByLabel("close-circle").locator("svg").click();
await closeNotification(page);
await page.getByLabel("tag1").click();
await page
.locator("div")
.filter({ hasText: /^Tag2$/ })
.nth(1)
.click();
await page.getByText("tag1", { exact: true }).click();
await closeNotification(page);
await expect(page.locator("#root").getByText("Tag2")).toBeVisible();
await page.getByLabel("Back").click();
Expand Down
5 changes: 5 additions & 0 deletions web/e2e/project/item/metadata/text.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ test("Text metadata creating and updating has succeeded", async ({ page }) => {
"text1 description",
);
await expect(page.getByLabel("Support multiple values")).not.toBeChecked();
await expect(page.getByLabel("Use as title")).toBeHidden();
await page.getByRole("tab", { name: "Validation" }).click();
await expect(page.getByLabel("Set maximum length")).toBeEmpty();
await expect(page.getByLabel("Make field required")).not.toBeChecked();
Expand Down Expand Up @@ -131,6 +132,10 @@ test("Text metadata editing has succeeded", async ({ page }) => {
await expect(page.getByRole("main")).toContainText("new text1 description");
await expect(page.getByRole("textbox").nth(0)).toHaveValue("text2");
await expect(page.getByRole("textbox").nth(1)).toHaveValue("text1");
await page.getByLabel("new text1(unique)").click();
await page.getByLabel("new text1(unique)").fill("text22");
await expect(page.getByRole("button", { name: "Save" })).toBeDisabled();
await page.getByLabel("new text1(unique)").fill("text2");

await page.getByRole("button", { name: "Save" }).click();
await closeNotification(page);
Expand Down
4 changes: 3 additions & 1 deletion web/e2e/project/item/metadata/update.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ test("Updating metadata added later from table has succeeded", async ({ page })
await closeNotification(page);
await page.getByRole("switch").click();
await closeNotification(page);
await page.getByRole("switch").click();
await closeNotification(page);
await page.getByRole("cell").getByLabel("edit").locator("svg").click();
await expect(page.getByLabel("boolean")).toHaveAttribute("aria-checked", "false");
await expect(page.getByLabel("boolean")).toHaveAttribute("aria-checked", "true");
});

test("Updating metadata added later from edit page has succeeded", async ({ page }) => {
Expand Down
1 change: 1 addition & 0 deletions web/e2e/project/item/metadata/url.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ test("Url metadata creating and updating has succeeded", async ({ page }) => {
await expect(page.getByLabel("Settings").locator("#key")).toHaveValue("url1");
await expect(page.getByLabel("Settings").locator("#description")).toHaveValue("url1 description");
await expect(page.getByLabel("Support multiple values")).not.toBeChecked();
await expect(page.getByLabel("Use as title")).toBeHidden();
await page.getByRole("tab", { name: "Validation" }).click();
await expect(page.getByLabel("Make field required")).not.toBeChecked();
await expect(page.getByLabel("Set field as unique")).not.toBeChecked();
Expand Down
3 changes: 2 additions & 1 deletion web/src/components/atoms/Form/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Form, FormInstance } from "antd";
import { Rule } from "antd/lib/form";
import { Rule, RuleObject } from "antd/lib/form";
import { FormItemProps } from "antd/lib/form/FormItem";
import { FormItemLabelProps } from "antd/lib/form/FormItemLabel";
import { FieldError, ValidateErrorEntity } from "rc-field-form/lib/interface";
Expand All @@ -12,5 +12,6 @@ export type {
FieldError,
FormInstance,
Rule,
RuleObject,
ValidateErrorEntity,
};
45 changes: 25 additions & 20 deletions web/src/components/atoms/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,35 @@ import { runes } from "runes2";
export type { SearchProps } from "antd/lib/input";

type Props = {
value?: string;
isError?: boolean;
} & InputProps;

const Input = forwardRef<InputRef, Props>(({ value, isError, maxLength, ...props }, ref) => {
const status = useMemo(() => {
if (isError || (maxLength && value && runes(value).length > maxLength)) {
return "error";
}
}, [isError, maxLength, value]);
const Input = forwardRef<InputRef, Props>(
({ value, isError, maxLength, required, ...props }, ref) => {
const status = useMemo(() => {
if (
isError ||
(required && !value) ||
(maxLength && typeof value === "string" && value && runes(value).length > maxLength)
) {
return "error";
}
}, [isError, maxLength, required, value]);

return (
<AntDInput
count={{
max: maxLength,
strategy: txt => runes(txt).length,
}}
value={value}
ref={ref}
status={status}
{...props}
/>
);
});
return (
<AntDInput
count={{
max: maxLength,
strategy: txt => runes(txt).length,
}}
value={value}
ref={ref}
status={status}
{...props}
/>
);
},
);

export default Input;
export type { InputProps };
17 changes: 11 additions & 6 deletions web/src/components/atoms/Markdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@ import { runes } from "runes2";
import TextArea, { TextAreaProps } from "@reearth-cms/components/atoms/TextArea";

type Props = {
value?: string;
onChange?: (value: string) => void;
isError?: boolean;
} & TextAreaProps;

const MarkdownInput: React.FC<Props> = ({ value, onChange, ...props }) => {
const [showMD, setShowMD] = useState(true);
const textareaRef = useRef<HTMLInputElement>(null);
const isError = useMemo(
() => (props.maxLength && value ? runes(value).length > props.maxLength : false),
[props.maxLength, value],
);
const isError = useMemo(() => {
if (props.isError || (props.required && !value)) {
return true;
} else if (props.maxLength && typeof value === "string" && value) {
return runes(value).length > props.maxLength;
} else {
return false;
}
}, [props, value]);

const handleBlur = useCallback((event: FocusEvent<HTMLTextAreaElement>) => {
event.stopPropagation();
Expand Down Expand Up @@ -46,7 +51,7 @@ const MarkdownInput: React.FC<Props> = ({ value, onChange, ...props }) => {
showCount
/>
<StyledMD disabled={props.disabled} isError={isError} hidden={!showMD} onClick={handleClick}>
<ReactMarkdown>{value}</ReactMarkdown>
<ReactMarkdown>{typeof value === "string" ? value : undefined}</ReactMarkdown>
</StyledMD>
</MarkdownWrapper>
);
Expand Down
Loading

0 comments on commit f13da3c

Please sign in to comment.