Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [FC-0044] Course unit - Copy/paste functionality #884

Merged

Conversation

PKulkoRaccoonGang
Copy link
Contributor

@PKulkoRaccoonGang PKulkoRaccoonGang commented Mar 10, 2024

Settings

EDX_PLATFORM_REPOSITORY: https://github.com/raccoongang/edx-platform.git
EDX_PLATFORM_VERSION: ts-develop

TUTOR_GROVE_WAFFLE_FLAGS:
  - name: contentstore.new_studio_mfe.use_new_unit_page
    everyone: true

TUTOR_GROVE_MFE_LMS_COMMON_SETTINGS:
  MFE_CONFIG:
    ENABLE_UNIT_PAGE: true

Description

In this PR, the opportunity for the user to copy and insert xblocks and units was added.

The primary features were implemented:

  • A new Copy/paste functionality.

Issue: openedx/platform-roadmap#321

Developer notes

Testing instructions

  1. Run master devstack.
  2. Start platform make dev.up.lms+cms+frontend-app-course-authoring and make checkout on this branch.
  3. Enable the new Unit page by adding a waffle flag contentstore.new_studio_mfe.use_new_unit_page in the CMS admin panel.
  4. Make sure that the MFE setting ENABLE_UNIT_PAGE=true is enabled.
  5. Enable contentstore.enable_copy_paste_units a waffle flag in the CMS admin panel.
  6. Go to the Course Unit page from the Course Outline page.
Screen.Recording.2024-03-10.at.17.08.32.mov

@PKulkoRaccoonGang PKulkoRaccoonGang requested a review from a team as a code owner March 10, 2024 14:06
@openedx-webhooks openedx-webhooks added the open-source-contribution PR author is not from Axim or 2U label Mar 10, 2024
@openedx-webhooks
Copy link

openedx-webhooks commented Mar 10, 2024

Thanks for the pull request, @PKulkoRaccoonGang! Please note that it may take us up to several weeks or months to complete a review and merge your PR.

Feel free to add as much of the following information to the ticket as you can:

  • supporting documentation
  • Open edX discussion forum threads
  • timeline information ("this must be merged by XX date", and why that is)
  • partner information ("this is a course on edx.org")
  • any other information that can help Product understand the context for the PR

All technical communication about the code itself will be done via the GitHub pull request interface. As a reminder, our process documentation is here.

Please let us know once your PR is ready for our review and all tests are green.

Copy link

codecov bot commented Mar 10, 2024

Codecov Report

Attention: Patch coverage is 90.82126% with 19 lines in your changes are missing coverage. Please review.

Project coverage is 92.02%. Comparing base (6ec44b5) to head (bf62229).
Report is 7 commits behind head on master.

Files Patch % Lines
src/generic/clipboard/paste-component/index.jsx 75.00% 4 Missing ⚠️
src/generic/data/thunks.js 76.47% 4 Missing ⚠️
...rd/paste-component/components/WhatsInClipboard.jsx 78.57% 3 Missing ⚠️
src/generic/data/api.js 57.14% 3 Missing ⚠️
...nce/sequence-navigation/SequenceNavigationTabs.jsx 77.77% 2 Missing ⚠️
src/course-unit/data/selectors.js 71.42% 2 Missing ⚠️
src/course-unit/data/thunk.js 92.85% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #884      +/-   ##
==========================================
- Coverage   92.14%   92.02%   -0.12%     
==========================================
  Files         637      686      +49     
  Lines       11149    11955     +806     
  Branches     2407     2571     +164     
