├── .eslintignore ├── .forceignore ├── .github └── workflows │ ├── pr-develop-branch.yml │ ├── push-develop-branch.yml │ └── push-master-branch.yml ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── README.md ├── config └── project-scratch-def.json ├── force-app └── main │ └── default │ ├── aura │ ├── .eslintrc.json │ └── pageTemplate_2_7_3 │ │ ├── pageTemplate_2_7_3.cmp │ │ ├── pageTemplate_2_7_3.cmp-meta.xml │ │ ├── pageTemplate_2_7_3.css │ │ ├── pageTemplate_2_7_3.design │ │ └── pageTemplate_2_7_3.svg │ ├── classes │ ├── ChangePasswordController.cls │ ├── ChangePasswordController.cls-meta.xml │ ├── ChangePasswordControllerTest.cls │ ├── ChangePasswordControllerTest.cls-meta.xml │ ├── CommunitiesLandingController.cls │ ├── CommunitiesLandingController.cls-meta.xml │ ├── CommunitiesLandingControllerTest.cls │ ├── CommunitiesLandingControllerTest.cls-meta.xml │ ├── CommunitiesLoginController.cls │ ├── CommunitiesLoginController.cls-meta.xml │ ├── CommunitiesLoginControllerTest.cls │ ├── CommunitiesLoginControllerTest.cls-meta.xml │ ├── CommunitiesSelfRegConfirmController.cls │ ├── CommunitiesSelfRegConfirmController.cls-meta.xml │ ├── CommunitiesSelfRegConfirmControllerTest.cls │ ├── CommunitiesSelfRegConfirmControllerTest.cls-meta.xml │ ├── CommunitiesSelfRegController.cls │ ├── CommunitiesSelfRegController.cls-meta.xml │ ├── CommunitiesSelfRegControllerTest.cls │ ├── CommunitiesSelfRegControllerTest.cls-meta.xml │ ├── ForgotPasswordController.cls │ ├── ForgotPasswordController.cls-meta.xml │ ├── ForgotPasswordControllerTest.cls │ ├── ForgotPasswordControllerTest.cls-meta.xml │ ├── HeroDetailsPositionCustomPicklist.cls │ ├── HeroDetailsPositionCustomPicklist.cls-meta.xml │ ├── MyProfilePageController.cls │ ├── MyProfilePageController.cls-meta.xml │ ├── MyProfilePageControllerTest.cls │ ├── MyProfilePageControllerTest.cls-meta.xml │ ├── OrderController.cls │ ├── OrderController.cls-meta.xml │ ├── PagedResult.cls │ ├── PagedResult.cls-meta.xml │ ├── ProductController.cls │ ├── ProductController.cls-meta.xml │ ├── ProductRecordInfoController.cls │ ├── ProductRecordInfoController.cls-meta.xml │ ├── SiteLoginController.cls │ ├── SiteLoginController.cls-meta.xml │ ├── SiteLoginControllerTest.cls │ ├── SiteLoginControllerTest.cls-meta.xml │ ├── SiteRegisterController.cls │ ├── SiteRegisterController.cls-meta.xml │ ├── SiteRegisterControllerTest.cls │ ├── SiteRegisterControllerTest.cls-meta.xml │ ├── TestOrderController.cls │ ├── TestOrderController.cls-meta.xml │ ├── TestProductController.cls │ ├── TestProductController.cls-meta.xml │ ├── UltimateClass.cls │ ├── UltimateClass.cls-meta.xml │ ├── UltimateClassTests.cls │ └── UltimateClassTests.cls-meta.xml │ ├── components │ ├── SiteFooter.component │ ├── SiteFooter.component-meta.xml │ ├── SiteHeader.component │ ├── SiteHeader.component-meta.xml │ ├── SiteLogin.component │ ├── SiteLogin.component-meta.xml │ ├── SitePoweredBy.component │ └── SitePoweredBy.component-meta.xml │ ├── lwc │ ├── .eslintrc.json │ ├── accountMap │ │ ├── accountMap.html │ │ ├── accountMap.js │ │ └── accountMap.js-meta.xml │ ├── createCase │ │ ├── createCase.css │ │ ├── createCase.html │ │ ├── createCase.js │ │ └── createCase.js-meta.xml │ ├── errorPanel │ │ ├── errorPanel.js │ │ ├── errorPanel.js-meta.xml │ │ └── templates │ │ │ ├── inlineMessage.html │ │ │ └── noDataIllustration.html │ ├── hero │ │ ├── hero.css │ │ ├── hero.html │ │ ├── hero.js │ │ └── hero.js-meta.xml │ ├── heroDetails │ │ ├── heroDetails.css │ │ ├── heroDetails.html │ │ ├── heroDetails.js │ │ └── heroDetails.js-meta.xml │ ├── ldsUtils │ │ ├── ldsUtils.js │ │ └── ldsUtils.js-meta.xml │ ├── orderBuilder │ │ ├── orderBuilder.css │ │ ├── orderBuilder.html │ │ ├── orderBuilder.js │ │ └── orderBuilder.js-meta.xml │ ├── orderItemTile │ │ ├── orderItemTile.css │ │ ├── orderItemTile.html │ │ ├── orderItemTile.js │ │ └── orderItemTile.js-meta.xml │ ├── paginator │ │ ├── paginator.css │ │ ├── paginator.html │ │ ├── paginator.js │ │ └── paginator.js-meta.xml │ ├── placeholder │ │ ├── placeholder.css │ │ ├── placeholder.html │ │ ├── placeholder.js │ │ └── placeholder.js-meta.xml │ ├── productCard │ │ ├── productCard.css │ │ ├── productCard.html │ │ ├── productCard.js │ │ └── productCard.js-meta.xml │ ├── productFilter │ │ ├── productFilter.css │ │ ├── productFilter.html │ │ ├── productFilter.js │ │ └── productFilter.js-meta.xml │ ├── productListItem │ │ ├── productListItem.css │ │ ├── productListItem.html │ │ ├── productListItem.js │ │ └── productListItem.js-meta.xml │ ├── productTile │ │ ├── productTile.css │ │ ├── productTile.html │ │ ├── productTile.js │ │ └── productTile.js-meta.xml │ ├── productTileList │ │ ├── productTileList.css │ │ ├── productTileList.html │ │ ├── productTileList.js │ │ └── productTileList.js-meta.xml │ └── similarProducts │ │ ├── similarProducts.css │ │ ├── similarProducts.html │ │ ├── similarProducts.js │ │ └── similarProducts.js-meta.xml │ ├── pages │ ├── AnswersHome.page │ ├── AnswersHome.page-meta.xml │ ├── BandwidthExceeded.page │ ├── BandwidthExceeded.page-meta.xml │ ├── ChangePassword.page │ ├── ChangePassword.page-meta.xml │ ├── CommunitiesLanding.page │ ├── CommunitiesLanding.page-meta.xml │ ├── CommunitiesLogin.page │ ├── CommunitiesLogin.page-meta.xml │ ├── CommunitiesSelfReg.page │ ├── CommunitiesSelfReg.page-meta.xml │ ├── CommunitiesSelfRegConfirm.page │ ├── CommunitiesSelfRegConfirm.page-meta.xml │ ├── CommunitiesTemplate.page │ ├── CommunitiesTemplate.page-meta.xml │ ├── Exception.page │ ├── Exception.page-meta.xml │ ├── FileNotFound.page │ ├── FileNotFound.page-meta.xml │ ├── ForgotPassword.page │ ├── ForgotPassword.page-meta.xml │ ├── ForgotPasswordConfirm.page │ ├── ForgotPasswordConfirm.page-meta.xml │ ├── IdeasHome.page │ ├── IdeasHome.page-meta.xml │ ├── InMaintenance.page │ ├── InMaintenance.page-meta.xml │ ├── MyProfilePage.page │ ├── MyProfilePage.page-meta.xml │ ├── SiteLogin.page │ ├── SiteLogin.page-meta.xml │ ├── SiteRegister.page │ ├── SiteRegister.page-meta.xml │ ├── SiteRegisterConfirm.page │ ├── SiteRegisterConfirm.page-meta.xml │ ├── SiteTemplate.page │ ├── SiteTemplate.page-meta.xml │ ├── StdExceptionTemplate.page │ ├── StdExceptionTemplate.page-meta.xml │ ├── Unauthorized.page │ ├── Unauthorized.page-meta.xml │ ├── UnderConstruction.page │ └── UnderConstruction.page-meta.xml │ └── staticresources │ ├── SiteSamples.resource-meta.xml │ ├── SiteSamples │ ├── SiteStyles.css │ └── img │ │ ├── clock.png │ │ ├── construction.png │ │ ├── force_logo.png │ │ ├── maintenance.png │ │ ├── poweredby.png │ │ ├── tools.png │ │ ├── unauthorized.png │ │ └── warning.png │ ├── bike_assets.resource-meta.xml │ └── bike_assets │ ├── CyclingGrass.jpg │ ├── commuter.png │ ├── enthusiast.png │ ├── logo.svg │ └── racer.png ├── jest.config.js ├── manifest └── package.xml ├── package.json ├── parsePR.js ├── pull_request_template.md ├── scripts ├── apex │ └── hello.apex └── soql │ └── account.soql └── sfdx-project.json /.eslintignore: -------------------------------------------------------------------------------- 1 | **/lwc/**/*.css 2 | **/lwc/**/*.html 3 | **/lwc/**/*.json 4 | **/lwc/**/*.svg 5 | **/lwc/**/*.xml 6 | **/aura/**/*.auradoc 7 | **/aura/**/*.cmp 8 | **/aura/**/*.css 9 | **/aura/**/*.design 10 | **/aura/**/*.evt 11 | **/aura/**/*.json 12 | **/aura/**/*.svg 13 | **/aura/**/*.tokens 14 | **/aura/**/*.xml 15 | **/aura/**/*.app 16 | .sfdx 17 | -------------------------------------------------------------------------------- /.forceignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status 2 | # More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm 3 | # 4 | 5 | package.xml 6 | 7 | # LWC configuration files 8 | **/jsconfig.json 9 | **/.eslintrc.json 10 | 11 | # LWC Jest 12 | **/__tests__/** -------------------------------------------------------------------------------- /.github/workflows/pr-develop-branch.yml: -------------------------------------------------------------------------------- 1 | # Unique name for this workflow 2 | name: Validate PR on develop branch 3 | 4 | # Definition when the workflow should run 5 | on: 6 | # The workflow will run whenever an event happens on a pull request 7 | pull_request: 8 | # The events are that a PR is opened, or when a commit is pushed 9 | # to a branch that has an existing pull request 10 | types: [opened, synchronize] 11 | # The branches filter allows to specify that this workflow should only 12 | # run if the branch name is "develop". This way we prevent this workflow 13 | # from running when PRs are opened on other branches 14 | branches: [ develop ] 15 | # We only care about changes to the force-app directory, which is the 16 | # root directory of the sfdx project. This prevents the job from running 17 | # when changing non-salesforce files (like this yml file). 18 | paths: 19 | - 'force-app/**' 20 | 21 | 22 | # Jobs to be executed when the above conditions are met 23 | jobs: 24 | # This is the name of the job. You can give it whatever name you want 25 | validate-deployment-on-develop-org: 26 | # As mentioned in the blog post, this job runs inside a VM. Here we 27 | # can specify which OS this VM should run on. 28 | # In this case, we are going to run our commands on the latest version 29 | # of ubuntu 30 | runs-on: ubuntu-latest 31 | if: ${{ github.actor != 'dependabot[bot]' }} 32 | steps: 33 | # Now we install nodejs in the VM, and specify version 14 34 | - uses: actions/setup-node@v3 35 | with: 36 | node-version: '14' 37 | 38 | # The idea is that the VM can access your remote repository 39 | # because your repository is an sfdx project. 40 | # This is a default action that allows us to enter the root 41 | # directory of the repository 42 | 43 | # Make sure to specify fetch-depth:0. This allows us to 44 | # access previous commits that have been pushed to the repository. 45 | 46 | # We'll need this later when we try to figure out which metadata has 47 | # changed between commits, so that we can only deploy that metadata 48 | # to the destination org 49 | 50 | - name: 'Checkout source code' 51 | uses: actions/checkout@v3 52 | with: 53 | fetch-depth: 0 54 | 55 | # Now, we need a way to let the developer specify which tests to run, which 56 | # could be all tests or just the tests relevant to their deployment. 57 | 58 | # To do this, we can ask the developer to name their test classes in the 59 | # body of the PR, using the following syntax 60 | 61 | # Apex::[CommunitiesLoginControllerTest,MyProfilePageControllerTest]::Apex 62 | # or Apex::[all]::Apex to run all tests 63 | 64 | # This special delimeter can be added to the PR template so that your 65 | # team doesn't have to remember the syntax. 66 | 67 | # Once a developer has specified a list of classes to run, we need to be able 68 | # to extract this information from the PR, and pass it on the the VM. 69 | 70 | - name: 'Read PR Body' 71 | env: 72 | # The pull request body is available through the github context object 73 | # we put the body of the pull request in an env variable (only available to this step) 74 | PR_BODY: ${{github.event.pull_request.body}} 75 | 76 | # Here we print the content of the environment variable and 77 | # pipe to a a text file. 78 | 79 | # Then we call the local script parsePR.js, which will create 80 | # a new file called testsToRun.txt. This file will have the list 81 | # of tests to run separated by a comma 82 | 83 | # Finally, we add the list of tests to the $GITHUB_ENV variable 84 | # as this allows us to reference the list in a subsequent step. If you 85 | # were using a normal env variable, its value would not be available outside this step. 86 | run: | 87 | echo $PR_BODY > ./pr_body.txt 88 | node ./parsePR.js 89 | TESTS=$(cat testsToRun.txt) 90 | echo "APEX_TESTS=$TESTS" >> $GITHUB_ENV 91 | 92 | # Now Install Salesforce CLI 93 | - name: 'Install Salesforce CLI' 94 | run: | 95 | wget https://developer.salesforce.com/media/salesforce-cli/sfdx/channels/stable/sfdx-linux-x64.tar.xz 96 | mkdir ~/sfdx 97 | tar xJf sfdx-linux-x64.tar.xz -C ~/sfdx --strip-components 1 98 | echo "$HOME/sfdx/bin" >> $GITHUB_PATH 99 | ~/sfdx/bin/sfdx version 100 | 101 | # Then we install the SFDX-Git-Delta plugin - https://github.com/scolladon/sfdx-git-delta 102 | # This is an awesome plugin that allows us to extract a package.xml with the metadata 103 | # that has changed between commits. I highly recommend going over the github readme 104 | # for more information on how this works. 105 | 106 | - name: 'Installing sfdx git delta' 107 | run: | 108 | echo y | sfdx plugins:install sfdx-git-delta 109 | sfdx plugins 110 | 111 | # Install java as it is required for the next step 112 | - name: 'Installing java' 113 | run: | 114 | sudo apt-get update 115 | sudo apt install default-jdk 116 | 117 | # Install SFDX scanner 118 | - name: 'Installing SFDX scanner' 119 | run: sfdx plugins:install @salesforce/sfdx-scanner 120 | 121 | # Prior to setting up this workflow, you have to create a Github Secret 122 | # that contains the sfdx url of the integration/qa org. 123 | 124 | # The steps to generate the url are here 125 | # https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_auth_sfdxurl.htm 126 | 127 | # This URL can then be used with the sfdx auth:sfdxurl:store to authenticate 128 | # the sfdx project in the repositry, against the org from which the URL 129 | # was generated from. This works just like that, there's no need to create 130 | # connected apps or any else. 131 | 132 | # The URL is stored in the Github Secret named SFDX_INTEGRATION_URL 133 | # so here we store the URL into a text file 134 | - name: 'Populate auth file with SFDX_URL secret of integration org' 135 | shell: bash 136 | run: | 137 | echo ${{ secrets.SFDX_INTEGRATION_URL}} > ./SFDX_INTEGRATION_URL.txt 138 | 139 | # Authenticate to org using the URL stored in the text file 140 | - name: 'Authenticate to Integration Org' 141 | run: sfdx auth:sfdxurl:store -f ./SFDX_INTEGRATION_URL.txt -s -a integration 142 | 143 | # We use SFDX Git Delta to create a directory with only the metadata that has changed. 144 | # this allows us to deploy only those changes, as opposed to deploying the entire branch. 145 | # This helps reducing deployment times 146 | - name: 'Create delta packages for new, modified or deleted metadata' 147 | run: | 148 | mkdir changed-sources 149 | sfdx sgd:source:delta --to "HEAD" --from "HEAD^" --output changed-sources/ --generate-delta --source force-app/ 150 | 151 | # Now we can use the sfdx scanner to scan the code in the delta directory 152 | # The output of the scan is stored in a file called apexScanResults.sarif 153 | 154 | # The .sarif file can later be uploaded to github, so that we can see the 155 | # results of the scan directly from the PR. 156 | 157 | - name: 'Scan code' 158 | run: | 159 | cd changed-sources 160 | sfdx scanner:run --format sarif --target './**/*.cls' --category "Design,Best Practices,Performance" --outfile 'apexScanResults.sarif' 161 | cd .. 162 | 163 | # Now we upload the .sarif file as explained in the previous step 164 | - name: Upload SARIF file 165 | uses: github/codeql-action/upload-sarif@v1 166 | with: 167 | sarif_file: changed-sources/apexScanResults.sarif 168 | 169 | # We do a check-only deploy and we only run the tests specified in the PR 170 | # If the env variable does not equal 'all', we know that there is a list of 171 | # tests that can be run 172 | 173 | - name: 'Check-only deploy delta changes - run specified tests' 174 | if: ${{ env.APEX_TESTS != 'all' }} 175 | run: | 176 | echo ${{env.APEX_TESTS}} 177 | sfdx force:source:deploy -p "changed-sources/force-app" --checkonly --testlevel RunSpecifiedTests --runtests ${{env.APEX_TESTS}} --json 178 | 179 | # If the env variable equals all, we run all tests 180 | - name: 'Check-only deploy delta changes - run all tests' 181 | if: ${{ env.APEX_TESTS == 'all' }} 182 | run: | 183 | sfdx force:source:deploy -p "changed-sources/force-app" --checkonly --testlevel RunLocalTests --json 184 | 185 | - name: 'Deploy destructive changes (if any)' 186 | run: sfdx force:mdapi:deploy -d "changed-sources/destructiveChanges" --checkonly --ignorewarnings 187 | -------------------------------------------------------------------------------- /.github/workflows/push-develop-branch.yml: -------------------------------------------------------------------------------- 1 | # Unique name for this workflow 2 | name: Deploy integration branch to integration and staging/uat orgs 3 | 4 | # Definition when the workflow should run 5 | on: 6 | push: 7 | branches: [ integration ] 8 | paths: 9 | - 'force-app/**' 10 | 11 | 12 | # Jobs to be executed 13 | jobs: 14 | deploy-branch-to-int-and-staging-orgs: 15 | runs-on: ubuntu-latest 16 | if: ${{ github.actor != 'dependabot[bot]' }} 17 | steps: 18 | # Install Salesforce CLI 19 | - name: 'Install Salesforce CLI' 20 | run: | 21 | wget https://developer.salesforce.com/media/salesforce-cli/sfdx/channels/stable/sfdx-linux-x64.tar.xz 22 | mkdir ~/sfdx 23 | tar xJf sfdx-linux-x64.tar.xz -C ~/sfdx --strip-components 1 24 | echo "$HOME/sfdx/bin" >> $GITHUB_PATH 25 | ~/sfdx/bin/sfdx version 26 | 27 | # install SFDX-Git-Delta plugin - https://github.com/scolladon/sfdx-git-delta 28 | - name: 'Installing sfdx git delta' 29 | run: | 30 | echo y | sfdx plugins:install sfdx-git-delta 31 | sfdx plugins 32 | 33 | # Checkout the source code 34 | - name: 'Checkout source code' 35 | uses: actions/checkout@v3 36 | with: 37 | fetch-depth: 0 38 | 39 | # Store secret for both otgs 40 | - name: 'Populate auth file with SFDX_URL secret of the integration and staging orgs' 41 | shell: bash 42 | run: | 43 | echo ${{ secrets.SFDX_INTEGRATION_URL}} > ./SFDX_INTEGRATION_URL.txt 44 | echo ${{ secrets.SFDX_STAGING_URL}} > ./SFDX_STAGING_URL.txt 45 | 46 | - name: 'Create delta packages for new, modified or deleted metadata' 47 | run: | 48 | mkdir changed-sources 49 | sfdx sgd:source:delta --to "HEAD" --from "HEAD^" --output changed-sources/ --generate-delta --source force-app/ 50 | 51 | # Authenticate to org 52 | - name: 'Authenticate to Integration Org' 53 | run: sfdx auth:sfdxurl:store -f ./SFDX_INTEGRATION_URL.txt -s -a integration 54 | 55 | - name: 'Deploy the entire branch to Integration org' 56 | run: sfdx force:source:deploy -p force-app --testlevel RunLocalTests --json 57 | 58 | - name: 'Deploy destructive changes (if any) to Integration org' 59 | run: sfdx force:mdapi:deploy -d "changed-sources/destructiveChanges" --checkonly --ignorewarnings 60 | 61 | # Authenticate to org 62 | - name: 'Authenticate to Staging Org to Staging org' 63 | run: sfdx auth:sfdxurl:store -f ./SFDX_STAGING_URL.txt -s -a staging 64 | 65 | - name: 'Deploy the entire branch' 66 | run: sfdx force:source:deploy -p force-app --testlevel RunLocalTests --json 67 | 68 | - name: 'Deploy destructive changes (if any) to Staging org' 69 | run: sfdx force:mdapi:deploy -d "changed-sources/destructiveChanges" --checkonly --ignorewarnings 70 | -------------------------------------------------------------------------------- /.github/workflows/push-master-branch.yml: -------------------------------------------------------------------------------- 1 | # Unique name for this workflow 2 | name: Deploy master branch to production org 3 | 4 | # Definition when the workflow should run 5 | on: 6 | push: 7 | branches: [ master ] 8 | paths: 9 | - 'force-app/**' 10 | 11 | 12 | # Jobs to be executed 13 | jobs: 14 | deploy-branch-to-production-org: 15 | runs-on: ubuntu-latest 16 | if: ${{ github.actor != 'dependabot[bot]' }} 17 | steps: 18 | # Install Salesforce CLI 19 | - name: 'Install Salesforce CLI' 20 | run: | 21 | wget https://developer.salesforce.com/media/salesforce-cli/sfdx/channels/stable/sfdx-linux-x64.tar.xz 22 | mkdir ~/sfdx 23 | tar xJf sfdx-linux-x64.tar.xz -C ~/sfdx --strip-components 1 24 | echo "$HOME/sfdx/bin" >> $GITHUB_PATH 25 | ~/sfdx/bin/sfdx version 26 | 27 | # install SFDX-Git-Delta plugin - https://github.com/scolladon/sfdx-git-delta 28 | - name: 'Installing sfdx git delta' 29 | run: | 30 | echo y | sfdx plugins:install sfdx-git-delta 31 | sfdx plugins 32 | 33 | # Checkout the source code 34 | - name: 'Checkout source code' 35 | uses: actions/checkout@v3 36 | with: 37 | fetch-depth: 0 38 | 39 | # Store secret for production org 40 | - name: 'Populate auth file with SFDX_URL secret of the integration and staging orgs' 41 | shell: bash 42 | run: | 43 | echo ${{ secrets.SFDX_PRODUCTION_URL}} > ./SFDX_PRODUCTION_URL.txt 44 | 45 | - name: 'Create delta packages for new, modified or deleted metadata' 46 | run: | 47 | mkdir changed-sources 48 | sfdx sgd:source:delta --to "HEAD" --from "HEAD^" --output changed-sources/ --generate-delta --source force-app/ 49 | 50 | # Authenticate to org 51 | - name: 'Authenticate to Production Org' 52 | run: sfdx auth:sfdxurl:store -f ./SFDX_PRODUCTION_URL.txt -s -a production 53 | 54 | - name: 'Deploy the entire branch to Production org' 55 | run: sfdx force:source:deploy -p force-app --testlevel RunLocalTests --json 56 | 57 | - name: 'Deploy destructive changes (if any) to Production org' 58 | run: sfdx force:mdapi:deploy -d "changed-sources/destructiveChanges" --checkonly --ignorewarnings 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used for Git repositories to specify intentionally untracked files that Git should ignore. 2 | # If you are not using git, you can delete this file. For more information see: https://git-scm.com/docs/gitignore 3 | # For useful gitignore templates see: https://github.com/github/gitignore 4 | 5 | # Salesforce cache 6 | .sf/ 7 | .sfdx/ 8 | .localdevserver/ 9 | deploy-options.json 10 | 11 | # LWC VSCode autocomplete 12 | **/lwc/jsconfig.json 13 | 14 | # LWC Jest coverage reports 15 | coverage/ 16 | 17 | # Logs 18 | logs 19 | *.log 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | 24 | # Dependency directories 25 | node_modules/ 26 | 27 | # Eslint cache 28 | .eslintcache 29 | 30 | # MacOS system files 31 | .DS_Store 32 | 33 | # Windows system files 34 | Thumbs.db 35 | ehthumbs.db 36 | [Dd]esktop.ini 37 | $RECYCLE.BIN/ 38 | 39 | # Local environment variables 40 | .env -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run precommit -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # List files or directories below to ignore them when running prettier 2 | # More information: https://prettier.io/docs/en/ignore.html 3 | # 4 | 5 | **/staticresources/** 6 | .localdevserver 7 | .sfdx 8 | .vscode 9 | 10 | coverage/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "none", 3 | "overrides": [ 4 | { 5 | "files": "**/lwc/**/*.html", 6 | "options": { "parser": "lwc" } 7 | }, 8 | { 9 | "files": "*.{cmp,page,component}", 10 | "options": { "parser": "html" } 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "salesforce.salesforcedx-vscode", 4 | "redhat.vscode-xml", 5 | "dbaeumer.vscode-eslint", 6 | "esbenp.prettier-vscode", 7 | "financialforce.lana" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch Apex Replay Debugger", 9 | "type": "apex-replay", 10 | "request": "launch", 11 | "logFile": "${command:AskForLogFileName}", 12 | "stopOnEntry": true, 13 | "trace": true 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.exclude": { 3 | "**/node_modules": true, 4 | "**/bower_components": true, 5 | "**/.sfdx": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CI/CD for Org Development Model 2 | 3 | This is a sample sfdx project that showcases how to use Github Actions for CI/CD in an org development model (no packages, no scratch orgs). 4 | 5 | Check out the `pr-develop-branch.yml` file under `.github/workflows` for a detailed explanation of the operations that are being automated. 6 | 7 | ## High level flow 8 | 9 | **1-** We have a master branch that represents the metadata we are tracking. 10 | 11 | **2-** At the beginning of a development sprint, we create a develop branch off of main, in the remote repository. 12 | 13 | **3-** Developers clone the repository (which is an sfdx project) to their local computer and authorize the project against their own sandbox (this is a one time step). This is an important and often overlooked feature of sfdx: you can authorize any sfdx project against any org, even if the project was created from a different org. 14 | 15 | **4-** Developers checkout the remote develop branch, and create a feature branch that corresponds to the bug or user story they are working on. 16 | 17 | **5-** Developers push their branch to the remote repository, and continue to push commits as they progress through the development process. 18 | 19 | **6-** Once ready, the developer opens a pull request from the feature branch against the develop branch. 20 | 21 | **7-** The pull request triggers a CI/CD job with Github Actions that will do the following: 22 | 23 | Do a check-only deployment of only the new metadata or the existing metadata that has changed. This deployment will be against the qa/integration org. 24 | 25 | If the deployment passes, run the tests specified by the developer (explained below). 26 | 27 | Scan the apex code for any vulnerabilities or code smells. Log any issues directly in github. 28 | 29 | **8-** If the CI/CD job completes successfully, then the feature branch can be merged into develop. 30 | 31 | **9-** The feature branch is merged into develop, and this triggers an actual deployment of the metadata into the qa/integration org, and again runs the tests specified by the developer. 32 | 33 | **10-** At the end of the sprint, the develop branch is merged into master, and this triggers a production deployment. 34 | 35 | 36 | ## Deploying delta changes 37 | 38 | We are `sfdx-git-delta` to only deploy the metadata that has been changed (or created) by the developer. 39 | 40 | If you want to deploy the entire branch, simply use the `deploy` command against the `force-app` directory. 41 | 42 | ## Specify which tests to run 43 | 44 | We allow the developer to specify which tests to run by using a special syntax in the pull request body 45 | 46 | `Apex::[Class1,Class2,Class3...]::Apex` 47 | 48 | Read `pr-develop-branch.yml` for a detailed description of how this works. 49 | 50 | ## Static code analysis 51 | 52 | We are using the `sfdx scanner` to scan the code in the delta directory. 53 | 54 | We decided not to fail the entire job just because there are warnings. Instead, the warnings are logged directly in the PR for your team to review. We think this is better than failing the job because it allows your team to review the code and have a conversation about it. If the same warning keeps showing up every now and then, then it might be worth to configure the job to fail. 55 | 56 | -------------------------------------------------------------------------------- /config/project-scratch-def.json: -------------------------------------------------------------------------------- 1 | { 2 | "orgName": "pgonzalez company", 3 | "edition": "Developer", 4 | "features": ["EnableSetPasswordInApi"], 5 | "settings": { 6 | "lightningExperienceSettings": { 7 | "enableS1DesktopEnabled": true 8 | }, 9 | "mobileSettings": { 10 | "enableS1EncryptedStoragePref2": false 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /force-app/main/default/aura/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["@salesforce/eslint-plugin-aura"], 3 | "extends": ["plugin:@salesforce/eslint-plugin-aura/recommended"], 4 | "rules": { 5 | "vars-on-top": "off", 6 | "no-unused-expressions": "off" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.cmp: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | {!v.left} 14 | 15 | 20 | {!v.center} 21 | 22 | 23 | {!v.right} 24 | 25 | 26 |
27 |
-------------------------------------------------------------------------------- /force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.cmp-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | A Lightning Component Bundle 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.css: -------------------------------------------------------------------------------- 1 | .THIS .center { 2 | padding: 0 12px; 3 | } -------------------------------------------------------------------------------- /force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.design: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /force-app/main/default/aura/pageTemplate_2_7_3/pageTemplate_2_7_3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /force-app/main/default/classes/ChangePasswordController.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that exposes the change password functionality 3 | */ 4 | public with sharing class ChangePasswordController { 5 | public String oldPassword {get; set;} 6 | public String newPassword {get; set;} 7 | public String verifyNewPassword {get; set;} 8 | 9 | public PageReference changePassword() { 10 | System.debug(true);//change 344565 11 | return Site.changePassword(newPassword, verifyNewPassword, oldpassword); 12 | } 13 | 14 | public ChangePasswordController() {} 15 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/ChangePasswordController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/ChangePasswordControllerTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that exposes the change password functionality 3 | */ 4 | @IsTest public with sharing class ChangePasswordControllerTest { 5 | @IsTest(SeeAllData=true) public static void testChangePasswordController() { 6 | // Instantiate a new controller with all parameters in the page 7 | ChangePasswordController controller = new ChangePasswordController(); 8 | controller.oldPassword = '123456'; 9 | controller.newPassword = 'qwerty1'; 10 | controller.verifyNewPassword = 'qwerty1'; 11 | 12 | System.assertEquals(controller.changePassword(),null); 13 | } 14 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/ChangePasswordControllerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesLandingController.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that takes the user to the right start page based on credentials or lack thereof 3 | */ 4 | public with sharing class CommunitiesLandingController { 5 | 6 | // Code we will invoke on page load. 7 | public PageReference forwardToStartPage() { 8 | return Network.communitiesLanding(); 9 | } 10 | 11 | public CommunitiesLandingController() {} 12 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesLandingController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesLandingControllerTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that takes the user to the right start page based on credentials or lack thereof 3 | */ 4 | @IsTest public with sharing class CommunitiesLandingControllerTest { 5 | @IsTest(SeeAllData=true) public static void testCommunitiesLandingController() { 6 | // Instantiate a new controller with all parameters in the page 7 | CommunitiesLandingController controller = new CommunitiesLandingController(); 8 | PageReference pageRef = controller.forwardToStartPage(); 9 | //PageRef is either null or an empty object in test context 10 | if(pageRef != null){ 11 | String url = pageRef.getUrl(); 12 | if(url != null){ 13 | System.assertEquals(true, String.isEmpty(url)); 14 | //show up in perforce 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesLandingControllerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesLoginController.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that exposes the site login functionality 3 | */ 4 | global with sharing class CommunitiesLoginController { 5 | 6 | global CommunitiesLoginController () {} 7 | 8 | // Code we will invoke on page load. 9 | global PageReference forwardToAuthPage() { 10 | String startUrl = System.currentPageReference().getParameters().get('startURL'); 11 | String displayType = System.currentPageReference().getParameters().get('display'); 12 | return Network.forwardToAuthPage(startUrl, displayType); 13 | } 14 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesLoginController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesLoginControllerTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that exposes the site login functionality 3 | */ 4 | @IsTest global with sharing class CommunitiesLoginControllerTest { 5 | @IsTest(SeeAllData=true) 6 | global static void testCommunitiesLoginController () { 7 | CommunitiesLoginController controller = new CommunitiesLoginController(); 8 | System.assertEquals(null, controller.forwardToAuthPage()); 9 | } 10 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesLoginControllerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesSelfRegConfirmController.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that takes the user to the right start page based on credentials or lack thereof 3 | */ 4 | public with sharing class CommunitiesSelfRegConfirmController { 5 | 6 | public CommunitiesSelfRegConfirmController() {} 7 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesSelfRegConfirmController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesSelfRegConfirmControllerTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that takes the user to the right start page based on credentials or lack thereof 3 | */ 4 | @IsTest public with sharing class CommunitiesSelfRegConfirmControllerTest { 5 | @IsTest(SeeAllData=true) public static void testCommunitiesSelfRegConfirmController() { 6 | // Instantiate a new controller with all parameters in the page 7 | CommunitiesSelfRegConfirmController controller = new CommunitiesSelfRegConfirmController(); 8 | } 9 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesSelfRegConfirmControllerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesSelfRegController.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that supports self registration of users in communities that allow self registration 3 | */ 4 | public class CommunitiesSelfRegController { 5 | 6 | public String firstName {get; set;} 7 | public String lastName {get; set;} 8 | public String email {get; set;} 9 | public String password {get; set {password = value == null ? value : value.trim(); } } 10 | public String confirmPassword {get; set { confirmPassword = value == null ? value : value.trim(); } } 11 | public String communityNickname {get; set { communityNickname = value == null ? value : value.trim(); } } 12 | 13 | public CommunitiesSelfRegController() { 14 | String expid = ApexPages.currentPage().getParameters().get('expid'); 15 | if (expId != null) { 16 | Site.setExperienceId(expId); 17 | } 18 | } 19 | 20 | private boolean isValidPassword() { 21 | return password == confirmPassword; 22 | } 23 | 24 | public PageReference registerUser() { 25 | 26 | // it's okay if password is null - we'll send the user a random password in that case 27 | if (!isValidPassword()) { 28 | ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.ERROR, Label.site.passwords_dont_match); 29 | ApexPages.addMessage(msg); 30 | return null; 31 | } 32 | 33 | String profileId = null; // To be filled in by customer. 34 | String roleEnum = null; // To be filled in by customer. 35 | String accountId = ''; // To be filled in by customer. 36 | 37 | String userName = email; 38 | 39 | User u = new User(); 40 | u.Username = userName; 41 | u.Email = email; 42 | u.FirstName = firstName; 43 | u.LastName = lastName; 44 | u.CommunityNickname = communityNickname; 45 | u.ProfileId = profileId; 46 | 47 | String userId; 48 | 49 | try { 50 | userId = Site.createExternalUser(u, accountId, password); 51 | } catch(Site.ExternalUserCreateException ex) { 52 | List errors = ex.getDisplayMessages(); 53 | for (String error : errors) { 54 | ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, error)); 55 | } 56 | 57 | // This message is used for debugging. Do not display this in the UI to the end user. 58 | // It has the information around why the user creation failed. 59 | System.debug(ex.getMessage()); 60 | } 61 | 62 | if (userId != null) { 63 | if (password != null && password.length() > 1) { 64 | return Site.login(userName, password, ApexPages.currentPage().getParameters().get('startURL')); 65 | } 66 | else { 67 | PageReference page = System.Page.CommunitiesSelfRegConfirm; 68 | page.setRedirect(true); 69 | return page; 70 | } 71 | } 72 | return null; 73 | } 74 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesSelfRegController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesSelfRegControllerTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that supports self registration of users in communities that allow self registration 3 | */ 4 | @IsTest public with sharing class CommunitiesSelfRegControllerTest { 5 | @IsTest(SeeAllData=true) 6 | public static void testCommunitiesSelfRegController() { 7 | CommunitiesSelfRegController controller = new CommunitiesSelfRegController(); 8 | controller.firstName = 'FirstName'; 9 | controller.lastName = 'LastName'; 10 | controller.email = 'test@force.com'; 11 | controller.communityNickname = 'test'; 12 | 13 | // registerUser will always return null when the page isn't accessed as a guest user 14 | System.assert(controller.registerUser() == null); 15 | 16 | controller.password = 'abcd1234'; 17 | controller.confirmPassword = 'abcd123'; 18 | System.assert(controller.registerUser() == null); 19 | } 20 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/CommunitiesSelfRegControllerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/ForgotPasswordController.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that exposes the site forgot password functionality 3 | */ 4 | public with sharing class ForgotPasswordController { 5 | public String username {get; set;} 6 | 7 | public ForgotPasswordController() {} 8 | 9 | public PageReference forgotPassword() { 10 | boolean success = Site.forgotPassword(username); 11 | PageReference pr = Page.ForgotPasswordConfirm; 12 | pr.setRedirect(true); 13 | 14 | if (success) { 15 | return pr; 16 | } 17 | return null; 18 | } 19 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/ForgotPasswordController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/ForgotPasswordControllerTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that exposes the site forgot password functionality 3 | */ 4 | @IsTest public with sharing class ForgotPasswordControllerTest { 5 | @IsTest(SeeAllData=true) public static void testForgotPasswordController() { 6 | // Instantiate a new controller with all parameters in the page 7 | ForgotPasswordController controller = new ForgotPasswordController(); 8 | controller.username = 'test@salesforce.com'; 9 | 10 | System.assertEquals(controller.forgotPassword(),null); 11 | } 12 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/ForgotPasswordControllerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/HeroDetailsPositionCustomPicklist.cls: -------------------------------------------------------------------------------- 1 | global class HeroDetailsPositionCustomPicklist extends VisualEditor.DynamicPickList { 2 | global override VisualEditor.DataRow getDefaultValue() { 3 | VisualEditor.DataRow defaultValue = new VisualEditor.DataRow( 4 | 'Right', 5 | 'right' 6 | ); 7 | return defaultValue; 8 | } 9 | global override VisualEditor.DynamicPickListRows getValues() { 10 | VisualEditor.DataRow value1 = new VisualEditor.DataRow('Left', 'left'); 11 | VisualEditor.DataRow value2 = new VisualEditor.DataRow( 12 | 'Right', 13 | 'right' 14 | ); 15 | VisualEditor.DynamicPickListRows myValues = new VisualEditor.DynamicPickListRows(); 16 | myValues.addRow(value1); 17 | myValues.addRow(value2); 18 | return myValues; 19 | } 20 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/HeroDetailsPositionCustomPicklist.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/MyProfilePageController.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex class that updates portal user details. 3 | Guest users are never able to access this page. 4 | */ 5 | public with sharing class MyProfilePageController { 6 | 7 | private User user; 8 | private boolean isEdit = false; 9 | 10 | public User getUser() { 11 | return user; 12 | } 13 | 14 | public MyProfilePageController() { 15 | user = [SELECT id, email, username, usertype, communitynickname, timezonesidkey, languagelocalekey, firstname, lastname, phone, title, 16 | street, city, country, postalcode, state, localesidkey, mobilephone, extension, fax, contact.email 17 | FROM User 18 | WHERE id = :UserInfo.getUserId()]; 19 | // guest users should never be able to access this page 20 | if (user.usertype == 'GUEST') { 21 | throw new NoAccessException(); 22 | } 23 | } 24 | 25 | public Boolean getIsEdit() { 26 | return isEdit; 27 | } 28 | 29 | public void edit() { 30 | isEdit=true; 31 | } 32 | 33 | public void save() { 34 | try { 35 | update user; 36 | isEdit=false; 37 | } catch(DmlException e) { 38 | ApexPages.addMessages(e); 39 | } 40 | } 41 | 42 | public PageReference changePassword() { 43 | return Page.ChangePassword; 44 | } 45 | 46 | public void cancel() { 47 | isEdit=false; 48 | user = [SELECT id, email, username, communitynickname, timezonesidkey, languagelocalekey, firstname, lastname, phone, title, 49 | street, city, country, postalcode, state, localesidkey, mobilephone, extension, fax, contact.email 50 | FROM User 51 | WHERE id = :UserInfo.getUserId()]; 52 | } 53 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/MyProfilePageController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/MyProfilePageControllerTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex class that updates details of a portal user. 3 | Guest users are never able to access this page. 4 | */ 5 | @IsTest public with sharing class MyProfilePageControllerTest { 6 | 7 | @IsTest(SeeAllData=true) static void testSave() { 8 | // Modify the test to query for a portal user that exists in your org 9 | List existingPortalUsers = [SELECT id, profileId, userRoleId FROM User WHERE UserRoleId <> null AND UserType='CustomerSuccess']; 10 | 11 | if (existingPortalUsers.isEmpty()) { 12 | User currentUser = [select id, title, firstname, lastname, email, phone, mobilephone, fax, street, city, state, postalcode, country 13 | FROM User WHERE id =: UserInfo.getUserId()]; 14 | MyProfilePageController controller = new MyProfilePageController(); 15 | System.assertEquals(currentUser.Id, controller.getUser().Id, 'Did not successfully load the current user'); 16 | System.assert(controller.getIsEdit() == false, 'isEdit should default to false'); 17 | controller.edit(); 18 | System.assert(controller.getIsEdit() == true); 19 | controller.cancel(); 20 | System.assert(controller.getIsEdit() == false); 21 | 22 | System.assert(Page.ChangePassword.getUrl().equals(controller.changePassword().getUrl())); 23 | 24 | String randFax = Math.rint(Math.random() * 1000) + '5551234'; 25 | controller.getUser().Fax = randFax; 26 | controller.save(); 27 | System.assert(controller.getIsEdit() == false); 28 | 29 | currentUser = [Select id, fax from User where id =: currentUser.Id]; 30 | System.assert(currentUser.fax == randFax); 31 | } else { 32 | User existingPortalUser = existingPortalUsers[0]; 33 | String randFax = Math.rint(Math.random() * 1000) + '5551234'; 34 | 35 | System.runAs(existingPortalUser) { 36 | MyProfilePageController controller = new MyProfilePageController(); 37 | System.assertEquals(existingPortalUser.Id, controller.getUser().Id, 'Did not successfully load the current user'); 38 | System.assert(controller.getIsEdit() == false, 'isEdit should default to false'); 39 | controller.edit(); 40 | System.assert(controller.getIsEdit() == true); 41 | 42 | controller.cancel(); 43 | System.assert(controller.getIsEdit() == false); 44 | 45 | controller.getUser().Fax = randFax; 46 | controller.save(); 47 | System.assert(controller.getIsEdit() == false); 48 | } 49 | 50 | // verify that the user was updated 51 | existingPortalUser = [Select id, fax from User where id =: existingPortalUser.Id]; 52 | System.assert(existingPortalUser.fax == randFax); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/MyProfilePageControllerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/OrderController.cls: -------------------------------------------------------------------------------- 1 | public with sharing class OrderController { 2 | //comment 3 | @AuraEnabled(Cacheable=true) 4 | public static Order_Item__c[] getOrderItems(Id orderId) { 5 | return [ 6 | SELECT 7 | Id, 8 | Qty_S__c, 9 | Qty_M__c, 10 | Qty_L__c, 11 | Price__c, 12 | Product__r.Name, 13 | Product__r.MSRP__c, 14 | Product__r.Picture_URL__c 15 | FROM Order_Item__c 16 | WHERE Order__c = :orderId 17 | WITH SECURITY_ENFORCED 18 | ]; 19 | } 20 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/OrderController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/PagedResult.cls: -------------------------------------------------------------------------------- 1 | public with sharing class PagedResult { 2 | @AuraEnabled 3 | public Integer pageSize { get; set; } 4 | 5 | @AuraEnabled 6 | public Integer pageNumber { get; set; } 7 | 8 | @AuraEnabled 9 | public Integer totalItemCount { get; set; } 10 | 11 | @AuraEnabled 12 | public Object[] records { get; set; } 13 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/PagedResult.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/ProductController.cls: -------------------------------------------------------------------------------- 1 | public with sharing class ProductController { 2 | static Integer PAGE_SIZE = 9; 3 | 4 | public class Filters { 5 | @AuraEnabled 6 | public String searchKey { get; set; } 7 | @AuraEnabled 8 | public Decimal maxPrice { get; set; } 9 | @AuraEnabled 10 | public String[] categories { get; set; } 11 | @AuraEnabled 12 | public String[] materials { get; set; } 13 | @AuraEnabled 14 | public String[] levels { get; set; } 15 | } 16 | 17 | @AuraEnabled(Cacheable=true) 18 | public static PagedResult getProducts(Filters filters, Integer pageNumber) { 19 | String key, whereClause = ''; 20 | Decimal maxPrice; 21 | String[] categories, materials, levels, criteria = new List{}; 22 | if (filters != null) { 23 | maxPrice = filters.maxPrice; 24 | materials = filters.materials; 25 | levels = filters.levels; 26 | if (!String.isEmpty(filters.searchKey)) { 27 | key = '%' + filters.searchKey + '%'; 28 | criteria.add('Name LIKE :key'); 29 | } 30 | if (filters.maxPrice >= 0) { 31 | maxPrice = filters.maxPrice; 32 | criteria.add('MSRP__c <= :maxPrice'); 33 | } 34 | if (filters.categories != null) { 35 | categories = filters.categories; 36 | criteria.add('Category__c IN :categories'); 37 | } 38 | if (filters.levels != null) { 39 | levels = filters.levels; 40 | criteria.add('Level__c IN :levels'); 41 | } 42 | if (filters.materials != null) { 43 | materials = filters.materials; 44 | criteria.add('Material__c IN :materials'); 45 | } 46 | if (criteria.size() > 0) { 47 | whereClause = 'WHERE ' + String.join(criteria, ' AND '); 48 | } 49 | } 50 | Integer pageSize = ProductController.PAGE_SIZE; 51 | Integer offset = (pageNumber - 1) * pageSize; 52 | PagedResult result = new PagedResult(); 53 | result.pageSize = pageSize; 54 | result.pageNumber = pageNumber; 55 | result.totalItemCount = Database.countQuery( 56 | 'SELECT count() FROM Product__c ' + whereClause 57 | ); 58 | result.records = Database.query( 59 | 'SELECT Id, Name, MSRP__c, Description__c, Category__c, Level__c, Picture_URL__c, Material__c FROM Product__c ' + 60 | whereClause + 61 | ' WITH SECURITY_ENFORCED' + 62 | ' ORDER BY Name LIMIT :pageSize OFFSET :offset' 63 | ); 64 | return result; 65 | } 66 | 67 | @AuraEnabled(Cacheable=true) 68 | public static Product__c[] getSimilarProducts(Id productId, Id familyId) { 69 | return [ 70 | SELECT 71 | Id, 72 | Name, 73 | MSRP__c, 74 | Description__c, 75 | Category__c, 76 | Level__c, 77 | Picture_URL__c, 78 | Material__c 79 | FROM Product__c 80 | WHERE Product_Family__c = :familyId AND Id != :productId 81 | WITH SECURITY_ENFORCED 82 | ]; 83 | } 84 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/ProductController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/ProductRecordInfoController.cls: -------------------------------------------------------------------------------- 1 | public with sharing class ProductRecordInfoController { 2 | @AuraEnabled(Cacheable=true) 3 | public static List getRecordInfo(String productOrFamilyName) { 4 | List recordInfo = new List(); 5 | 6 | List cProductList = [ 7 | SELECT ID 8 | FROM Product__c 9 | WHERE NAME = :productOrFamilyName 10 | WITH SECURITY_ENFORCED 11 | ]; 12 | if (cProductList.size() > 0) { 13 | recordInfo.add(cProductList[0].ID); 14 | recordInfo.add('Product__c'); 15 | return recordInfo; 16 | } 17 | 18 | List cProductFamilyList = [ 19 | SELECT ID 20 | FROM Product_Family__c 21 | WHERE NAME = :productOrFamilyName 22 | WITH SECURITY_ENFORCED 23 | ]; 24 | if (cProductFamilyList.size() > 0) { 25 | recordInfo.add(cProductFamilyList[0].ID); 26 | recordInfo.add('Product_Family__c'); 27 | return recordInfo; 28 | } 29 | return null; 30 | } 31 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/ProductRecordInfoController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/SiteLoginController.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that exposes the site login functionality 3 | */ 4 | global with sharing class SiteLoginController { 5 | global String username {get; set;} 6 | global String password {get; set;} 7 | 8 | global PageReference login() { 9 | String startUrl = System.currentPageReference().getParameters().get('startURL'); 10 | return Site.login(username, password, startUrl); 11 | } 12 | 13 | global SiteLoginController () {} 14 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/SiteLoginController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/SiteLoginControllerTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex page controller that exposes the site login functionality 3 | */ 4 | @IsTest global with sharing class SiteLoginControllerTest { 5 | @IsTest(SeeAllData=true) global static void testSiteLoginController () { 6 | // Instantiate a new controller with all parameters in the page 7 | SiteLoginController controller = new SiteLoginController (); 8 | controller.username = 'test@salesforce.com'; 9 | controller.password = '123456'; 10 | 11 | System.assertEquals(controller.login(),null); 12 | } 13 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/SiteLoginControllerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/SiteRegisterController.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * An apex class that creates a portal user 3 | */ 4 | public with sharing class SiteRegisterController { 5 | // PORTAL_ACCOUNT_ID is the account on which the contact will be created on and then enabled as a portal user. 6 | // you need to add the account owner into the role hierarchy before this will work - please see Customer Portal Setup help for more information. 7 | private static Id PORTAL_ACCOUNT_ID = '001x000xxx35tPN'; 8 | 9 | public SiteRegisterController () { 10 | } 11 | 12 | public String username {get; set;} 13 | public String email {get; set;} 14 | public String password {get; set {password = value == null ? value : value.trim(); } } 15 | public String confirmPassword {get; set { confirmPassword = value == null ? value : value.trim(); } } 16 | public String communityNickname {get; set { communityNickname = value == null ? value : value.trim(); } } 17 | 18 | private boolean isValidPassword() { 19 | return password == confirmPassword; 20 | } 21 | 22 | public PageReference registerUser() { 23 | // it's okay if password is null - we'll send the user a random password in that case 24 | if (!isValidPassword()) { 25 | ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.ERROR, Label.site.passwords_dont_match); 26 | ApexPages.addMessage(msg); 27 | return null; 28 | } 29 | User u = new User(); 30 | u.Username = username; 31 | u.Email = email; 32 | u.CommunityNickname = communityNickname; 33 | 34 | String accountId = PORTAL_ACCOUNT_ID; 35 | 36 | // lastName is a required field on user, but if it isn't specified, we'll default it to the username 37 | String userId = Site.createPortalUser(u, accountId, password); 38 | if (userId != null) { 39 | if (password != null && password.length() > 1) { 40 | return Site.login(username, password, null); 41 | } 42 | else { 43 | PageReference page = System.Page.SiteRegisterConfirm; 44 | page.setRedirect(true); 45 | return page; 46 | } 47 | } 48 | return null; 49 | } 50 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/SiteRegisterController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/SiteRegisterControllerTest.cls: -------------------------------------------------------------------------------- 1 | /** 2 | * Class containing tests for SiteRegisterController 3 | */ 4 | @IsTest public with sharing class SiteRegisterControllerTest { 5 | @IsTest(SeeAllData=true) static void testRegistration() { 6 | SiteRegisterController controller = new SiteRegisterController(); 7 | controller.username = 'test@force.com'; 8 | controller.email = 'test@force.com'; 9 | controller.communityNickname = 'test'; 10 | // registerUser will always return null when the page isn't accessed as a guest user 11 | System.assert(controller.registerUser() == null); 12 | 13 | controller.password = 'abcd1234'; 14 | controller.confirmPassword = 'abcd123'; 15 | System.assert(controller.registerUser() == null); 16 | } 17 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/SiteRegisterControllerTest.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/TestOrderController.cls: -------------------------------------------------------------------------------- 1 | @isTest 2 | public class TestOrderController { 3 | @testSetup 4 | static void setup() { 5 | Account acc = new Account(Name = 'Sample Account'); 6 | insert acc; 7 | 8 | Order__c order = new Order__c(Account__c = acc.Id); 9 | insert order; 10 | 11 | Product__c p = new Product__c(Name = 'Sample Product'); 12 | insert p; 13 | 14 | Order_Item__c orderItem = new Order_Item__c( 15 | Order__c = order.Id, 16 | Product__c = p.Id 17 | ); 18 | insert orderItem; 19 | } 20 | 21 | @isTest 22 | static void testGetOrderItems() { 23 | Order__c testOrder = [SELECT Id FROM Order__c]; 24 | List orderItems = OrderController.getOrderItems( 25 | testOrder.Id 26 | ); 27 | System.assertEquals(orderItems.size(), 1); 28 | } 29 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/TestOrderController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/TestProductController.cls: -------------------------------------------------------------------------------- 1 | @isTest 2 | public class TestProductController { 3 | @testSetup 4 | static void createProducts() { 5 | List products = new List(); 6 | 7 | products.add( 8 | new Product__c( 9 | Name = 'Sample Bike 1', 10 | MSRP__c = 1000, 11 | Category__c = 'Mountain', 12 | Level__c = 'Beginner', 13 | Material__c = 'Carbon' 14 | ) 15 | ); 16 | 17 | products.add( 18 | new Product__c( 19 | Name = 'Sample Bike 2', 20 | MSRP__c = 1200, 21 | Category__c = 'Mountain', 22 | Level__c = 'Beginner', 23 | Material__c = 'Carbon' 24 | ) 25 | ); 26 | 27 | insert products; 28 | } 29 | 30 | @isTest 31 | static void testGetProducts() { 32 | ProductController.Filters filters = new ProductController.Filters(); 33 | filters.searchKey = 'Sample'; 34 | filters.maxPrice = 2000; 35 | filters.categories = new List{ 'Mountain' }; 36 | filters.levels = new List{ 'Beginner' }; 37 | filters.materials = new List{ 'Carbon' }; 38 | PagedResult result = ProductController.getProducts(filters, 1); 39 | System.assertEquals(result.records.size(), 2); 40 | } 41 | 42 | @isTest 43 | static void testGetSimilarProducts() { 44 | ProductController.Filters filters = new ProductController.Filters(); 45 | filters.searchKey = 'Sample'; 46 | filters.maxPrice = 2000; 47 | filters.categories = new List{ 'Mountain' }; 48 | filters.levels = new List{ 'Beginner' }; 49 | filters.materials = new List{ 'Carbon' }; 50 | PagedResult result = ProductController.getProducts(filters, 1); 51 | Product__c productToCompare = (Product__c) result.records[0]; 52 | Product__c[] products = ProductController.getSimilarProducts( 53 | productToCompare.Id, 54 | null 55 | ); 56 | System.assertEquals(products.size(), 1); 57 | } 58 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/TestProductController.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/UltimateClass.cls: -------------------------------------------------------------------------------- 1 | public with sharing class UltimateClass { 2 | public UltimateClass() { 3 | String a = 'hi'; 4 | String b = null; 5 | if(a == 'hi'){ 6 | b = 'great'; 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/UltimateClass.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 52.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/classes/UltimateClassTests.cls: -------------------------------------------------------------------------------- 1 | @IsTest 2 | public with sharing class UltimateClassTests { 3 | 4 | @IsTest 5 | public static void testMyCode(){ 6 | UltimateClass a = new UltimateClass(); 7 | System.assert(true); 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /force-app/main/default/classes/UltimateClassTests.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 52.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/components/SiteFooter.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /force-app/main/default/components/SiteFooter.component-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Default Lightning Platform site footer component 5 | 6 | 7 | 1 8 | 7 9 | sf_com_apps 10 | 11 | 12 | 1 13 | 6 14 | trlhdtips 15 | 16 | 17 | -------------------------------------------------------------------------------- /force-app/main/default/components/SiteHeader.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {!$Label.site.login_button} 7 | 8 | {!$Label.site.forgot_your_password_q} 9 | 10 | {!$Label.site.new_user_q} 11 | 12 | {!$Label.site.logout} 13 | 14 | 15 | -------------------------------------------------------------------------------- /force-app/main/default/components/SiteHeader.component-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Default Lightning Platform site header component 5 | 6 | 7 | 1 8 | 7 9 | sf_com_apps 10 | 11 | 12 | 1 13 | 6 14 | trlhdtips 15 | 16 | 17 | -------------------------------------------------------------------------------- /force-app/main/default/components/SiteLogin.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {!$Label.site.forgot_your_password_q} 17 | 18 | {!$Label.site.new_user_q} 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /force-app/main/default/components/SiteLogin.component-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Default Salesforce Sites Login component 5 | 6 | 7 | 1 8 | 7 9 | sf_com_apps 10 | 11 | 12 | 1 13 | 6 14 | trlhdtips 15 | 16 | 17 | -------------------------------------------------------------------------------- /force-app/main/default/components/SitePoweredBy.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /force-app/main/default/components/SitePoweredBy.component-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | Default Lightning Platform site powered by component 5 | 6 | 7 | 1 8 | 7 9 | sf_com_apps 10 | 11 | 12 | 1 13 | 6 14 | trlhdtips 15 | 16 | 17 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@salesforce/eslint-config-lwc/recommended"], 3 | "overrides": [ 4 | { 5 | "files": ["*.test.js"], 6 | "rules": { 7 | "@lwc/lwc/no-unexpected-wire-adapter-usages": "off" 8 | } 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/accountMap/accountMap.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/accountMap/accountMap.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api, wire } from 'lwc'; 2 | import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; 3 | 4 | import BILLING_CITY from '@salesforce/schema/Account.BillingCity'; 5 | import BILLING_COUNTRY from '@salesforce/schema/Account.BillingCountry'; 6 | import BILLING_POSTAL_CODE from '@salesforce/schema/Account.BillingPostalCode'; 7 | import BILLING_STATE from '@salesforce/schema/Account.BillingState'; 8 | import BILLING_STREET from '@salesforce/schema/Account.BillingStreet'; 9 | 10 | const fields = [ 11 | BILLING_CITY, 12 | BILLING_COUNTRY, 13 | BILLING_POSTAL_CODE, 14 | BILLING_STATE, 15 | BILLING_STREET 16 | ]; 17 | 18 | export default class PropertyMap extends LightningElement { 19 | @api recordId; 20 | 21 | zoomLevel = 14; 22 | markers = []; 23 | error; 24 | 25 | @wire(getRecord, { recordId: '$recordId', fields }) 26 | wiredRecord({ error, data }) { 27 | if (data) { 28 | this.markers = []; 29 | this.error = undefined; 30 | const street = getFieldValue(data, BILLING_STREET); 31 | if (street) { 32 | this.markers = [ 33 | { 34 | location: { 35 | City: getFieldValue(data, BILLING_CITY), 36 | Country: getFieldValue(data, BILLING_COUNTRY), 37 | PostalCode: getFieldValue( 38 | data, 39 | BILLING_POSTAL_CODE 40 | ), 41 | State: getFieldValue(data, BILLING_STATE), 42 | Street: street 43 | } 44 | } 45 | ]; 46 | } 47 | } else if (error) { 48 | this.markers = []; 49 | this.error = error; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/accountMap/accountMap.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | true 5 | Account Map 6 | 7 | lightning__RecordPage 8 | 9 | 10 | 11 | 12 | Account 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/createCase/createCase.css: -------------------------------------------------------------------------------- 1 | .title-order, 2 | .submit-button { 3 | font-weight: bold; 4 | } 5 | 6 | .navigate-hidden { 7 | display: none; 8 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/createCase/createCase.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/createCase/createCase.js: -------------------------------------------------------------------------------- 1 | import { LightningElement } from 'lwc'; 2 | import { ShowToastEvent } from 'lightning/platformShowToastEvent'; 3 | 4 | import CASE_OBJECT from '@salesforce/schema/Case'; 5 | import SUBJECT from '@salesforce/schema/Case.Subject'; 6 | import DESCRIPTION from '@salesforce/schema/Case.Description'; 7 | import PRODUCT from '@salesforce/schema/Case.Product__c'; 8 | import PRIORITY from '@salesforce/schema/Case.Priority'; 9 | import CASE_CATEGORY from '@salesforce/schema/Case.Case_Category__c'; 10 | import REASON from '@salesforce/schema/Case.Reason'; 11 | 12 | const TITLE_SUCCESS = 'Case Created!'; 13 | const MESSAGE_SUCCESS = 'You have successfully created a Case'; 14 | 15 | export default class CreateCase extends LightningElement { 16 | caseObject = CASE_OBJECT; 17 | subjectField = SUBJECT; 18 | productField = PRODUCT; 19 | descriptionField = DESCRIPTION; 20 | priorityField = PRIORITY; 21 | reasonField = REASON; 22 | categoryField = CASE_CATEGORY; 23 | 24 | handleCaseCreated() { 25 | // Fire event for Toast to appear that Order was created 26 | const evt = new ShowToastEvent({ 27 | title: TITLE_SUCCESS, 28 | message: MESSAGE_SUCCESS, 29 | variant: 'success' 30 | }); 31 | this.dispatchEvent(evt); 32 | 33 | const refreshEvt = new CustomEvent('refresh'); 34 | // Fire the custom event 35 | this.dispatchEvent(refreshEvt); 36 | } 37 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/createCase/createCase.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 53.0 7 | true 8 | Create Case 9 | 10 | lightningCommunity__Page 11 | 12 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/errorPanel/errorPanel.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | import { reduceErrors } from 'c/ldsUtils'; 3 | import noDataIllustration from './templates/noDataIllustration.html'; 4 | import inlineMessage from './templates/inlineMessage.html'; 5 | 6 | export default class ErrorPanel extends LightningElement { 7 | /** Single or array of LDS errors */ 8 | @api errors; 9 | /** Generic / user-friendly message */ 10 | @api friendlyMessage = 'Error retrieving data'; 11 | /** Type of error message **/ 12 | @api type; 13 | 14 | viewDetails = false; 15 | 16 | get errorMessages() { 17 | return reduceErrors(this.errors); 18 | } 19 | 20 | handleShowDetailsClick() { 21 | this.viewDetails = !this.viewDetails; 22 | } 23 | 24 | render() { 25 | if (this.type === 'inlineMessage') return inlineMessage; 26 | return noDataIllustration; 27 | } 28 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/errorPanel/errorPanel.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/errorPanel/templates/inlineMessage.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/hero/hero.css: -------------------------------------------------------------------------------- 1 | :host { 2 | position: relative; 3 | display: block; 4 | } 5 | 6 | img, 7 | video { 8 | position: relative; 9 | width: 100%; 10 | } 11 | 12 | .c-hero-center-default, 13 | .c-hero-center-left { 14 | top: 30%; 15 | left: 10%; 16 | } 17 | 18 | .c-hero-center-right { 19 | top: 30%; 20 | right: 10%; 21 | } 22 | 23 | div { 24 | background-color: black; 25 | opacity: 0.5; 26 | top: 0; 27 | bottom: 0; 28 | left: 0; 29 | right: 0; 30 | position: absolute; 31 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/hero/hero.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/hero/hero.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | import IMAGE_URL from '@salesforce/resourceUrl/bike_assets'; 3 | 4 | const VIDEO = 'Video'; 5 | const IMAGE = 'Image'; 6 | 7 | /** 8 | * A Hero component that can display a Video or Image. 9 | */ 10 | export default class Hero extends LightningElement { 11 | @api title; 12 | @api slogan; 13 | @api buttonText; 14 | @api heroDetailsPosition; 15 | @api resourceUrl; 16 | @api imgOrVideo; 17 | @api internalResource; 18 | @api overlay; 19 | @api opacity; 20 | @api buttonClickProductOrFamilyName; 21 | 22 | get resUrl() { 23 | if (this.isImg) { 24 | if (this.internalResource) { 25 | return IMAGE_URL + this.resourceUrl; 26 | } 27 | } 28 | return this.resourceUrl; 29 | } 30 | 31 | get isVideo() { 32 | return this.imgOrVideo === VIDEO; 33 | } 34 | 35 | get isImg() { 36 | return this.imgOrVideo === IMAGE; 37 | } 38 | 39 | get isOverlay() { 40 | return this.overlay === 'true'; 41 | } 42 | 43 | // Apply CSS Class depending upon what position to put the hero text block 44 | get heroDetailsPositionClass() { 45 | if (this.heroDetailsPosition === 'left') { 46 | return 'c-hero-center-left'; 47 | } else if (this.heroDetailsPosition === 'right') { 48 | return 'c-hero-center-right'; 49 | } 50 | 51 | return 'c-hero-center-default'; 52 | } 53 | 54 | renderedCallback() { 55 | // Update the overlay with the opacity configured by the admin in builder 56 | const overlay = this.template.querySelector('div'); 57 | if (overlay) { 58 | overlay.style.opacity = parseInt(this.opacity, 10) / 10; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/hero/hero.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | true 5 | Hero 6 | 7 | lightningCommunity__Page 8 | lightningCommunity__Default 9 | 10 | 11 | 12 | 19 | 26 | 34 | 40 | 46 | 52 | 58 | 65 | 74 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/heroDetails/heroDetails.css: -------------------------------------------------------------------------------- 1 | :host { 2 | position: absolute; 3 | text-align: center; 4 | } 5 | 6 | h1, 7 | p { 8 | color: var(--lwc-colorTextButtonBrand, white); 9 | font-family: 'KlavikaWebRegularCond', 'Klavika', Helvetica; 10 | margin-bottom: 10px; 11 | font-weight: normal; 12 | letter-spacing: 0.14em; 13 | line-height: 1; 14 | font-size: 1.5rem; 15 | margin: 0.5em 0 0.74em; 16 | padding: 0; 17 | text-transform: uppercase; 18 | } 19 | 20 | h1 { 21 | letter-spacing: 0.03em; 22 | line-height: 0.88; 23 | margin: 0; 24 | font-size: 3rem; 25 | font-weight: bold; 26 | } 27 | 28 | a { 29 | text-align: center; 30 | padding: 4rem; 31 | padding-top: 0.5rem; 32 | padding-bottom: 0.5rem; 33 | border-radius: 10px; 34 | border: none; 35 | font-size: 1rem; 36 | font-weight: bold; 37 | text-transform: uppercase; 38 | } 39 | 40 | button:hover { 41 | background-position: right center; 42 | color: white; 43 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/heroDetails/heroDetails.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/heroDetails/heroDetails.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api, wire } from 'lwc'; 2 | import getRecordInfo from '@salesforce/apex/ProductRecordInfoController.getRecordInfo'; 3 | 4 | /** 5 | * Details component that is on top of the video. 6 | */ 7 | export default class HeroDetails extends LightningElement { 8 | @api title = 'Hero Details'; // Default title to comply with accessibility 9 | @api slogan; 10 | @api recordName; 11 | 12 | recordInfoData; 13 | hrefUrl; 14 | 15 | @wire(getRecordInfo, { productOrFamilyName: '$recordName' }) 16 | recordInfo({ error, data }) { 17 | this.recordInfoData = { error, data }; 18 | // Temporary workaround so that clicking on button navigates every time 19 | if (!error && data) { 20 | if (data[1] === 'Product__c') { 21 | this.hrefUrl = `product/${data[0]}`; 22 | } else { 23 | this.hrefUrl = `product-family/${data[0]}`; 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/heroDetails/heroDetails.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/ldsUtils/ldsUtils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Reduces one or more LDS errors into a string[] of error messages. 3 | * @param {FetchResponse|FetchResponse[]} errors 4 | * @return {String[]} Error messages 5 | */ 6 | export function reduceErrors(errors) { 7 | if (!Array.isArray(errors)) { 8 | errors = [errors]; 9 | } 10 | 11 | return ( 12 | errors 13 | // Remove null/undefined items 14 | .filter((error) => !!error) 15 | // Extract an error message 16 | .map((error) => { 17 | // UI API read errors 18 | if (Array.isArray(error.body)) { 19 | return error.body.map((e) => e.message); 20 | } 21 | // UI API DML, Apex and network errors 22 | else if (error.body && typeof error.body.message === 'string') { 23 | return error.body.message; 24 | } 25 | // JS errors 26 | else if (typeof error.message === 'string') { 27 | return error.message; 28 | } 29 | // Unknown error shape so try HTTP status text 30 | return error.statusText; 31 | }) 32 | // Flatten 33 | .reduce((prev, curr) => prev.concat(curr), []) 34 | // Remove empty strings 35 | .filter((message) => !!message) 36 | ); 37 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/ldsUtils/ldsUtils.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 53.0 7 | false 8 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/orderBuilder/orderBuilder.css: -------------------------------------------------------------------------------- 1 | header { 2 | padding: 12px 16px; 3 | background-color: rgba(194, 51, 53, 1); 4 | color: #ffffff; 5 | border-top-left-radius: 0.25rem; 6 | border-top-right-radius: 0.25rem; 7 | display: flex; 8 | } 9 | 10 | header .right { 11 | flex: 1; 12 | text-align: right; 13 | } 14 | 15 | .order-total { 16 | margin-left: 4px; 17 | } 18 | 19 | .drop-zone { 20 | background: rgb(243, 242, 242); 21 | display: flex; 22 | flex-wrap: wrap; 23 | border-bottom-left-radius: 0.25rem; 24 | border-bottom-right-radius: 0.25rem; 25 | } 26 | 27 | c-placeholder, 28 | c-order-item-tile { 29 | min-width: 250px; 30 | flex: 1; 31 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/orderBuilder/orderBuilder.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/orderBuilder/orderBuilder.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, wire, api } from 'lwc'; 2 | import { ShowToastEvent } from 'lightning/platformShowToastEvent'; 3 | import { reduceErrors } from 'c/ldsUtils'; 4 | 5 | /** Record DML operations. */ 6 | import { 7 | createRecord, 8 | updateRecord, 9 | deleteRecord 10 | } from 'lightning/uiRecordApi'; 11 | 12 | /** Use Apex to fetch related records. */ 13 | import { refreshApex, getSObjectValue } from '@salesforce/apex'; 14 | import getOrderItems from '@salesforce/apex/OrderController.getOrderItems'; 15 | 16 | /** Order_Item__c Schema. */ 17 | import ORDER_ITEM_OBJECT from '@salesforce/schema/Order_Item__c'; 18 | import ORDER_FIELD from '@salesforce/schema/Order_Item__c.Order__c'; 19 | import PRODUCT_FIELD from '@salesforce/schema/Order_Item__c.Product__c'; 20 | import QTY_SMALL_FIELD from '@salesforce/schema/Order_Item__c.Qty_S__c'; 21 | import QTY_MEDIUM_FIELD from '@salesforce/schema/Order_Item__c.Qty_M__c'; 22 | import QTY_LARGE_FIELD from '@salesforce/schema/Order_Item__c.Qty_L__c'; 23 | import PRICE_FIELD from '@salesforce/schema/Order_Item__c.Price__c'; 24 | 25 | /** Order_Item__c Schema. */ 26 | import PRODUCT_MSRP_FIELD from '@salesforce/schema/Product__c.MSRP__c'; 27 | 28 | /** Discount for resellers. TODO - move to custom field on Account. */ 29 | const DISCOUNT = 0.6; 30 | 31 | /** 32 | * Gets the quantity of all items in an Order_Item__c SObject. 33 | */ 34 | function getQuantity(orderItem) { 35 | return ( 36 | getSObjectValue(orderItem, QTY_SMALL_FIELD) + 37 | getSObjectValue(orderItem, QTY_MEDIUM_FIELD) + 38 | getSObjectValue(orderItem, QTY_LARGE_FIELD) 39 | ); 40 | } 41 | 42 | /** 43 | * Gets the price for the specified quantity of Order_Item__c SObject. 44 | */ 45 | function getPrice(orderItem, quantity) { 46 | return getSObjectValue(orderItem, PRICE_FIELD) * quantity; 47 | } 48 | 49 | /** 50 | * Calculates the quantity and price of all Order_Item__c SObjects. 51 | */ 52 | function calculateOrderSummary(orderItems) { 53 | const summary = orderItems.reduce( 54 | (acc, orderItem) => { 55 | const quantity = getQuantity(orderItem); 56 | const price = getPrice(orderItem, quantity); 57 | acc.quantity += quantity; 58 | acc.price += price; 59 | return acc; 60 | }, 61 | { quantity: 0, price: 0 } 62 | ); 63 | return summary; 64 | } 65 | 66 | /** 67 | * Builds Order__c by CRUD'ing the related Order_Item__c SObjects. 68 | */ 69 | export default class OrderBuilder extends LightningElement { 70 | /** Id of Order__c SObject to display. */ 71 | @api recordId; 72 | 73 | /** The Order_Item__c SObjects to display. */ 74 | orderItems; 75 | 76 | /** Total price of the Order__c. Calculated from this.orderItems. */ 77 | orderPrice = 0; 78 | 79 | /** Total quantity of the Order__c. Calculated from this.orderItems. */ 80 | orderQuantity = 0; 81 | 82 | error; 83 | 84 | /** Wired Apex result so it may be programmatically refreshed. */ 85 | wiredOrderItems; 86 | 87 | /** Apex load the Order__c's Order_Item_c[] and their related Product__c details. */ 88 | @wire(getOrderItems, { orderId: '$recordId' }) 89 | wiredGetOrderItems(value) { 90 | this.wiredOrderItems = value; 91 | if (value.error) { 92 | this.error = value.error; 93 | } else if (value.data) { 94 | this.setOrderItems(value.data); 95 | } 96 | } 97 | 98 | /** Updates the order items, recalculating the order quantity and price. */ 99 | setOrderItems(orderItems) { 100 | this.orderItems = orderItems.slice(); 101 | const summary = calculateOrderSummary(this.orderItems); 102 | this.orderQuantity = summary.quantity; 103 | this.orderPrice = summary.price; 104 | } 105 | 106 | /** Handles drag-and-dropping a new product to create a new Order_Item__c. */ 107 | handleDrop(event) { 108 | event.preventDefault(); 109 | // Product__c from LDS 110 | const product = JSON.parse(event.dataTransfer.getData('product')); 111 | 112 | // build new Order_Item__c record 113 | const fields = {}; 114 | fields[ORDER_FIELD.fieldApiName] = this.recordId; 115 | fields[PRODUCT_FIELD.fieldApiName] = product.Id; 116 | fields[PRICE_FIELD.fieldApiName] = Math.round( 117 | getSObjectValue(product, PRODUCT_MSRP_FIELD) * DISCOUNT 118 | ); 119 | 120 | // create Order_Item__c record on server 121 | const recordInput = { 122 | apiName: ORDER_ITEM_OBJECT.objectApiName, 123 | fields 124 | }; 125 | createRecord(recordInput) 126 | .then(() => { 127 | // refresh the Order_Item__c SObjects 128 | return refreshApex(this.wiredOrderItems); 129 | }) 130 | .catch((e) => { 131 | this.dispatchEvent( 132 | new ShowToastEvent({ 133 | title: 'Error creating order', 134 | message: reduceErrors(e).join(', '), 135 | variant: 'error' 136 | }) 137 | ); 138 | }); 139 | } 140 | 141 | /** Handles for dragging events. */ 142 | handleDragOver(event) { 143 | event.preventDefault(); 144 | } 145 | 146 | /** Handles event to change Order_Item__c details. */ 147 | handleOrderItemChange(evt) { 148 | const orderItemChanges = evt.detail; 149 | 150 | // optimistically make the change on the client 151 | const previousOrderItems = this.orderItems; 152 | const orderItems = this.orderItems.map((orderItem) => { 153 | if (orderItem.Id === orderItemChanges.Id) { 154 | // synthesize a new Order_Item__c SObject 155 | return Object.assign({}, orderItem, orderItemChanges); 156 | } 157 | return orderItem; 158 | }); 159 | this.setOrderItems(orderItems); 160 | 161 | // update Order_Item__c on the server 162 | const recordInput = { fields: orderItemChanges }; 163 | updateRecord(recordInput) 164 | .then(() => { 165 | // if there were triggers/etc that invalidate the Apex result then we'd refresh it 166 | // return refreshApex(this.wiredOrderItems); 167 | }) 168 | .catch((e) => { 169 | // error updating server so rollback to previous data 170 | this.setOrderItems(previousOrderItems); 171 | this.dispatchEvent( 172 | new ShowToastEvent({ 173 | title: 'Error updating order item', 174 | message: reduceErrors(e).join(', '), 175 | variant: 'error' 176 | }) 177 | ); 178 | }); 179 | } 180 | 181 | /** Handles event to delete Order_Item__c. */ 182 | handleOrderItemDelete(evt) { 183 | const id = evt.detail.id; 184 | 185 | // optimistically make the change on the client 186 | const previousOrderItems = this.orderItems; 187 | const orderItems = this.orderItems.filter( 188 | (orderItem) => orderItem.Id !== id 189 | ); 190 | this.setOrderItems(orderItems); 191 | 192 | // delete Order_Item__c SObject on the server 193 | deleteRecord(id) 194 | .then(() => { 195 | // if there were triggers/etc that invalidate the Apex result then we'd refresh it 196 | // return refreshApex(this.wiredOrderItems); 197 | }) 198 | .catch((e) => { 199 | // error updating server so rollback to previous data 200 | this.setOrderItems(previousOrderItems); 201 | this.dispatchEvent( 202 | new ShowToastEvent({ 203 | title: 'Error deleting order item', 204 | message: reduceErrors(e).join(', '), 205 | variant: 'error' 206 | }) 207 | ); 208 | }); 209 | } 210 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/orderBuilder/orderBuilder.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | true 5 | Order Builder 6 | 7 | lightning__AppPage 8 | lightning__RecordPage 9 | lightning__HomePage 10 | lightningCommunity__Page 11 | lightningCommunity__Default 12 | 13 | 14 | 15 | 16 | Order__c 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/orderItemTile/orderItemTile.css: -------------------------------------------------------------------------------- 1 | .content { 2 | padding: 8px 8px 12px 8px; 3 | background-color: #ffffff; 4 | position: relative; 5 | border-radius: 0.25rem; 6 | } 7 | 8 | img.product { 9 | height: 120px; 10 | max-width: initial; 11 | } 12 | 13 | .title { 14 | font-weight: bold; 15 | text-transform: uppercase; 16 | } 17 | 18 | .quantity { 19 | width: 58px; 20 | margin: 0 2px; 21 | } 22 | 23 | .price { 24 | width: 94px; 25 | margin: 0 2px; 26 | } 27 | 28 | .form { 29 | display: flex; 30 | } 31 | 32 | .save-button { 33 | position: absolute; 34 | top: 10px; 35 | right: 10px; 36 | } 37 | 38 | .delete-button { 39 | position: absolute; 40 | top: 10px; 41 | left: 10px; 42 | display: none; 43 | } 44 | 45 | .content:hover .delete-button { 46 | display: inherit; 47 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/orderItemTile/orderItemTile.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/orderItemTile/orderItemTile.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | 3 | /** 4 | * Displays an Order_Item__c SObject. Note that this component does not use schema imports and uses dynamic 5 | * references to the schema instead. For example, orderItem.Price__c (see template). The dynamic approach is 6 | * less verbose but does not provide referential integrity. The schema imports approach is more verbose but 7 | * enforces referential integrity: 1) The existence of the fields you reference is checked at compile time. 8 | * 2) Fields that are statically imported in a component cannot be deleted in the object model. 9 | */ 10 | export default class OrderItemTile extends LightningElement { 11 | /** Order_Item__c SObject to display. */ 12 | @api orderItem; 13 | 14 | /** Whether the component has unsaved changes. */ 15 | isModified = false; 16 | 17 | /** Mutated/unsaved Order_Item__c values. */ 18 | form = {}; 19 | 20 | /** Handles form input. */ 21 | handleFormChange(evt) { 22 | this.isModified = true; 23 | const field = evt.target.dataset.fieldName; 24 | let value = parseInt(evt.detail.value.trim(), 10); 25 | if (!Number.isInteger(value)) { 26 | value = 0; 27 | } 28 | this.form[field] = value; 29 | } 30 | 31 | /** Fires event to update the Order_Item__c SObject. */ 32 | 33 | saveOrderItem() { 34 | const event = new CustomEvent('orderitemchange', { 35 | detail: Object.assign({}, { Id: this.orderItem.Id }, this.form) 36 | }); 37 | this.dispatchEvent(event); 38 | this.isModified = false; 39 | } 40 | 41 | /** Fires event to delete the Order_Item__c SObject. */ 42 | deleteOrderItem() { 43 | const event = new CustomEvent('orderitemdelete', { 44 | detail: { id: this.orderItem.Id } 45 | }); 46 | this.dispatchEvent(event); 47 | } 48 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/orderItemTile/orderItemTile.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/paginator/paginator.css: -------------------------------------------------------------------------------- 1 | .nav-info { 2 | text-align: center; 3 | } 4 | 5 | .nav-next { 6 | text-align: right; 7 | height: 32px; 8 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/paginator/paginator.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/paginator/paginator.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | 3 | export default class Paginator extends LightningElement { 4 | /** The current page number. */ 5 | @api pageNumber; 6 | 7 | /** The number of items on a page. */ 8 | @api pageSize; 9 | 10 | /** The total number of items in the list. */ 11 | @api totalItemCount; 12 | 13 | handlePrevious() { 14 | this.dispatchEvent(new CustomEvent('previous')); 15 | } 16 | 17 | handleNext() { 18 | this.dispatchEvent(new CustomEvent('next')); 19 | } 20 | 21 | get currentPageNumber() { 22 | return this.totalItemCount === 0 ? 0 : this.pageNumber; 23 | } 24 | 25 | get isFirstPage() { 26 | return this.pageNumber === 1; 27 | } 28 | 29 | get isLastPage() { 30 | return this.pageNumber >= this.totalPages; 31 | } 32 | 33 | get totalPages() { 34 | return Math.ceil(this.totalItemCount / this.pageSize); 35 | } 36 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/paginator/paginator.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/placeholder/placeholder.css: -------------------------------------------------------------------------------- 1 | :host > div { 2 | text-align: center; 3 | color: #c23335; 4 | } 5 | 6 | img { 7 | height: 70px; 8 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/placeholder/placeholder.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/placeholder/placeholder.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | 3 | /** Static Resources. */ 4 | import BIKE_ASSETS_URL from '@salesforce/resourceUrl/bike_assets'; 5 | 6 | export default class Placeholder extends LightningElement { 7 | @api message; 8 | 9 | /** Url for bike logo. */ 10 | logoUrl = `${BIKE_ASSETS_URL}/logo.svg`; 11 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/placeholder/placeholder.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/productCard/productCard.css: -------------------------------------------------------------------------------- 1 | img.product { 2 | width: 100%; 3 | margin-bottom: 0.5rem; 4 | } 5 | 6 | section { 7 | font-weight: bold; 8 | font-size: 0.85rem; 9 | margin-top: 0.75rem; 10 | text-transform: uppercase; 11 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/productCard/productCard.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/productCard/productCard.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, wire } from 'lwc'; 2 | 3 | // Lightning Message Service and a message channel 4 | import { NavigationMixin } from 'lightning/navigation'; 5 | import { subscribe, MessageContext } from 'lightning/messageService'; 6 | import PRODUCT_SELECTED_MESSAGE from '@salesforce/messageChannel/ProductSelected__c'; 7 | 8 | // Utils to extract field values 9 | import { getFieldValue } from 'lightning/uiRecordApi'; 10 | 11 | // Product__c Schema 12 | import PRODUCT_OBJECT from '@salesforce/schema/Product__c'; 13 | import NAME_FIELD from '@salesforce/schema/Product__c.Name'; 14 | import PICTURE_URL_FIELD from '@salesforce/schema/Product__c.Picture_URL__c'; 15 | import CATEGORY_FIELD from '@salesforce/schema/Product__c.Category__c'; 16 | import LEVEL_FIELD from '@salesforce/schema/Product__c.Level__c'; 17 | import MSRP_FIELD from '@salesforce/schema/Product__c.MSRP__c'; 18 | import BATTERY_FIELD from '@salesforce/schema/Product__c.Battery__c'; 19 | import CHARGER_FIELD from '@salesforce/schema/Product__c.Charger__c'; 20 | import MOTOR_FIELD from '@salesforce/schema/Product__c.Motor__c'; 21 | import MATERIAL_FIELD from '@salesforce/schema/Product__c.Material__c'; 22 | import FOPK_FIELD from '@salesforce/schema/Product__c.Fork__c'; 23 | import FRONT_BRAKES_FIELD from '@salesforce/schema/Product__c.Front_Brakes__c'; 24 | import REAR_BRAKES_FIELD from '@salesforce/schema/Product__c.Rear_Brakes__c'; 25 | 26 | /** 27 | * Component to display details of a Product__c. 28 | */ 29 | export default class ProductCard extends NavigationMixin(LightningElement) { 30 | // Exposing fields to make them available in the template 31 | categoryField = CATEGORY_FIELD; 32 | levelField = LEVEL_FIELD; 33 | msrpField = MSRP_FIELD; 34 | batteryField = BATTERY_FIELD; 35 | chargerField = CHARGER_FIELD; 36 | motorField = MOTOR_FIELD; 37 | materialField = MATERIAL_FIELD; 38 | forkField = FOPK_FIELD; 39 | frontBrakesField = FRONT_BRAKES_FIELD; 40 | rearBrakesField = REAR_BRAKES_FIELD; 41 | 42 | // Id of Product__c to display 43 | recordId; 44 | 45 | // Product fields displayed with specific format 46 | productName; 47 | productPictureUrl; 48 | 49 | /** Load context for Lightning Messaging Service */ 50 | @wire(MessageContext) messageContext; 51 | 52 | /** Subscription for ProductSelected Lightning message */ 53 | productSelectionSubscription; 54 | 55 | connectedCallback() { 56 | // Subscribe to ProductSelected message 57 | this.productSelectionSubscription = subscribe( 58 | this.messageContext, 59 | PRODUCT_SELECTED_MESSAGE, 60 | (message) => this.handleProductSelected(message.productId) 61 | ); 62 | } 63 | 64 | handleRecordLoaded(event) { 65 | const { records } = event.detail; 66 | const recordData = records[this.recordId]; 67 | this.productName = getFieldValue(recordData, NAME_FIELD); 68 | this.productPictureUrl = getFieldValue(recordData, PICTURE_URL_FIELD); 69 | } 70 | 71 | /** 72 | * Handler for when a product is selected. When `this.recordId` changes, the 73 | * lightning-record-view-form component will detect the change and provision new data. 74 | */ 75 | handleProductSelected(productId) { 76 | this.recordId = productId; 77 | } 78 | 79 | handleNavigateToRecord() { 80 | this[NavigationMixin.Navigate]({ 81 | type: 'standard__recordPage', 82 | attributes: { 83 | recordId: this.recordId, 84 | objectApiName: PRODUCT_OBJECT.objectApiName, 85 | actionName: 'view' 86 | } 87 | }); 88 | } 89 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/productCard/productCard.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | true 5 | Product Card 6 | 7 | lightning__AppPage 8 | lightning__RecordPage 9 | lightning__HomePage 10 | lightningCommunity__Page 11 | 12 | 13 | 14 | 15 | Product__c 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/productFilter/productFilter.css: -------------------------------------------------------------------------------- 1 | section { 2 | margin-top: 16px; 3 | } 4 | 5 | section > h1 { 6 | font-weight: bold; 7 | text-transform: uppercase; 8 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/productFilter/productFilter.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/productFilter/productFilter.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, wire } from 'lwc'; 2 | import { getPicklistValues } from 'lightning/uiObjectInfoApi'; 3 | 4 | // Product schema 5 | import CATEGORY_FIELD from '@salesforce/schema/Product__c.Category__c'; 6 | import LEVEL_FIELD from '@salesforce/schema/Product__c.Level__c'; 7 | import MATERIAL_FIELD from '@salesforce/schema/Product__c.Material__c'; 8 | 9 | // Lightning Message Service and a message channel 10 | import { publish, MessageContext } from 'lightning/messageService'; 11 | import PRODUCTS_FILTERED_MESSAGE from '@salesforce/messageChannel/ProductsFiltered__c'; 12 | 13 | // The delay used when debouncing event handlers before firing the event 14 | const DELAY = 350; 15 | 16 | /** 17 | * Displays a filter panel to search for Product__c[]. 18 | */ 19 | export default class ProductFilter extends LightningElement { 20 | searchKey = ''; 21 | maxPrice = 10000; 22 | 23 | filters = { 24 | searchKey: '', 25 | maxPrice: 10000 26 | }; 27 | 28 | @wire(MessageContext) 29 | messageContext; 30 | 31 | @wire(getPicklistValues, { 32 | recordTypeId: '012000000000000AAA', 33 | fieldApiName: CATEGORY_FIELD 34 | }) 35 | categories; 36 | 37 | @wire(getPicklistValues, { 38 | recordTypeId: '012000000000000AAA', 39 | fieldApiName: LEVEL_FIELD 40 | }) 41 | levels; 42 | 43 | @wire(getPicklistValues, { 44 | recordTypeId: '012000000000000AAA', 45 | fieldApiName: MATERIAL_FIELD 46 | }) 47 | materials; 48 | 49 | handleSearchKeyChange(event) { 50 | this.filters.searchKey = event.target.value; 51 | this.delayedFireFilterChangeEvent(); 52 | } 53 | 54 | handleMaxPriceChange(event) { 55 | const maxPrice = event.target.value; 56 | this.filters.maxPrice = maxPrice; 57 | this.delayedFireFilterChangeEvent(); 58 | } 59 | 60 | handleCheckboxChange(event) { 61 | if (!this.filters.categories) { 62 | // Lazy initialize filters with all values initially set 63 | this.filters.categories = this.categories.data.values.map( 64 | (item) => item.value 65 | ); 66 | this.filters.levels = this.levels.data.values.map( 67 | (item) => item.value 68 | ); 69 | this.filters.materials = this.materials.data.values.map( 70 | (item) => item.value 71 | ); 72 | } 73 | const value = event.target.dataset.value; 74 | const filterArray = this.filters[event.target.dataset.filter]; 75 | if (event.target.checked) { 76 | if (!filterArray.includes(value)) { 77 | filterArray.push(value); 78 | } 79 | } else { 80 | this.filters[event.target.dataset.filter] = filterArray.filter( 81 | (item) => item !== value 82 | ); 83 | } 84 | // Published ProductsFiltered message 85 | publish(this.messageContext, PRODUCTS_FILTERED_MESSAGE, { 86 | filters: this.filters 87 | }); 88 | } 89 | 90 | delayedFireFilterChangeEvent() { 91 | // Debouncing this method: Do not actually fire the event as long as this function is 92 | // being called within a delay of DELAY. This is to avoid a very large number of Apex 93 | // method calls in components listening to this event. 94 | window.clearTimeout(this.delayTimeout); 95 | // eslint-disable-next-line @lwc/lwc/no-async-operation 96 | this.delayTimeout = setTimeout(() => { 97 | // Published ProductsFiltered message 98 | publish(this.messageContext, PRODUCTS_FILTERED_MESSAGE, { 99 | filters: this.filters 100 | }); 101 | }, DELAY); 102 | } 103 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/productFilter/productFilter.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | true 5 | Product Filter 6 | 7 | lightning__AppPage 8 | lightning__HomePage 9 | lightningCommunity__Page 10 | 11 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/productListItem/productListItem.css: -------------------------------------------------------------------------------- 1 | img.product { 2 | height: 80px; 3 | max-width: initial; 4 | pointer-events: none; 5 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/productListItem/productListItem.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/productListItem/productListItem.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | import { NavigationMixin } from 'lightning/navigation'; 3 | import PRODUCT_OBJECT from '@salesforce/schema/Product__c'; 4 | 5 | /** 6 | * A presentation component to display a Product__c sObject. The provided 7 | * Product__c data must contain all fields used by this component. 8 | */ 9 | export default class ProductListItem extends NavigationMixin(LightningElement) { 10 | @api product; 11 | 12 | /** View Details Handler to navigates to the record page */ 13 | handleViewDetailsClick() { 14 | this[NavigationMixin.Navigate]({ 15 | type: 'standard__recordPage', 16 | attributes: { 17 | recordId: this.product.Id, 18 | objectApiName: PRODUCT_OBJECT.objectApiName, 19 | actionName: 'view' 20 | } 21 | }); 22 | } 23 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/productListItem/productListItem.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/productTile/productTile.css: -------------------------------------------------------------------------------- 1 | .content { 2 | padding: 8px; 3 | background-color: #ffffff; 4 | border-radius: 0.25rem; 5 | } 6 | 7 | a { 8 | color: inherit; 9 | } 10 | 11 | img.product { 12 | height: 120px; 13 | max-width: initial; 14 | pointer-events: none; 15 | } 16 | 17 | .title { 18 | font-weight: bold; 19 | text-transform: uppercase; 20 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/productTile/productTile.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/productTile/productTile.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api } from 'lwc'; 2 | 3 | /** 4 | * A presentation component to display a Product__c sObject. The provided 5 | * Product__c data must contain all fields used by this component. 6 | */ 7 | export default class ProductTile extends LightningElement { 8 | /** Whether the tile is draggable. */ 9 | @api draggable; 10 | 11 | _product; 12 | /** Product__c to display. */ 13 | @api 14 | get product() { 15 | return this._product; 16 | } 17 | set product(value) { 18 | this._product = value; 19 | this.pictureUrl = value.Picture_URL__c; 20 | this.name = value.Name; 21 | this.msrp = value.MSRP__c; 22 | } 23 | 24 | /** Product__c field values to display. */ 25 | pictureUrl; 26 | name; 27 | msrp; 28 | 29 | handleClick() { 30 | const selectedEvent = new CustomEvent('selected', { 31 | detail: this.product.Id 32 | }); 33 | this.dispatchEvent(selectedEvent); 34 | } 35 | 36 | handleDragStart(event) { 37 | event.dataTransfer.setData('product', JSON.stringify(this.product)); 38 | } 39 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/productTile/productTile.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | true 5 | Product Tile 6 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/productTileList/productTileList.css: -------------------------------------------------------------------------------- 1 | .slds-card { 2 | background: rgb(243, 242, 242); 3 | } 4 | 5 | .search-bar { 6 | display: block; 7 | margin: 0 0.5rem 0.3rem 0.5rem; 8 | } 9 | 10 | .content { 11 | display: flex; 12 | flex-wrap: wrap; 13 | } 14 | 15 | c-product-tile { 16 | min-width: 200px; 17 | flex: 1; 18 | } 19 | 20 | c-paginator { 21 | display: block; 22 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/productTileList/productTileList.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/productTileList/productTileList.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api, wire } from 'lwc'; 2 | 3 | // Lightning Message Service and message channels 4 | import { publish, subscribe, MessageContext } from 'lightning/messageService'; 5 | import PRODUCTS_FILTERED_MESSAGE from '@salesforce/messageChannel/ProductsFiltered__c'; 6 | import PRODUCT_SELECTED_MESSAGE from '@salesforce/messageChannel/ProductSelected__c'; 7 | 8 | // getProducts() method in ProductController Apex class 9 | import getProducts from '@salesforce/apex/ProductController.getProducts'; 10 | 11 | /** 12 | * Container component that loads and displays a list of Product__c records. 13 | */ 14 | export default class ProductTileList extends LightningElement { 15 | /** 16 | * Whether to display the search bar. 17 | * TODO - normalize value because it may come as a boolean, string or otherwise. 18 | */ 19 | @api searchBarIsVisible = false; 20 | 21 | /** 22 | * Whether the product tiles are draggable. 23 | * TODO - normalize value because it may come as a boolean, string or otherwise. 24 | */ 25 | @api tilesAreDraggable = false; 26 | 27 | /** Current page in the product list. */ 28 | pageNumber = 1; 29 | 30 | /** The number of items on a page. */ 31 | pageSize; 32 | 33 | /** The total number of items matching the selection. */ 34 | totalItemCount = 0; 35 | 36 | /** JSON.stringified version of filters to pass to apex */ 37 | filters = {}; 38 | 39 | /** Load context for Lightning Messaging Service */ 40 | @wire(MessageContext) messageContext; 41 | 42 | /** Subscription for ProductsFiltered Lightning message */ 43 | productFilterSubscription; 44 | 45 | /** 46 | * Load the list of available products. 47 | */ 48 | @wire(getProducts, { filters: '$filters', pageNumber: '$pageNumber' }) 49 | products; 50 | 51 | connectedCallback() { 52 | // Subscribe to ProductsFiltered message 53 | this.productFilterSubscription = subscribe( 54 | this.messageContext, 55 | PRODUCTS_FILTERED_MESSAGE, 56 | (message) => this.handleFilterChange(message) 57 | ); 58 | } 59 | 60 | handleProductSelected(event) { 61 | // Published ProductSelected message 62 | publish(this.messageContext, PRODUCT_SELECTED_MESSAGE, { 63 | productId: event.detail 64 | }); 65 | } 66 | 67 | handleSearchKeyChange(event) { 68 | this.filters = { 69 | searchKey: event.target.value.toLowerCase() 70 | }; 71 | this.pageNumber = 1; 72 | } 73 | 74 | handleFilterChange(message) { 75 | this.filters = { ...message.filters }; 76 | this.pageNumber = 1; 77 | } 78 | 79 | handlePreviousPage() { 80 | this.pageNumber = this.pageNumber - 1; 81 | } 82 | 83 | handleNextPage() { 84 | this.pageNumber = this.pageNumber + 1; 85 | } 86 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/productTileList/productTileList.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | true 5 | Product Tile List 6 | 7 | lightning__AppPage 8 | lightning__RecordPage 9 | lightning__HomePage 10 | lightningCommunity__Page 11 | lightningCommunity__Default 12 | 13 | 14 | 15 | 20 | 25 | 26 | Order__c 27 | 28 | 29 | 30 | 35 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/similarProducts/similarProducts.css: -------------------------------------------------------------------------------- 1 | img.product { 2 | height: 120px; 3 | max-width: initial; 4 | pointer-events: none; 5 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/similarProducts/similarProducts.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/lwc/similarProducts/similarProducts.js: -------------------------------------------------------------------------------- 1 | import { LightningElement, api, wire } from 'lwc'; 2 | import { getRecord } from 'lightning/uiRecordApi'; 3 | import getSimilarProducts from '@salesforce/apex/ProductController.getSimilarProducts'; 4 | import PRODUCT_FAMILY_FIELD from '@salesforce/schema/Product__c.Product_Family__c'; 5 | 6 | const fields = [PRODUCT_FAMILY_FIELD]; 7 | 8 | export default class SimilarProducts extends LightningElement { 9 | @api recordId; 10 | @api familyId; 11 | 12 | // Track changes to the Product_Family__c field that could be made in other components. 13 | // If Product_Family__c is updated in another component, getSimilarProducts 14 | // is automatically re-invoked with the new this.familyId parameter 15 | @wire(getRecord, { recordId: '$recordId', fields }) 16 | product; 17 | 18 | @wire(getSimilarProducts, { 19 | productId: '$recordId', 20 | familyId: '$product.data.fields.Product_Family__c.value' 21 | }) 22 | similarProducts; 23 | 24 | get errors() { 25 | const errors = [this.product.error, this.similarProducts.error].filter( 26 | (error) => error 27 | ); 28 | return errors.length ? errors : undefined; 29 | } 30 | } -------------------------------------------------------------------------------- /force-app/main/default/lwc/similarProducts/similarProducts.js-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | true 5 | Similar Products 6 | 7 | lightning__RecordPage 8 | lightningCommunity__Page 9 | lightningCommunity__Default 10 | 11 | 12 | 13 | 14 | Product__c 15 | 16 | 17 | 18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /force-app/main/default/pages/AnswersHome.page: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/pages/AnswersHome.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Lightning Platform home page for Answers sites 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/BandwidthExceeded.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 | 11 |
12 |
13 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/BandwidthExceeded.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Lightning Platform Limit Exceeded page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/ChangePassword.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 |
8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 |
34 | 35 |
36 |
37 |
38 |
39 |
40 |
41 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/ChangePassword.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Salesforce Sites Change Password page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/CommunitiesLanding.page: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/pages/CommunitiesLanding.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default communities landing page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/CommunitiesLogin.page: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /force-app/main/default/pages/CommunitiesLogin.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default experiences login page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/CommunitiesSelfReg.page: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 | 28 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/CommunitiesSelfReg.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default experiences self registration page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/CommunitiesSelfRegConfirm.page: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 | 8 |
9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 |
17 | {!$Label.site.go_to_login_page} 18 |
19 |
20 |
21 |
22 | 23 |
24 |
25 |
26 |
27 |
28 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/CommunitiesSelfRegConfirm.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default experiences self registration confirmation page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/CommunitiesTemplate.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/pages/CommunitiesTemplate.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default template for experiences pages 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/Exception.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 |
8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 |
22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 |
33 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/Exception.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Lightning Platform page for post-authentication errors 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/FileNotFound.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 |
8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 |
30 | 31 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/FileNotFound.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Lightning Platform Page/Data Not Found page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/ForgotPassword.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 |
8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 |
35 |
36 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/ForgotPassword.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Salesforce Sites Forgot Password Confirmation page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/ForgotPasswordConfirm.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 |
8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 |
18 | {!$Label.site.go_to_login_page} 19 |
20 |
21 |
22 |
23 | 24 |
25 |
26 |
27 |
28 |
29 |
30 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/ForgotPasswordConfirm.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Salesforce Sites Forgot Password Confirmation page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/IdeasHome.page: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /force-app/main/default/pages/IdeasHome.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Lightning Platform home page for ideas sites 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/InMaintenance.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 |
14 |
15 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/InMaintenance.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Lightning Platform In Maintenance page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/MyProfilePage.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /force-app/main/default/pages/MyProfilePage.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Salesforce Sites My Profile page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/SiteLogin.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 |
8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 |
19 |
20 |
21 |
22 | 23 |
24 |
25 |
26 |
27 |
28 |
29 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/SiteLogin.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Salesforce Sites Login page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/SiteRegister.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 |
8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/SiteRegister.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Salesforce Sites User Registration page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/SiteRegisterConfirm.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 |
8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 |
18 | {!$Label.site.go_to_login_page} 19 |
20 |
21 |
22 |
23 | 24 |
25 |
26 |
27 |
28 |
29 |
30 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/SiteRegisterConfirm.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Salesforce Sites User Registration Confirmation page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/SiteTemplate.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 |
7 | 8 | 9 |
10 | 11 | 12 |
13 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/SiteTemplate.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Lightning Platform template for site pages 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/StdExceptionTemplate.page: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |
7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/StdExceptionTemplate.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Lightning Platform template for standard exception pages 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/Unauthorized.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 |
8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 | 19 |
20 | 21 |
22 |
23 |
24 | 25 | 26 | 27 |
28 |
29 |
30 | 31 |
32 |
33 |
34 |
35 |
36 |
37 | 38 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/Unauthorized.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Lightning Platform Authorization Required page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/pages/UnderConstruction.page: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 |
14 |
15 |
-------------------------------------------------------------------------------- /force-app/main/default/pages/UnderConstruction.page-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53.0 4 | false 5 | false 6 | Default Lightning Platform Under Construction page 7 | 8 | 9 | 1 10 | 7 11 | sf_com_apps 12 | 13 | 14 | 1 15 | 6 16 | trlhdtips 17 | 18 | 19 | -------------------------------------------------------------------------------- /force-app/main/default/staticresources/SiteSamples.resource-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Public 4 | application/zip 5 | Static resource for sites sample pages 6 | 7 | -------------------------------------------------------------------------------- /force-app/main/default/staticresources/SiteSamples/SiteStyles.css: -------------------------------------------------------------------------------- 1 | .topPanelContainer { 2 | text-align:left; 3 | border:1px solid #ccc; 4 | } 5 | 6 | .topPanel { 7 | background-color: white; 8 | border: 1px solid #ccc; 9 | padding: 0px; 10 | margin-top: 10px; 11 | margin-bottom: 0px; 12 | margin-left: 10px; 13 | margin-right: 10px; 14 | } 15 | 16 | .title { 17 | font-size: larger; 18 | font-weight: bold; 19 | } 20 | 21 | .poweredByImage { 22 | vertical-align: middle; 23 | margin:12px 8px 8px 0; 24 | } 25 | 26 | img { 27 | border: none; 28 | } -------------------------------------------------------------------------------- /force-app/main/default/staticresources/SiteSamples/img/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/SiteSamples/img/clock.png -------------------------------------------------------------------------------- /force-app/main/default/staticresources/SiteSamples/img/construction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/SiteSamples/img/construction.png -------------------------------------------------------------------------------- /force-app/main/default/staticresources/SiteSamples/img/force_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/SiteSamples/img/force_logo.png -------------------------------------------------------------------------------- /force-app/main/default/staticresources/SiteSamples/img/maintenance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/SiteSamples/img/maintenance.png -------------------------------------------------------------------------------- /force-app/main/default/staticresources/SiteSamples/img/poweredby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/SiteSamples/img/poweredby.png -------------------------------------------------------------------------------- /force-app/main/default/staticresources/SiteSamples/img/tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/SiteSamples/img/tools.png -------------------------------------------------------------------------------- /force-app/main/default/staticresources/SiteSamples/img/unauthorized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/SiteSamples/img/unauthorized.png -------------------------------------------------------------------------------- /force-app/main/default/staticresources/SiteSamples/img/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/SiteSamples/img/warning.png -------------------------------------------------------------------------------- /force-app/main/default/staticresources/bike_assets.resource-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Public 4 | application/zip 5 | 6 | -------------------------------------------------------------------------------- /force-app/main/default/staticresources/bike_assets/CyclingGrass.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/bike_assets/CyclingGrass.jpg -------------------------------------------------------------------------------- /force-app/main/default/staticresources/bike_assets/commuter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/bike_assets/commuter.png -------------------------------------------------------------------------------- /force-app/main/default/staticresources/bike_assets/enthusiast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/bike_assets/enthusiast.png -------------------------------------------------------------------------------- /force-app/main/default/staticresources/bike_assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Slice 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /force-app/main/default/staticresources/bike_assets/racer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/salto-io/salesforce-ci-cd-org-dev/ca2177829b49b0fce1167ad4c93ea0190293f9ad/force-app/main/default/staticresources/bike_assets/racer.png -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const { jestConfig } = require('@salesforce/sfdx-lwc-jest/config'); 2 | 3 | module.exports = { 4 | ...jestConfig, 5 | modulePathIgnorePatterns: ['/.localdevserver'] 6 | }; 7 | -------------------------------------------------------------------------------- /manifest/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | * 5 | ApexClass 6 | 7 | 8 | * 9 | ApexComponent 10 | 11 | 12 | * 13 | ApexPage 14 | 15 | 16 | * 17 | ApexTestSuite 18 | 19 | 20 | * 21 | ApexTrigger 22 | 23 | 24 | * 25 | AuraDefinitionBundle 26 | 27 | 28 | * 29 | LightningComponentBundle 30 | 31 | 32 | * 33 | StaticResource 34 | 35 | 52.0 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "salesforce-app", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "Salesforce App", 6 | "scripts": { 7 | "lint": "eslint **/{aura,lwc}/**", 8 | "test": "npm run test:unit", 9 | "test:unit": "sfdx-lwc-jest", 10 | "test:unit:watch": "sfdx-lwc-jest --watch", 11 | "test:unit:debug": "sfdx-lwc-jest --debug", 12 | "test:unit:coverage": "sfdx-lwc-jest --coverage", 13 | "prettier": "prettier --write \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"", 14 | "prettier:verify": "prettier --list-different \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"", 15 | "postinstall": "husky install", 16 | "precommit": "lint-staged" 17 | }, 18 | "devDependencies": { 19 | "@lwc/eslint-plugin-lwc": "^1.0.1", 20 | "@prettier/plugin-xml": "^0.13.1", 21 | "@salesforce/eslint-config-lwc": "^2.0.0", 22 | "@salesforce/eslint-plugin-aura": "^2.0.0", 23 | "@salesforce/eslint-plugin-lightning": "^0.1.1", 24 | "@salesforce/sfdx-lwc-jest": "^0.13.0", 25 | "eslint": "^7.29.0", 26 | "eslint-plugin-import": "^2.23.4", 27 | "eslint-plugin-jest": "^24.3.6", 28 | "husky": "^7.0.0", 29 | "lint-staged": "^11.0.0", 30 | "prettier": "^2.3.2", 31 | "prettier-plugin-apex": "^1.10.1" 32 | }, 33 | "lint-staged": { 34 | "**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}": [ 35 | "prettier --write" 36 | ], 37 | "**/{aura,lwc}/**": [ 38 | "eslint" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /parsePR.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const readline = require('readline') 3 | 4 | async function extractTests(){ 5 | 6 | //by default we specify that all tests should run 7 | let testsFile = __dirname+'/testsToRun.txt'; 8 | await fs.promises.writeFile(testsFile,'all'); 9 | 10 | const lines = readline.createInterface({ 11 | input: fs.createReadStream(__dirname+'/pr_body.txt'), 12 | crlfDelay: Infinity 13 | }); 14 | 15 | for await (const line of lines) { 16 | //special delimeter for apex tests 17 | if(line.includes('Apex::[') && line.includes(']::Apex')){ 18 | 19 | let tests = line.substring(8,line.length-7); 20 | await fs.promises.writeFile(testsFile,tests); 21 | await fs.promises.appendFile(testsFile,'\n'); 22 | } 23 | } 24 | } 25 | 26 | extractTests(); -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Please include a summary of the change and what has changed. 4 | 5 | ### Jira Ticket 6 | 7 | CRM-XXX 8 | 9 | ### Apex Tests to Run 10 | 11 | Apex::[all]::Apex -------------------------------------------------------------------------------- /scripts/apex/hello.apex: -------------------------------------------------------------------------------- 1 | // Use .apex files to store anonymous Apex. 2 | // You can execute anonymous Apex in VS Code by selecting the 3 | // apex text and running the command: 4 | // SFDX: Execute Anonymous Apex with Currently Selected Text 5 | // You can also execute the entire file by running the command: 6 | // SFDX: Execute Anonymous Apex with Editor Contents 7 | 8 | string tempvar = 'Enter_your_name_here'; 9 | System.debug('Hello World!'); 10 | System.debug('My name is ' + tempvar); -------------------------------------------------------------------------------- /scripts/soql/account.soql: -------------------------------------------------------------------------------- 1 | // Use .soql files to store SOQL queries. 2 | // You can execute queries in VS Code by selecting the 3 | // query text and running the command: 4 | // SFDX: Execute SOQL Query with Currently Selected Text 5 | 6 | SELECT Id, Name FROM Account 7 | -------------------------------------------------------------------------------- /sfdx-project.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageDirectories": [ 3 | { 4 | "path": "force-app", 5 | "default": true 6 | } 7 | ], 8 | "name": "Salesforce-Org-Development", 9 | "namespace": "", 10 | "sfdcLoginUrl": "https://login.salesforce.com", 11 | "sourceApiVersion": "52.0" 12 | } 13 | --------------------------------------------------------------------------------