diff --git a/.github/workflows/build-client-server-count.yml b/.github/workflows/build-client-server-count.yml index 7f2210f32063..c15a92947b0c 100644 --- a/.github/workflows/build-client-server-count.yml +++ b/.github/workflows/build-client-server-count.yml @@ -149,6 +149,7 @@ jobs: with: pr: ${{fromJson(needs.file-check.outputs.pr)}} run_count: ${{fromJson(needs.file-check.outputs.run_count)}} + ci-test-limited-existing-docker-image: needs: [file-check] @@ -260,39 +261,62 @@ jobs: with: name: cypress-repeat-logs path: app/client + + - name: Download the ci_test_status + uses: actions/download-artifact@v4 + with: + name: ci_test_status + path: app/client - name: Read and Set File Content as ENV Variable id: set-summary-content run: | summary_content=$(cat app/client/cy-repeat-summary.txt | tr '\n' ' ') - echo "summary_content=$summary_content" >> $GITHUB_ENV + echo "summary_content=$summary_content" >> $GITHUB_ENV + + - name: Check CI Test Result + id: check-ci-test + run: | + # Check if the ci_test_failed flag is set + if [ -f app/client/ci_test_status.txt ]; then + if grep -q "ci_test_failed=true" app/client/ci_test_status.txt; then + echo "Tests failed. Please review the test results." + echo "ci_test_failed=true" >> $GITHUB_ENV + else + echo "Tests passed." + echo "ci_test_failed=false" >> $GITHUB_ENV + fi + else + echo "ci_test_status.txt file not found." + echo "ci_test_failed=unknown" >> $GITHUB_ENV + fi - name: Add a comment on the PR with new CI failures - if: needs.ci-test-limited.result != 'success' && needs.file-check.outputs.pr != '0' + if: env.ci_test_failed != 'true' && needs.file-check.outputs.pr != '0' uses: peter-evans/create-or-update-comment@v3 with: issue-number: ${{fromJson(needs.file-check.outputs.pr)}} body: | - Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. - Cypress dashboard: Click here! - The following are new failures, please fix them before merging the PR: ${{env.new_failed_spec_env}} - To know the list of identified flaky tests - Refer here - ``` - ${{ env.summary_content }} - ``` - - - name: Add a comment on the PR when ci-test-limited is success - if: needs.ci-test-limited.result == 'success' && needs.file-check.outputs.pr != '0' + Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. + Cypress dashboard: Click here! + The following are new failures, please fix them before merging the PR: ${{env.new_failed_spec_env}} + To know the list of identified flaky tests - Refer here + ``` + ${{ env.summary_content }} + ``` + + - name: Add a comment on the PR when ci-test-limited is successful + if: env.ci_test_failed == 'true' && needs.file-check.outputs.pr != '0' uses: peter-evans/create-or-update-comment@v3 with: issue-number: ${{fromJson(needs.file-check.outputs.pr)}} body: | - Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. - Cypress dashboard url: Click here! - All cypress tests have passed 🎉🎉🎉 - ``` - ${{ env.summary_content }} - ``` + Workflow run: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>. + Cypress dashboard url: Click here! + All Cypress tests have passed 🎉🎉🎉 + ``` + ${{ env.summary_content }} + ``` - name: Check ci-test-limited set status if: needs.ci-test-limited.result != 'success' @@ -396,6 +420,12 @@ jobs: with: name: cypress-repeat-logs path: app/client + + - name: Download the ci_test_status + uses: actions/download-artifact@v4 + with: + name: ci_test_status + path: app/client - name: Read and Set File Content as ENV Variable id: set-summary-content @@ -403,9 +433,25 @@ jobs: summary_content=$(cat app/client/cy-repeat-summary.txt | tr '\n' ' ') echo "summary_content=$summary_content" >> $GITHUB_ENV + - name: Check CI Test Result + id: check-ci-test + run: | + # Check if the ci_test_failed flag is set + if [ -f app/client/ci_test_status.txt ]; then + if grep -q "ci_test_failed=true" app/client/ci_test_status.txt; then + echo "Tests failed. Please review the test results." + echo "ci_test_failed=true" >> $GITHUB_ENV + else + echo "Tests passed." + echo "ci_test_failed=false" >> $GITHUB_ENV + fi + else + echo "ci_test_status.txt file not found." + echo "ci_test_failed=unknown" >> $GITHUB_ENV + fi - name: Add a comment on the PR with new CI failures - if: needs.ci-test-limited-existing-docker-image.result != 'success' && needs.file-check.outputs.pr != '0' + if: env.ci_test_failed != 'true' && needs.file-check.outputs.pr != '0' uses: peter-evans/create-or-update-comment@v3 with: issue-number: ${{fromJson(needs.file-check.outputs.pr)}} @@ -419,7 +465,7 @@ jobs: ``` - name: Add a comment on the PR when ci-test-limited-existing-docker-image is success - if: needs.ci-test-limited-existing-docker-image.result == 'success' && needs.file-check.outputs.pr != '0' + if: env.ci_test_failed == 'true' && needs.file-check.outputs.pr != '0' uses: peter-evans/create-or-update-comment@v3 with: issue-number: ${{fromJson(needs.file-check.outputs.pr)}} diff --git a/.github/workflows/ci-test-limited-with-count.yml b/.github/workflows/ci-test-limited-with-count.yml index 3399eaddb703..65af0adfb198 100644 --- a/.github/workflows/ci-test-limited-with-count.yml +++ b/.github/workflows/ci-test-limited-with-count.yml @@ -350,12 +350,17 @@ jobs: --spec ${{ env.specs_to_run }} \ --config-file "cypress_ci_custom.config.ts" cat cy-repeat-summary.txt - # Check if "Total Failed: 0" is present + # Define the path for the failure flag file + FAILURE_FLAG_FILE="ci_test_status.txt" + + # Check for test results and store the status in the file if ! grep -q "Total Failed: 0" cy-repeat-summary.txt; then - echo "Tests failed, failing the GitHub Action." - exit 1 # Fails the step if tests failed - fi - + echo "ci_test_failed=true" > "$FAILURE_FLAG_FILE" + else + echo "ci_test_failed=false" > "$FAILURE_FLAG_FILE" + fi + cat "$FAILURE_FLAG_FILE" + - name: Trim number of cypress log files if: failure() run: | @@ -368,9 +373,17 @@ jobs: name: cypress-repeat-logs path: ${{ github.workspace }}/app/client/cy-repeat-summary.txt overwrite: true + + - name: Upload ci_test_status.txt artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: ci_test_status + path: ${{ github.workspace }}/app/client/ci_test_status.txt + overwrite: true - name: Upload failed test cypress logs artifact - if: failure() + if: always() uses: actions/upload-artifact@v4 with: name: cypress-console-logs @@ -386,7 +399,7 @@ jobs: overwrite: true - name: Collect CI container logs - if: failure() + if: always() working-directory: "." run: | mkdir -p ~/dockerlogs @@ -394,7 +407,7 @@ jobs: # Upload docker logs - name: Upload failed test list artifact - if: failure() + if: always() uses: actions/upload-artifact@v4 with: name: dockerlogs @@ -402,13 +415,13 @@ jobs: overwrite: true - name: Rename reports - if: failure() + if: always() run: | mkdir -p ~/results mv ${{ github.workspace }}/app/client/results ~/results - name: Upload cypress report - if: failure() + if: always() uses: actions/upload-artifact@v4 with: name: results-${{github.run_attempt}} @@ -417,13 +430,13 @@ jobs: # Set status = failedtest - name: Set fail if there are test failures - if: failure() + if: always() run: | echo "failedtest" > ~/run_result # Force store previous run result to cache - name: Store the previous run result - if: failure() + if: always() uses: actions/cache/save@v4 with: path: | @@ -433,7 +446,7 @@ jobs: # Upload the log artifact so that it can be used by the test & deploy job in the workflow - name: Upload server logs bundle on failure uses: actions/upload-artifact@v4 - if: failure() + if: always() with: name: server-logs path: app/server/server-logs.log diff --git a/.github/workflows/on-demand-build-docker-image-deploy-preview.yml b/.github/workflows/on-demand-build-docker-image-deploy-preview.yml index 69c3e6a0b911..44cce790ba30 100644 --- a/.github/workflows/on-demand-build-docker-image-deploy-preview.yml +++ b/.github/workflows/on-demand-build-docker-image-deploy-preview.yml @@ -118,6 +118,10 @@ jobs: push-image: needs: [client-build, rts-build, server-build] runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + if: success() steps: # Check out merge commit @@ -176,6 +180,9 @@ jobs: scripts/prepare_server_artifacts.sh fi + - name: Set up Depot CLI + uses: depot/setup-action@v1 + - name: Login to DockerHub uses: docker/login-action@v1 with: @@ -193,11 +200,12 @@ jobs: echo "base_tag=$base_tag" >> $GITHUB_OUTPUT - name: Push to Docker Hub - uses: docker/build-push-action@v4 + uses: depot/build-push-action@v1 with: context: . pull: true push: true + platforms: linux/arm64,linux/amd64 cache-from: ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-${{ vars.EDITION }}:release tags: | ${{ vars.DOCKER_HUB_ORGANIZATION }}/appsmith-dp:${{ vars.EDITION }}-${{ github.event.client_payload.pull_request.number }} diff --git a/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts index 7000e5d226dc..6f2bb3ff6e60 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Anvil/AppTheming/AnvilAppThemingSnapshot_spec.ts @@ -36,17 +36,7 @@ describe( anvilSnapshot.setAccentColor("#0080ff"); }); - it("3. Typography", () => { - anvilSnapshot.setTypography("Inter"); - - anvilSnapshot.matchSnapshotForCanvasMode("AppThemingTypography"); - anvilSnapshot.matchSnapshotForPreviewMode("AppThemingTypography"); - anvilSnapshot.matchSnapshotForDeployMode("AppThemingTypography"); - - anvilSnapshot.setTypography("System Default"); - }); - - it("4. Density", () => { + it("3. Density", () => { ["Tight", "Regular", "Loose"].forEach((density) => { anvilSnapshot.setDensity(density); @@ -58,7 +48,7 @@ describe( }); }); - it("5. Sizing", () => { + it("4. Sizing", () => { ["Small", "Regular", "Big"].forEach((size) => { anvilSnapshot.setSizing(size); @@ -68,7 +58,7 @@ describe( }); }); - it("6. Corners", () => { + it("5. Corners", () => { ["0px", "6px", "20px"].forEach((corner) => { anvilSnapshot.setCorners(corner); @@ -77,15 +67,5 @@ describe( anvilSnapshot.matchSnapshotForDeployMode(`AppThemingCorner${corner}`); }); }); - - it("7. Icon Style", () => { - ["Filled", "Outlined"].forEach((iconStyle) => { - anvilSnapshot.setIconStyle(iconStyle); - - anvilSnapshot.matchSnapshotForCanvasMode(`AppThemingIcon${iconStyle}`); - anvilSnapshot.matchSnapshotForPreviewMode(`AppThemingIcon${iconStyle}`); - anvilSnapshot.matchSnapshotForDeployMode(`AppThemingIcon${iconStyle}`); - }); - }); }, ); diff --git a/app/client/cypress/e2e/Regression/ClientSide/Git/GitAutocommit_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Git/GitAutocommit_spec.ts index fbc7b921c5a3..724e9c72a043 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Git/GitAutocommit_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Git/GitAutocommit_spec.ts @@ -11,7 +11,7 @@ let repoName: string = "TED-testrepo1"; describe( "Git Autocommit", - { tags: ["@tag.Git", "@tag.GitAutocommit"] }, + { tags: ["@tag.Git", "@tag.GitAutocommit", "@tag.excludeForAirgap"] }, function () { it("Check if autocommit progress bar is visible and network requests are properly called", function () { featureFlagIntercept({ diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_1_Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_1_Spec.ts index 2c529e35fd2b..142401c067c9 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_1_Spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/TableV2Filter1_1_Spec.ts @@ -143,10 +143,10 @@ describe( }); it("11. Verify table search includes label and value for table with select column type", () => { + deployMode.NavigateBacktoEditor(); // This flag is turned on to allow the label show in the table select cell content // when this feature is turned on fully, this flag will be removed featureFlagIntercept({ release_table_cell_label_value_enabled: true }); - deployMode.NavigateBacktoEditor(); EditorNavigation.SelectEntityByName("Table1", EntityType.Widget); propPane.EnterJSContext("Table data", demoTableDataForSelect); diff --git a/app/client/cypress/support/Pages/Anvil/AnvilSnapshot.ts b/app/client/cypress/support/Pages/Anvil/AnvilSnapshot.ts index a3c06bec87f0..356e16994c36 100644 --- a/app/client/cypress/support/Pages/Anvil/AnvilSnapshot.ts +++ b/app/client/cypress/support/Pages/Anvil/AnvilSnapshot.ts @@ -19,7 +19,6 @@ export class AnvilSnapshot { densityOptions: "[data-testid=t--anvil-theme-settings-density] > div", sizingOptions: "[data-testid=t--anvil-theme-settings-sizing] > div", cornersOptions: "[data-testid=t--anvil-theme-settings-corners] > div", - iconStyleOptions: "[data-testid=t--anvil-theme-settings-icon-style] > div", }; /** @@ -163,14 +162,6 @@ export class AnvilSnapshot { }); }; - public setIconStyle = (iconStyle: string) => { - this.updateThemeOption(() => { - cy.get(this.locators.iconStyleOptions) - .contains(iconStyle) - .click({ force: true }); - }); - }; - public updateThemeOption = (callback: () => void) => { this.appSettings.OpenAppSettings(); this.appSettings.GoToThemeSettings(); diff --git a/app/client/packages/design-system/theming/src/hooks/src/index.ts b/app/client/packages/design-system/theming/src/hooks/src/index.ts index f8d6541c98fa..7c0c56efa008 100644 --- a/app/client/packages/design-system/theming/src/hooks/src/index.ts +++ b/app/client/packages/design-system/theming/src/hooks/src/index.ts @@ -3,3 +3,5 @@ export * from "./useSpacing"; export * from "./useTypography"; export * from "./useTheme"; export * from "./useCssTokens"; +export * from "./useIconDensity"; +export * from "./useIconSizing"; diff --git a/app/client/packages/design-system/theming/src/hooks/src/useCssTokens.tsx b/app/client/packages/design-system/theming/src/hooks/src/useCssTokens.tsx index 56deb1ea41db..b5e30df72fe3 100644 --- a/app/client/packages/design-system/theming/src/hooks/src/useCssTokens.tsx +++ b/app/client/packages/design-system/theming/src/hooks/src/useCssTokens.tsx @@ -1,22 +1,21 @@ import { css } from "@emotion/css"; -import { useEffect, useState } from "react"; -import { cssRule, getTypographyClassName } from "../../utils"; +import { useMemo } from "react"; +import { objectKeys } from "@appsmith/utils"; import type { Theme } from "../../theme"; -import type { FontFamily, ThemeToken, Typography } from "../../token"; +import type { ThemeToken, Typography } from "../../token"; +import { cssRule, getTypographyClassName } from "../../utils"; -const fontFamilyCss = (fontFamily?: FontFamily) => { +const fontFamilyCss = () => { const fontFamilyCss = - fontFamily && fontFamily !== "System Default" - ? `${fontFamily}, sans-serif` - : "-apple-system, 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Ubuntu', sans-serif"; + "-apple-system, 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Ubuntu', sans-serif"; return `font-family: ${fontFamilyCss}; --font-family: ${fontFamilyCss}`; }; const getTypographyCss = (typography: Typography) => { return css` - ${Object.keys(typography).reduce((prev, key) => { + ${objectKeys(typography).reduce((prev, key) => { const currentKey = key as keyof Typography; const { after, before, fontSize, lineHeight } = typography[currentKey]; return ( @@ -55,47 +54,39 @@ const getColorCss = (color: ThemeToken["color"]) => { }; export function useCssTokens(props: Theme) { - const { color, colorMode, fontFamily, typography, ...restTokens } = props; + const { color, colorMode, typography, ...restTokens } = props; - const [colorClassName, setColorClassName] = useState(); - const [colorModeClassName, setColorModeClassName] = useState(); - const [fontFamilyClassName, setFontFamilyClassName] = useState(); - const [typographyClassName, setTypographyClassName] = useState(); - const [providerClassName, setProviderClassName] = useState(); - - useEffect(() => { + const colorClassName = useMemo(() => { if (color != null) { - setColorClassName(css` + return css` ${getColorCss(color)} - `); + `; } }, [color]); - useEffect(() => { + const typographyClassName = useMemo(() => { if (typography != null) { - setTypographyClassName(css` + return css` ${getTypographyCss(typography)} - `); + `; } }, [typography]); - useEffect(() => { - setFontFamilyClassName(css` - ${fontFamilyCss(fontFamily)} - `); - }, [fontFamily]); + const fontFamilyClassName = css` + ${fontFamilyCss()} + `; - useEffect(() => { - setProviderClassName(css` + const providerClassName = useMemo(() => { + return css` ${cssRule(restTokens)}; - `); + `; }, [restTokens]); - useEffect(() => { + const colorModeClassName = useMemo(() => { if (colorMode != null) { - setColorModeClassName(css` + return css` color-scheme: ${colorMode}; - `); + `; } }, [colorMode]); diff --git a/app/client/packages/design-system/theming/src/hooks/src/useIconDensity.tsx b/app/client/packages/design-system/theming/src/hooks/src/useIconDensity.tsx index 8d4b3dad0e1b..e8e170a1994c 100644 --- a/app/client/packages/design-system/theming/src/hooks/src/useIconDensity.tsx +++ b/app/client/packages/design-system/theming/src/hooks/src/useIconDensity.tsx @@ -1,23 +1,17 @@ -import { useEffect, useState } from "react"; -import type { IconDensity, TokenObj } from "../../token"; +import { useMemo } from "react"; +import type { IconDensity } from "../../token"; export const useIconDensity = (density: IconDensity, userDensity = 1) => { - const [strokeWidth, setStrokeWidth] = useState(); - - useEffect(() => { + const strokeWidth = useMemo(() => { switch (true) { case userDensity < 1: - setStrokeWidth(density.tight); - break; + return density.tight; case userDensity === 1: - setStrokeWidth(density.regular); - break; + return density.regular; case userDensity > 1: - setStrokeWidth(density.loose); - break; + return density.loose; default: - setStrokeWidth(density.regular); - break; + return density.regular; } }, [userDensity, density]); diff --git a/app/client/packages/design-system/theming/src/hooks/src/useIconSizing.tsx b/app/client/packages/design-system/theming/src/hooks/src/useIconSizing.tsx index 51ddc60c7a71..02c1da490056 100644 --- a/app/client/packages/design-system/theming/src/hooks/src/useIconSizing.tsx +++ b/app/client/packages/design-system/theming/src/hooks/src/useIconSizing.tsx @@ -1,23 +1,17 @@ -import { useEffect, useState } from "react"; -import type { IconSizing, TokenObj } from "../../token"; +import { useMemo } from "react"; +import type { IconSizing } from "../../token"; export const useIconSizing = (sizing: IconSizing, userSizing = 1) => { - const [iconSize, setIconSize] = useState(); - - useEffect(() => { + const iconSize = useMemo(() => { switch (true) { case userSizing < 1: - setIconSize(sizing.small); - break; + return sizing.small; case userSizing === 1: - setIconSize(sizing.regular); - break; + return sizing.regular; case userSizing > 1: - setIconSize(sizing.big); - break; + return sizing.big; default: - setIconSize(sizing.regular); - break; + return sizing.regular; } }, [userSizing, sizing]); diff --git a/app/client/packages/design-system/theming/src/hooks/src/useSizing.tsx b/app/client/packages/design-system/theming/src/hooks/src/useSizing.tsx index 047ed16f138a..14cde9b5f7ec 100644 --- a/app/client/packages/design-system/theming/src/hooks/src/useSizing.tsx +++ b/app/client/packages/design-system/theming/src/hooks/src/useSizing.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useMemo } from "react"; import { calculateScales } from "./calculateScales"; import type { TokenObj, TokenScaleConfig } from "../../token"; @@ -8,7 +8,7 @@ export const getSizing = ( userDensity = 1, userSizing = 1, count = 200, -) => { +): TokenObj => { const { userDensityRatio = 1, userSizingRatio = 1, V, ...rest } = sizing; const ratio = userDensity * userDensityRatio + userSizing * userSizingRatio; @@ -35,11 +35,9 @@ export const useSizing = ( userDensity = 1, userSizing = 1, ) => { - const [sizing, setSizing] = useState(); - - useEffect(() => { - setSizing(getSizing(config, userDensity, userSizing)); - }, [userDensity, userSizing, config]); + const sizing = useMemo(() => { + return getSizing(config, userDensity, userSizing); + }, [config, userDensity, userSizing]); return { sizing, diff --git a/app/client/packages/design-system/theming/src/hooks/src/useSpacing.tsx b/app/client/packages/design-system/theming/src/hooks/src/useSpacing.tsx index 7cbc7bb65868..aeba5c8907b6 100644 --- a/app/client/packages/design-system/theming/src/hooks/src/useSpacing.tsx +++ b/app/client/packages/design-system/theming/src/hooks/src/useSpacing.tsx @@ -1,7 +1,7 @@ -import { useEffect, useState } from "react"; +import { useMemo } from "react"; import { calculateScales } from "./calculateScales"; -import type { TokenObj, TokenScaleConfig } from "../../token"; +import type { TokenScaleConfig } from "../../token"; export const getSpacing = ( spacing: TokenScaleConfig, @@ -36,16 +36,13 @@ export const useSpacing = ( userDensity = 1, userSizing = 1, ) => { - const [outerSpacing, setOuterSpacing] = useState(); - const [innerSpacing, setInnerSpacing] = useState(); + const outerSpacing = useMemo(() => { + return getSpacing(outerSpacingConfig, userDensity, userSizing); + }, [outerSpacingConfig, userDensity, userSizing]); - useEffect(() => { - setOuterSpacing(getSpacing(outerSpacingConfig, userDensity, userSizing)); - }, [userDensity, userSizing, outerSpacingConfig]); - - useEffect(() => { - setInnerSpacing(getSpacing(innerSpacingConfig, userDensity, userSizing)); - }, [userDensity, userSizing, innerSpacingConfig]); + const innerSpacing = useMemo(() => { + return getSpacing(innerSpacingConfig, userDensity, userSizing); + }, [innerSpacingConfig, userDensity, userSizing]); return { outerSpacing, diff --git a/app/client/packages/design-system/theming/src/hooks/src/useTheme.tsx b/app/client/packages/design-system/theming/src/hooks/src/useTheme.tsx index 908f268f56eb..7cee09699342 100644 --- a/app/client/packages/design-system/theming/src/hooks/src/useTheme.tsx +++ b/app/client/packages/design-system/theming/src/hooks/src/useTheme.tsx @@ -1,12 +1,16 @@ import Color from "colorjs.io"; -import { useEffect, useState } from "react"; +import { useMemo } from "react"; import { TokensAccessor, defaultTokens, tokensConfigs } from "../../token"; -import { useSizing, useSpacing, useTypography } from "./"; +import { + useSizing, + useSpacing, + useTypography, + useIconSizing, + useIconDensity, +} from "./"; import type { ColorMode } from "../../color"; -import type { TokenSource, FontFamily, IconStyle } from "../../token"; -import { useIconDensity } from "./useIconDensity"; -import { useIconSizing } from "./useIconSizing"; +import type { TokenSource } from "../../token"; const tokensAccessor = new TokensAccessor({ ...(defaultTokens as TokenSource), @@ -16,18 +20,14 @@ export interface UseThemeProps { seedColor?: string; colorMode?: ColorMode; borderRadius?: string; - fontFamily?: FontFamily; userDensity?: number; userSizing?: number; - iconStyle?: IconStyle; } export function useTheme(props: UseThemeProps = {}) { const { borderRadius, colorMode = "light", - fontFamily, - iconStyle = "outlined", seedColor, userDensity = 1, userSizing = 1, @@ -42,168 +42,83 @@ export function useTheme(props: UseThemeProps = {}) { ); const { typography } = useTypography( tokensConfigs.typography, - fontFamily, userDensity, userSizing, ); - const { iconSize } = useIconSizing(tokensConfigs.icon.sizing, userSizing); - const { strokeWidth } = useIconDensity( tokensConfigs.icon.density, userDensity, ); - const [theme, setTheme] = useState(tokensAccessor.getAllTokens); - - useEffect(() => { - if (colorMode) { - tokensAccessor.updateColorMode(colorMode); + const theme = useMemo(() => { + // Color mode + tokensAccessor.updateColorMode(colorMode); - setTheme((prevState) => { - return { - ...prevState, - ...tokensAccessor.getColors(), - colorMode: tokensAccessor.getColorMode(), - }; - }); - } - }, [colorMode]); - - useEffect(() => { + // Border radius if (borderRadius != null) { tokensAccessor.updateBorderRadiusElevation({ ...defaultTokens.borderRadiusElevation, base: borderRadius, }); - - setTheme((prevState) => { - return { - ...prevState, - ...tokensAccessor.getBorderRadiusElevation(), - }; - }); } - }, [borderRadius]); - useEffect(() => { + // Seed color if (seedColor != null) { - let color; - try { - color = Color.parse(seedColor); + Color.parse(seedColor); + tokensAccessor.updateSeedColor(seedColor); } catch (error) { // eslint-disable-next-line no-console console.error(error); - return; // Prevent further execution if color parsing fails - } - - if (color != null) { - tokensAccessor.updateSeedColor(seedColor); - - setTheme((prevState) => { - return { - ...prevState, - ...tokensAccessor.getColors(), - }; - }); } } - }, [seedColor]); - useEffect(() => { - // Check typography, as fontFamily may be undefined + // Typography if (typography != null) { - tokensAccessor.updateFontFamily(fontFamily); tokensAccessor.updateTypography(typography); - - setTheme((prevState) => { - return { - ...prevState, - typography: tokensAccessor.getTypography(), - fontFamily: tokensAccessor.getFontFamily(), - }; - }); - } - }, [typography, fontFamily]); - - useEffect(() => { - if (sizing) { - tokensAccessor.updateSizing(sizing); - - setTheme((prevState) => { - return { - ...prevState, - ...tokensAccessor.getSizing(), - }; - }); - } - }, [sizing]); - - useEffect(() => { - if (outerSpacing) { - tokensAccessor.updateOuterSpacing(outerSpacing); - - setTheme((prevState) => { - return { - ...prevState, - ...tokensAccessor.getOuterSpacing(), - }; - }); - } - }, [outerSpacing]); - - useEffect(() => { - if (innerSpacing) { - tokensAccessor.updateInnerSpacing(innerSpacing); - - setTheme((prevState) => { - return { - ...prevState, - ...tokensAccessor.getInnerSpacing(), - }; - }); } - }, [innerSpacing]); - useEffect(() => { - if (iconStyle) { - tokensAccessor.updateIconStyle(iconStyle); + // Sizing + tokensAccessor.updateSizing(sizing); - setTheme((prevState) => { - return { - ...prevState, - iconStyle: tokensAccessor.getIconStyle(), - }; - }); - } - }, [iconStyle]); + // Spacing + tokensAccessor.updateOuterSpacing(outerSpacing); + tokensAccessor.updateInnerSpacing(innerSpacing); - useEffect(() => { + // Icon size if (iconSize != null) { tokensAccessor.updateIconSize(iconSize); - - setTheme((prevState) => { - return { - ...prevState, - ...tokensAccessor.getIconSize(), - }; - }); } - }, [iconSize]); - useEffect(() => { + // Stroke width if (strokeWidth != null) { tokensAccessor.updateStrokeWidth(strokeWidth); - - setTheme((prevState) => { - return { - ...prevState, - ...tokensAccessor.getStrokeWidth(), - }; - }); } - }, [strokeWidth]); - return { theme, setTheme }; + return { + ...tokensAccessor.getAllTokens(), + ...tokensAccessor.getColors(), + colorMode: tokensAccessor.getColorMode(), + ...tokensAccessor.getBorderRadiusElevation(), + typography: tokensAccessor.getTypography(), + ...tokensAccessor.getSizing(), + ...tokensAccessor.getOuterSpacing(), + ...tokensAccessor.getInnerSpacing(), + ...tokensAccessor.getIconSize(), + ...tokensAccessor.getStrokeWidth(), + }; + }, [ + colorMode, + borderRadius, + seedColor, + typography, + sizing, + outerSpacing, + innerSpacing, + iconSize, + strokeWidth, + ]); + + return { theme }; } diff --git a/app/client/packages/design-system/theming/src/hooks/src/useTypography.tsx b/app/client/packages/design-system/theming/src/hooks/src/useTypography.tsx index 21cfaaa61258..05380e99d634 100644 --- a/app/client/packages/design-system/theming/src/hooks/src/useTypography.tsx +++ b/app/client/packages/design-system/theming/src/hooks/src/useTypography.tsx @@ -1,29 +1,20 @@ -import { useEffect, useState } from "react"; -import { FONT_METRICS, TYPOGRAPHY_VARIANTS } from "../../token"; +import { useMemo } from "react"; import { calculateScales } from "./calculateScales"; import { createStyleObject } from "@capsizecss/core"; import appleSystem from "@capsizecss/metrics/appleSystem"; import type { - FontFamily, Typography, TypographyVariantMetric, TokenScaleConfig, } from "../../token"; - -const getFontMetrics = (fontFamily?: FontFamily) => { - return !Boolean(fontFamily) || - fontFamily == null || - fontFamily === "System Default" - ? appleSystem - : FONT_METRICS[fontFamily]; -}; +import { TYPOGRAPHY_VARIANTS } from "../../token/src/types"; +import { objectKeys } from "@appsmith/utils"; export const getTypography = ( typography: TokenScaleConfig, userDensity = 1, userSizing = 1, - fontFamily?: FontFamily, ) => { const { userDensityRatio = 1, userSizingRatio = 1, V, ...rest } = typography; const ratio = userDensity * userDensityRatio + userSizing * userSizingRatio; @@ -37,7 +28,7 @@ export const getTypography = ( const typographyStyle = createStyleObject({ capHeight: currentValue, lineGap: currentValue, - fontMetrics: getFontMetrics(fontFamily), + fontMetrics: appleSystem, }); metrics.push({ @@ -46,12 +37,13 @@ export const getTypography = ( before: typographyStyle["::before"], after: typographyStyle["::after"], }); + return metrics; }, [], ); - return Object.keys(TYPOGRAPHY_VARIANTS).reduce((prev, current, index) => { + return objectKeys(TYPOGRAPHY_VARIANTS).reduce((prev, current, index) => { return { ...prev, [current]: styles[index], @@ -61,15 +53,12 @@ export const getTypography = ( export const useTypography = ( config: TokenScaleConfig, - fontFamily?: FontFamily, userDensity = 1, userSizing = 1, ) => { - const [typography, setTypography] = useState(null); - - useEffect(() => { - setTypography(getTypography(config, userDensity, userSizing, fontFamily)); - }, [userDensity, userSizing, fontFamily, config]); + const typography = useMemo(() => { + return getTypography(config, userDensity, userSizing); + }, [config, userDensity, userSizing]); return { typography, diff --git a/app/client/packages/design-system/theming/src/theme/src/ThemeProvider.tsx b/app/client/packages/design-system/theming/src/theme/src/ThemeProvider.tsx index 8dddca61b732..1cfb2f1bb634 100644 --- a/app/client/packages/design-system/theming/src/theme/src/ThemeProvider.tsx +++ b/app/client/packages/design-system/theming/src/theme/src/ThemeProvider.tsx @@ -20,7 +20,7 @@ export const ThemeProvider = (props: ThemeProviderProps) => { fontFamilyClassName, providerClassName, typographyClassName, - } = useCssTokens({ ...theme }); + } = useCssTokens(theme); return ( diff --git a/app/client/packages/design-system/theming/src/theme/src/types.ts b/app/client/packages/design-system/theming/src/theme/src/types.ts index e7d56e2af57a..f2972c47453b 100644 --- a/app/client/packages/design-system/theming/src/theme/src/types.ts +++ b/app/client/packages/design-system/theming/src/theme/src/types.ts @@ -1,18 +1,12 @@ -import type { CSSProperties } from "react"; import type { ReactNode } from "react"; +import type { CSSProperties } from "react"; + import type { ColorMode } from "../../color"; -import type { - FontFamily, - Typography, - ThemeToken, - IconStyle, -} from "../../token"; +import type { Typography, ThemeToken } from "../../token"; export type Theme = ThemeToken & { typography?: Typography; - fontFamily?: FontFamily; colorMode?: ColorMode; - iconStyle?: IconStyle; }; export interface ThemeProviderProps { diff --git a/app/client/packages/design-system/theming/src/token/src/TokensAccessor.ts b/app/client/packages/design-system/theming/src/token/src/TokensAccessor.ts index 5e2c14d3d726..05c3bcbfb310 100644 --- a/app/client/packages/design-system/theming/src/token/src/TokensAccessor.ts +++ b/app/client/packages/design-system/theming/src/token/src/TokensAccessor.ts @@ -7,9 +7,7 @@ import type { TokenObj, TokenSource, TokenType, - FontFamily, Typography, - IconStyle, } from "./types"; export class TokensAccessor { @@ -20,12 +18,10 @@ export class TokensAccessor { private borderWidth?: TokenObj; private opacity?: TokenObj; private typography?: Typography; - private fontFamily?: FontFamily; private outerSpacing?: TokenObj; private innerSpacing?: TokenObj; private sizing?: TokenObj; private zIndex?: TokenObj; - private iconStyle?: IconStyle; private strokeWidth?: TokenObj; private iconSize?: TokenObj; @@ -34,9 +30,7 @@ export class TokensAccessor { borderWidth, boxShadow, colorMode, - fontFamily, iconSize, - iconStyle, innerSpacing, opacity, outerSpacing, @@ -52,21 +46,15 @@ export class TokensAccessor { this.boxShadow = boxShadow; this.borderWidth = borderWidth; this.opacity = opacity; - this.fontFamily = fontFamily; this.sizing = sizing; this.outerSpacing = outerSpacing; this.innerSpacing = innerSpacing; this.typography = typography; this.zIndex = zIndex; - this.iconStyle = iconStyle; this.strokeWidth = strokeWidth; this.iconSize = iconSize; } - updateFontFamily = (fontFamily?: FontFamily) => { - this.fontFamily = fontFamily; - }; - updateTypography = (typography: Typography) => { this.typography = typography; }; @@ -120,10 +108,6 @@ export class TokensAccessor { this.sizing = sizing; }; - updateIconStyle = (iconStyle: IconStyle) => { - this.iconStyle = iconStyle; - }; - updateStrokeWidth = (strokeWidth: TokenObj) => { this.strokeWidth = strokeWidth; }; @@ -135,7 +119,6 @@ export class TokensAccessor { getAllTokens = () => { return { typography: this.getTypography(), - fontFamily: this.getFontFamily(), ...this.getOuterSpacing(), ...this.getInnerSpacing(), ...this.getSizing(), @@ -148,7 +131,6 @@ export class TokensAccessor { ...this.getStrokeWidth(), ...this.getIconSize(), colorMode: this.getColorMode(), - iconStyle: this.getIconStyle(), }; }; @@ -156,10 +138,6 @@ export class TokensAccessor { return this.typography; }; - getFontFamily = () => { - return this.fontFamily; - }; - getColors = () => { if (this.seedColor == null) return {} as ThemeToken; @@ -237,10 +215,6 @@ export class TokensAccessor { return this.colorMode; }; - getIconStyle = () => { - return this.iconStyle; - }; - getStrokeWidth = () => { if (this.strokeWidth == null) return {} as ThemeToken; diff --git a/app/client/packages/design-system/theming/src/token/src/types.ts b/app/client/packages/design-system/theming/src/token/src/types.ts index e94859a4ab3c..5a457153f690 100644 --- a/app/client/packages/design-system/theming/src/token/src/types.ts +++ b/app/client/packages/design-system/theming/src/token/src/types.ts @@ -1,17 +1,3 @@ -import arial from "@capsizecss/metrics/arial"; -import inter from "@capsizecss/metrics/inter"; -import rubik from "@capsizecss/metrics/rubik"; -import roboto from "@capsizecss/metrics/roboto"; -import ubuntu from "@capsizecss/metrics/ubuntu"; -import poppins from "@capsizecss/metrics/poppins"; -import segoeUI from "@capsizecss/metrics/segoeUI"; -import openSans from "@capsizecss/metrics/openSans"; -import notoSans from "@capsizecss/metrics/notoSans"; -import montserrat from "@capsizecss/metrics/montserrat"; -import nunitoSans from "@capsizecss/metrics/nunitoSans12pt"; -import appleSystem from "@capsizecss/metrics/appleSystem"; -import BlinkMacSystemFont from "@capsizecss/metrics/blinkMacSystemFont"; - import type { ColorMode, ColorTypes } from "../../color"; export type ThemeToken = { @@ -44,12 +30,10 @@ export interface TokenSource { boxShadow?: TokenObj; borderWidth?: TokenObj; opacity?: TokenObj; - fontFamily?: FontFamily; zIndex?: TokenObj; sizing?: TokenObj; outerSpacing?: TokenObj; innerSpacing?: TokenObj; - iconStyle?: IconStyle; strokeWidth?: TokenObj; iconSize?: TokenObj; } @@ -80,22 +64,6 @@ export interface TokenScaleConfig { userDensityRatio?: number; } -export const FONT_METRICS = { - Poppins: poppins, - Inter: inter, - Roboto: roboto, - Rubik: rubik, - Ubuntu: ubuntu, - "Noto Sans": notoSans, - "Open Sans": openSans, - Montserrat: montserrat, - "Nunito Sans": nunitoSans, - Arial: arial, - "-apple-system": appleSystem, - BlinkMacSystemFont: BlinkMacSystemFont, - "Segoe UI": segoeUI, -} as const; - // we use "as const" here because we need to iterate by variants export const TYPOGRAPHY_VARIANTS = { footnote: "footnote", @@ -118,8 +86,6 @@ export const TYPOGRAPHY_FONT_WEIGHTS = { 900: 900, } as const; -export type FontFamily = keyof typeof FONT_METRICS | "System Default"; - export interface TypographyVariantMetric { fontSize: string; lineHeight: string; @@ -139,8 +105,6 @@ export type Typography = { [key in keyof typeof TYPOGRAPHY_VARIANTS]: TypographyVariantMetric; }; -export type IconStyle = "outlined" | "filled"; - export const APP_MAX_WIDTH = { Unlimited: "UNLIMITED", Large: "LARGE", diff --git a/app/client/packages/design-system/widgets/src/components/Icon/src/Icon.tsx b/app/client/packages/design-system/widgets/src/components/Icon/src/Icon.tsx index ef7276806bdd..9dbcb8efb551 100644 --- a/app/client/packages/design-system/widgets/src/components/Icon/src/Icon.tsx +++ b/app/client/packages/design-system/widgets/src/components/Icon/src/Icon.tsx @@ -1,6 +1,5 @@ import type { Component, Ref } from "react"; import React, { Suspense, forwardRef, lazy, useMemo } from "react"; -import { useThemeContext } from "@appsmith/wds-theming"; import { ICONS } from "./icons"; import styles from "./styles.module.css"; @@ -8,25 +7,13 @@ import type { IconProps } from "./types"; import { FallbackIcon } from "./FallbackIcon"; const _Icon = (props: IconProps, ref: Ref) => { - const { color, filled: filledProp, name, size = "medium", ...rest } = props; - const theme = useThemeContext(); - const filled = theme.iconStyle === "filled" || filledProp; + const { color, name, size = "medium", ...rest } = props; const Icon = useMemo(() => { const pascalName = ICONS[name]; return lazy(async () => import("@tabler/icons-react").then((module) => { - if (Boolean(filled)) { - const filledVariant = `${pascalName}Filled`; - - if (filledVariant in module) { - return { - default: module[filledVariant] as React.ComponentType, - }; - } - } - if (pascalName in module) { return { default: module[pascalName] as React.ComponentType, @@ -36,7 +23,7 @@ const _Icon = (props: IconProps, ref: Ref) => { return { default: FallbackIcon }; }), ); - }, [name, filled]); + }, [name]); return ( ( - - - - - ), -}; - export const AllIcons: Story = { render: () => (
name !== "createReactComponent") - .filter((name) => !name.endsWith("Filled")) .map((name) => { content += `\n "${kebabCase(name).replace("icon-", "")}": "${name}",`; }); diff --git a/app/client/packages/storybook/.storybook/addons/theming/ThemingPopup.tsx b/app/client/packages/storybook/.storybook/addons/theming/ThemingPopup.tsx index 390763d83558..f7ebfb17dde9 100644 --- a/app/client/packages/storybook/.storybook/addons/theming/ThemingPopup.tsx +++ b/app/client/packages/storybook/.storybook/addons/theming/ThemingPopup.tsx @@ -61,8 +61,6 @@ export const ThemingPopup: React.FC = ({ leftShift, onClose }) => { setBorderRadius={(value) => updateGlobal("borderRadius", value)} seedColor={globals.seedColor} setSeedColor={(value) => updateGlobal("seedColor", value)} - fontFamily={globals.fontFamily} - setFontFamily={(value) => updateGlobal("fontFamily", value)} userDensity={globals.userDensity} userSizing={globals.userSizing} setUserDensity={(value) => updateGlobal("userDensity", value)} diff --git a/app/client/packages/storybook/.storybook/decorators/theming.tsx b/app/client/packages/storybook/.storybook/decorators/theming.tsx index 23b58e53a837..9efe5e3cd2ec 100644 --- a/app/client/packages/storybook/.storybook/decorators/theming.tsx +++ b/app/client/packages/storybook/.storybook/decorators/theming.tsx @@ -18,7 +18,6 @@ export const theming = (Story, args) => { seedColor: args.globals.seedColor, colorMode: args.parameters.colorMode || args.globals.colorMode, borderRadius: args.globals.borderRadius, - fontFamily: args.globals.fontFamily, userDensity: args.globals.userDensity, userSizing: args.globals.userSizing, }); diff --git a/app/client/packages/storybook/src/components/ThemeSettings.tsx b/app/client/packages/storybook/src/components/ThemeSettings.tsx index f9b227934de0..b3d77aa3b3db 100644 --- a/app/client/packages/storybook/src/components/ThemeSettings.tsx +++ b/app/client/packages/storybook/src/components/ThemeSettings.tsx @@ -2,7 +2,6 @@ import { Form } from "@storybook/components"; import React, { useCallback } from "react"; import { Flex, Text } from "@appsmith/wds"; import { ColorControl, BooleanControl, RangeControl } from "@storybook/blocks"; -import { FONT_METRICS } from "@appsmith/wds-theming"; import styled from "styled-components"; import { debounce } from "lodash"; import { AddonPanel } from "@storybook/components"; @@ -42,12 +41,10 @@ interface ThemeSettingsProps { export const ThemeSettings = ({ borderRadius, direction = "column", - fontFamily, isDarkMode, seedColor, setBorderRadius, setDarkMode, - setFontFamily, setSeedColor, setUserDensity, setUserSizing, @@ -106,36 +103,6 @@ export const ThemeSettings = ({ )} - {setFontFamily && ( - - Font Family - setFontFamily(e.target.value)} - size="100%" - title="Font Family" - > - - {Object.keys(FONT_METRICS) - .filter((item) => { - return ( - [ - "-apple-system", - "BlinkMacSystemFont", - "Segoe UI", - ].includes(item) === false - ); - }) - .map((font) => ( - - ))} - - - )} - {setUserDensity && ( Density diff --git a/app/client/src/PluginActionEditor/PluginActionContext.tsx b/app/client/src/PluginActionEditor/PluginActionContext.tsx index 0b99f9dc363d..21c76f6c8985 100644 --- a/app/client/src/PluginActionEditor/PluginActionContext.tsx +++ b/app/client/src/PluginActionEditor/PluginActionContext.tsx @@ -20,7 +20,7 @@ interface PluginActionContextType { const PluginActionContext = createContext(null); interface ChildrenProps { - children: ReactNode[]; + children: ReactNode | ReactNode[]; } export const PluginActionContextProvider = ( diff --git a/app/client/src/PluginActionEditor/PluginActionEditor.tsx b/app/client/src/PluginActionEditor/PluginActionEditor.tsx index d8e480403064..bfdad62b30b7 100644 --- a/app/client/src/PluginActionEditor/PluginActionEditor.tsx +++ b/app/client/src/PluginActionEditor/PluginActionEditor.tsx @@ -18,7 +18,7 @@ import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper"; import { Text } from "@appsmith/ads"; interface ChildrenProps { - children: React.ReactNode[]; + children: React.ReactNode | React.ReactNode[]; } const PluginActionEditor = (props: ChildrenProps) => { diff --git a/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx b/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx index ee90ecc960ba..75ee4dc86bd2 100644 --- a/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx +++ b/app/client/src/PluginActionEditor/components/PluginActionToolbar.tsx @@ -1,11 +1,12 @@ import React from "react"; import { IDEToolbar } from "IDE"; -import { Button, Tooltip } from "@appsmith/ads"; -import { modText } from "../../utils/helpers"; +import { Button, Menu, MenuContent, MenuTrigger, Tooltip } from "@appsmith/ads"; +import { modText } from "utils/helpers"; interface PluginActionToolbarProps { runOptions?: React.ReactNode; children?: React.ReactNode[] | React.ReactNode; + menuContent?: React.ReactNode[] | React.ReactNode; } const PluginActionToolbar = (props: PluginActionToolbarProps) => { @@ -29,12 +30,19 @@ const PluginActionToolbar = (props: PluginActionToolbarProps) => { size="sm" startIcon="settings-2-line" /> -