==========================================
+ Hits        10273    11002     +729     
- Misses        847      917      +70     
- Partials       29       36       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@PKulkoRaccoonGang PKulkoRaccoonGang force-pushed the Peter_Kulko/copy-paste-functionality branch from af87165 to 5435ce0 Compare March 10, 2024 14:21
@PKulkoRaccoonGang PKulkoRaccoonGang added the create-sandbox open-craft-grove should create a sandbox environment from this PR label Mar 10, 2024
@PKulkoRaccoonGang PKulkoRaccoonGang changed the title feat: Copy/paste functionality feat: Course unit - Copy/paste functionality Mar 10, 2024
@PKulkoRaccoonGang PKulkoRaccoonGang changed the title feat: Course unit - Copy/paste functionality feat: [FC-0044] Course unit - Copy/paste functionality Mar 10, 2024
@PKulkoRaccoonGang PKulkoRaccoonGang self-assigned this Mar 10, 2024
@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@PKulkoRaccoonGang PKulkoRaccoonGang added create-sandbox open-craft-grove should create a sandbox environment from this PR and removed create-sandbox open-craft-grove should create a sandbox environment from this PR labels Mar 10, 2024
@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@PKulkoRaccoonGang PKulkoRaccoonGang added create-sandbox open-craft-grove should create a sandbox environment from this PR and removed create-sandbox open-craft-grove should create a sandbox environment from this PR labels Mar 10, 2024
@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@PKulkoRaccoonGang
Copy link
Contributor Author

@arbrandes The initial 1 commit in this PR is temporary. Once the #882 is merged, the third commit of this PR will become the main commit.

@bradenmacdonald
Copy link
Contributor

bradenmacdonald commented Mar 11, 2024

Bug 1:

When I have the course outline open in one tab:
Screenshot 2024-03-11 at 12 48 12 PM
And then I click "copy unit" in another tab:
Screenshot 2024-03-11 at 12 48 47 PM
The copy seems to work, but the broadcast event causes an error to appear on the outline page:
Screenshot 2024-03-11 at 12 49 35 PM

(Also: if I have the old outline page open, then I copy a block on the new MFE unit page, the old outline page doesn't update. I guess they are using different broadcast channels? Is that intentional? It's fine because we don't need to support the old pages at the same time as the new ones - but it makes it harder to test when they're not compatible. Edit: never mind, they're on separate domains so obviously they can't sync with a BroadcastChannel.)

Bug 2: When I copy a unit from the new MFE outline page, it syncs to any other tabs that have the new MFE outline page open, but it doesn't sync to this unit page.

@bradenmacdonald
Copy link
Contributor

bradenmacdonald commented Mar 11, 2024

Bug. 3: I can't get the "Paste component" button to appear. I can see there is code for it but when I copy a component, nothing happens. (It does copy to the clipboard, as I can verify using the old unit page, but no button appears in the new MFE.)

This one:
Screenshot 2024-03-11 at 1 02 54 PM

No error appears in the console.

@PKulkoRaccoonGang PKulkoRaccoonGang marked this pull request as draft March 12, 2024 09:26
@PKulkoRaccoonGang
Copy link
Contributor Author

@bradenmacdonald thanks for your contribution 💯

Bug 1 and Bug 2

Now we can notice the use of two different approaches to working with BroadcastChannel. I have two options for solving these differences. Tomorrow after a discussion with the team I will provide you with more information.

(Also: if I have the old outline page open, then I copy a block on the new MFE unit page, the old outline page doesn't update. I guess they are using different broadcast channels? Is that intentional? It's fine because we don't need to support the old pages at the same time as the new ones - but it makes it harder to test when they're not compatible. Edit: never mind, they're on separate domains so obviously they can't sync with a BroadcastChannel.)

Yes, you are right. Now we are not able to use the BroadcastChannel (between MFE and Legacy) without reloading the page, but for testing, after copying an element in MFE, you can reload the page in Legacy.

Bug. 3: I can't get the "Paste component" button to appear. I can see there is code for it but when I copy a component, nothing happens. (It does copy to the clipboard, as I can verify using the old unit page, but no button appears in the new MFE.)

Have you tried seeing the button after copying a unit?

@bradenmacdonald
Copy link
Contributor

Have you tried seeing the button after copying a unit?

Yes, that works (the button appears at the top of the page). But when I copy a component (XBlock, not a unit), the button at the bottom of the page does not appear for me.

@bradenmacdonald
Copy link
Contributor

@PKulkoRaccoonGang OK, the reason that the "paste component" button was not working on my devstack is it was missing this commit:

raccoongang/edx-platform@b686d70

Is there a PR to merge that to master edx-platform?

@PKulkoRaccoonGang
Copy link
Contributor Author

@bradenmacdonald Yes, this PR is not yet available in the upstream. I recommend using a sandbox (or the branch specified in the sandbox deployment configuration) for testing. This way you will have the most current version of the platform.

Now we can notice the use of two different approaches to working with BroadcastChannel. I have two options for solving these differences. Tomorrow after a discussion with the team I will provide you with more information.

After a discussion with the team, we decided to fix and check the communication of the Copy/paste functionality between the Course outline and Course unit pages and refactor (move elements that are repeated on both pages into generics). In order not to block the flow of delivery of new features, we propose to do this within a separate PR, which we will later open after development and testing.

@arbrandes
Copy link
Contributor

#882 is merged. @PKulkoRaccoonGang, mind rebasing? Probably good to upgrade the PR off of Draft, too.

@arbrandes
Copy link
Contributor

Or rather, let's leave it in draft until it doesn't depend on any other PRs. Is there one for raccoongang/edx-platform@b686d70, yet?

@PKulkoRaccoonGang PKulkoRaccoonGang force-pushed the Peter_Kulko/copy-paste-functionality branch from 5435ce0 to 14eba02 Compare March 13, 2024 15:13
@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@PKulkoRaccoonGang PKulkoRaccoonGang marked this pull request as ready for review April 15, 2024 13:52
@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

Copy link
Contributor

@bradenmacdonald bradenmacdonald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This seems much nicer but unfortunately the "paste component" button is still not showing up for me. I'm not sure why?

The "paste unit" appears to be working correctly.

xblock-clipboard-missing.mov

Also, it seems to be missing some kind of notification that the copy worked (or not)?

package.json Outdated
@@ -121,5 +120,8 @@
},
"peerDependencies": {
"decode-uri-component": ">=0.2.2"
},
"overrides": {
"react-intl": "^6.4.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to include this override here? I don't think we should be specifying the react-intl version as it comes from frontend-platform.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that better to use react-intl from the frontend-platform. Let's remove it and look that all CI checks were successful.

src/constants.js Outdated
error: 'error',
};

export const NOT_XBLOCK_TYPES = ['vertical', 'sequential', 'chapter', 'course'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the name of this variable is very clear. Technically, those are XBlocks. Maybe NOT_COMPONENT_TYPES or STRUCTURAL_XBLOCK_TYPES or add a comment with more details about what this is?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to STRUCTURAL_XBLOCK_TYPES

});

await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch);
await executeThunk(copyToClipboard(blockId), store.dispatch);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you have to manually call these thunks in the test case? I would have expected that the line above, userEvent.click(getByRole('button', { name: ...CopyToClipboard... })); will trigger the thunks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was an extra call of executeThunk and was removed, thanks

const messages = defineMessages({
hasConflictingErrorsTitle: {
id: 'course-authoring.course-unit.paste-notification.has-conflicting-errors.title',
defaultMessage: 'Files need to be updated manually.',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe all messages should now have a description in our MFE codebases.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Descriptions were added

ready: 'ready',
expired: 'expired',
error: 'error',
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These constants are all duplicates of the ones in src/constants.js - we should only define them once.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agree, removed an extra constant

@@ -0,0 +1,16 @@
module.exports = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
module.exports = {
export default {

Try to avoid module.exports if at all possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

@@ -0,0 +1,16 @@
module.exports = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
module.exports = {
export default {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed


const handleKeyDown = ({ key }) => {
if (key === 'Tab') {
popoverElementRef.current.focus();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
popoverElementRef.current.focus();
popoverElementRef.current?.focus();

I got an error here when testing the course outline page pressing TAB and SHIFT-TAB to move focus around via keyboard:

react-dom.development.js:4091 Uncaught TypeError: Cannot read properties of null (reading 'focus')
    at handleKeyDown (WhatsInClipboard.jsx:17:33)
    at HTMLUnknownElement.callCallback (react-dom.development.js:3945:14)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:3994:16)
    at invokeGuardedCallback (react-dom.development.js:4056:31)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:4070:25)
    at executeDispatch (react-dom.development.js:8243:3)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks

<PasteButton className={className} onClick={onClick} text={text} />
<OverlayTrigger
show={showPopover}
trigger={OVERLAY_TRIGGERS}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have <OverlayTrigger trigger={OVERLAY_TRIGGERS} and OVERLAY_TRIGGERS = ['hover', 'focus'] then why do <WhatsInClipboard> and the <Popover> above both have their own onMouseEnter, onMouseLeave, onFocus, onBlur handlers? There seems to be a lot of custom code here just to display a tooltip, and it seems a bit buggy in my testing. Can we rely more on Paragon and use less custom code here? I feel like there should already be a reusable interactive tooltip widget that doesn't require writing your own hover/focus handlers.

For reference, the legacy implementation doesn't use any JavaScript at all - just the :hover and :focus-within styles to make it appear.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it looks with excessive logic and processing, but this was done to keep the tooltip in an open state and the ability to click on it, since the entire body of the tooltip is a link to the unit from which the component was copied

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @ihor-romaniuk. A generic tooltip is not supposed to be used when there is a clickable link inside. The alternative to a tooltip is a ModalPopover, but it was decided not to use that because of the z-indexing and because it requires the user to click when we want the open state to be available on hover.

@@ -0,0 +1,9 @@
module.exports = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
module.exports = {
export default {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

<Dropdown.Item onClick={() => dispatch(copyToClipboard(id))}>
{intl.formatMessage(messages.blockLabelButtonCopyToClipboard)}
</Dropdown.Item>
)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate of the previous comment

@ihor-romaniuk ihor-romaniuk force-pushed the Peter_Kulko/copy-paste-functionality branch from a8b2baa to 7cb96ce Compare April 16, 2024 16:18
@ihor-romaniuk
Copy link
Contributor

ihor-romaniuk commented Apr 16, 2024

the "paste component" button is still not showing up for me. I'm not sure why?

This is due to the lack of necessary changes on the edx-platform side, namely openedx/edx-platform#34521 We have to wait for it to merge before merging this PR. Thanks for notice that.

Also, it seems to be missing some kind of notification that the copy worked (or not)?

If you mean alert messages that appear after pasting a copied unit, then they have been implemented. I have attached the screenshots below.

image (1) image (2) image

@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@bradenmacdonald
Copy link
Contributor

If you mean alert messages that appear after pasting a copied unit, then they have been implemented. I have attached the screenshots below.

No, I mean a notification that the copy worked. (The legacy UI doesn't have this but it does display a "Copying..." notification while the copy is happening.) When I tested this, it was hard to tell that the Copy button did anything because there was no change after clicking it.

@ihor-romaniuk
Copy link
Contributor

ihor-romaniuk commented Apr 17, 2024

No, I mean a notification that the copy worked. (The legacy UI doesn't have this but it does display a "Copying..." notification while the copy is happening.) When I tested this, it was hard to tell that the Copy button did anything because there was no change after clicking it.

We have already implemented a notification when copying a unit or xblock.
You may not see this due to the server's fast response.

image (3) image (4)

@open-craft-grove
Copy link

Sandbox deployment failed 💥
Please check the settings and requirements.
Retry deployment by pushing a new commit or updating the requirements/settings in the pull request's description.
📜 Failure Logs
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@bradenmacdonald
Copy link
Contributor

@ihor-romaniuk

We have already implemented a notification when copying a unit or xblock.
You may not see this due to the server's fast response.

Ah, I see. This is another area where we shouldn't have copied the old design. A "Copying..." status message that is barely even visible doesn't really help much. We always wanted to display "Copied!" toast popup after the copy succeeds, but the legacy UI had no API for displaying a "Copied!" success message. But in the MFE, with Paragon, it should be very easy to display a "Copied!" success <Toast>

Screenshot of a toast example

@jmakowski1123 could you advise?

monteri and others added 4 commits April 23, 2024 09:14
* feat: [AXIMST-344] Copy/paste functionality base

* feat: [AXIMST-344] Copy/paste functionality visible part

* feat: tests

* fix: PR comment review

* refactor: refactoring after review

* refactor: refactoring after rebase

---------

Co-authored-by: monteri <lansevermore>
Co-authored-by: PKulkoRaccoonGang <[email protected]>

feat: [AXIMST-375] Course unit - Added functionality for copying and pasting xblocks and units (#147)

* feat: [AXIMST-350] added functionality for copying and pasting xblocks and units

* refactor: refactoring after review

* refactor: refactoring after second review

fix: [AXIMST-480] fixed paste notification behavior after switching a unit (#160)

fix: [AXIMST-478] fixed copy-paste tooltip (#161)

feat: [AXIMST-338] Course unit - Added canEdit and canPasteComponent variables (#170)

* feat: [AXIMST-338] added canEdit and canPasteComponent variables

* refactor: added condition for Can copy Unit btn

feat: [AXIMST-525] separated the copy unit button (#190)

refactor: [AXIMST-507] Course unit - Changed Paste unit UI (#186)

* refactor: [AXIMST-507] changed Paste unit UI

* refactor: code refactoring

fix: fixed react-intl error (#197)

fix: [AXIMST-516] fixed paste alerts view (#189)

refactor: code refactoring

refactor: code refactoring
* refactor: copy paste functional refactoring

* refactor: refactoring paste-button

* refactor: tests refactoring

* refactor: updated translations

* refactor: refactoring after review

* refactor: renamed status selector name
* fix: [AXIMST-718] second attempt to fix the CSRF token

* fix: [AXIMST-718] third attempt to fix the CSRF token

* fix: [AXIMST-767] fixed new files alert

* refactor: unnecessary code removed
@ihor-romaniuk ihor-romaniuk force-pushed the Peter_Kulko/copy-paste-functionality branch from 2c1864e to e5ba0f7 Compare April 23, 2024 07:22
@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@GlugovGrGlib
Copy link
Member

@bradenmacdonald We will bring up this point on the next project sync up. However, in any case we would really like to add this change in the follow-up PR, so we could merge this one and unblock dependent Unit page PRs.

@bradenmacdonald
Copy link
Contributor

@GlugovGrGlib Oh yeah, that can definitely be addressed in a follow-up PR. Sorry for not being clear.

@bradenmacdonald
Copy link
Contributor

I'm not planning to review this further - I'm not a CC on this repo in any case. I've mentioned the minor concerns that I have, which don't need to block anything. I'm assuming you have someone else to do the full review and merge?

Copy link
Contributor

@arbrandes arbrandes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just missing descriptions in one small messages file. Otherwise, can't find anything to object to that hadn't been already addressed or pushed to a subsequent PR. Nice work!

const messages = defineMessages({
popoverContentText: {
id: 'course-authoring.generic.paste-component.popover.content.text',
defaultMessage: 'From:',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get descriptions in this file, please?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Descriptions were added. Please recheck and LGTM.

Copy link
Contributor

@arbrandes arbrandes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thank you!

@open-craft-grove
Copy link

Sandbox deployment failed 💥
Please check the settings and requirements.
Retry deployment by pushing a new commit or updating the requirements/settings in the pull request's description.
📜 Failure Logs
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@arbrandes arbrandes merged commit 5686dee into openedx:master Apr 24, 2024
4 of 6 checks passed
@openedx-webhooks
Copy link

@PKulkoRaccoonGang 🎉 Your pull request was merged! Please take a moment to answer a two question survey so we can improve your experience in the future.

1 similar comment
@openedx-webhooks
Copy link

@PKulkoRaccoonGang 🎉 Your pull request was merged! Please take a moment to answer a two question survey so we can improve your experience in the future.

@ihor-romaniuk ihor-romaniuk deleted the Peter_Kulko/copy-paste-functionality branch April 25, 2024 06:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
create-sandbox open-craft-grove should create a sandbox environment from this PR open-source-contribution PR author is not from Axim or 2U
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

9 participants