Closed JohnSimonsen closed 4 months ago
@MidhunSureshR @t3chguy I am having trouble requesting a code reviewer. Could any of you help me out?
@robintown @t3chguy Could I have another go at the workflow? I think the lint-errors should be fixed now.
I personally don't have a lot of context for how this project works, and to what extent it already embraces things that feel a little hacky, but that's my impression of this solution.
Am I right that this only allows customization of class components? While many important components in matrix-react-sdk are classes, nowadays we're trying to only write functional components, so I'd much prefer a solution that generalizes to them as well. If it's not possible to customize functional components in a similar manner, then adding this feature could create a counter-productive incentive to rewrite our functional components as classes.
I'll need to defer final judgement to someone like @t3chguy who may have more experience with the module API, but hopefully my thoughts are of some use.
In theory it shouldn't matter if it is a class or a functional component. As long as you are able to put the customComponentOpts
wrapper around it. I haven't personally tried on a functional component, just yet. But i'll be happy to provide an example if necessary. I completely agree that handling customisations differently for different component types would be an anti-pattern.
I would greatly appreciate if you could also have a look at the example provided in the PR-description on how it could be implemented in matrix-react-sdk
as well. If you / others in the Matrix team don't like the way the implementation looks - It would be good to catch it now, so we can adjust the lifecycle ahead of time.
As for some more context on the proposed solution: I did some alternative experimentation on how to achieve the end goal of component override/customisation(Factory implementations etc.). But in my opinion I believe this was the best solution I found, as it has notable upsides:
matrix-react-sdk
WrapperLifecycle
- which has already been acceptedThat being said, I'd be willing to put down the work if there are any suggestions on how to improve it.
I'll need to defer final judgement to someone like @t3chguy who may have more experience with the module API, but hopefully my thoughts are of some use.
I have zero experience with the module API and very little context aside that so please do not block this one me.
@robintown - I extended the tests to include usecase of how you can just as easily wrap and swap a functional component with the same method. I also took your comment into account and got rid off the casting in the constructor of module, and I dropped the "any", that was pointed out in one of the tests (Although was solved by casting the result. As React.Children.toArray()
has multiple possible return values.)
If neither of you has experience with the module-api. Maybe I could suggest adding @germain-gg as a code reviewer? By the looks of it he handled and accepted this PR: https://github.com/matrix-org/matrix-react-sdk-module-api/pull/13 This PR builds on the same ideas.
The mechanics of how this works, can be confusing. And I realize that the PR-description is quite extensive; I'll try to give a short and concise explanation, to ease the burden of mental gymnastics, when familiarizing with the concept. (TL;DR)
1. Initialization of CustomComponentOpts:
const customComponentOpts: CustomComponentOpts = { CustomComponent: React.Fragment };
2. Invocation of ModuleRunner:
ModuleRunner.instance.invoke(CustomComponentLifecycle.UserMenu, customComponentOpts)
This feature could help resolve reported issues, like: https://github.com/matrix-org/matrix-react-sdk-module-api/issues/21
I marked this as needs product/design as I think we would need their alignment/approval to understand if this is a way in which we want extensibility to work.
@langleyd Understandable, thank you for getting back to me. Please let me know if I can be of assistance in any way.
Our team (Verji) have chosen to move ahead with this feature on our fork, as it provides us with a "cleaner", organised structure of custom code vs upstream, and drastically lessens the burden of updating/maintaining our fork.
Hi @JohnSimonsen , This is a very generic solution and its somewhat unclear what the implications would be on our apps overall maintainability if we were to take this approach. Itβs great that it helps you manage your fork but our productβs module apis(including on other platforms) are still experimental and without a more evolved strategy/guidance we can't accept this at this point in time.
@langleyd Thanks for the update, a bit disappointed with the decision. It would've been a huge win to get this into the upstream, for us at least. And probably others, as it would allow the community to be able to create detailed customisations on component level, completely without having to fork the project.
We'll stay tuned if there are better solutions presented at a later time. In the meantime we'll get some mileage on this solution, and if you're interested - we'll be happy to give you an update later with more mature results.
Appreciate you took the time to look into it, @langleyd! π
CustomComponentLifecycle
This lifecycle borrows a lot from the existing WrapperLifecycle.ts(credit: Mikhail Aheichyk, Nordeck IT + Consulting GmbH.) and can be implemented in the same fashion. However we felt it was needed to create a seperate lifecycle as the intended usecase is different. The idea behind the CustomComponentLifecycle is that it should "swap" an existing standard element/matrix-react-sdk component with a custom component in it's place by writing a module. This deviates from the WrapperLifeCycle's usecase to wrap a component and append custom components as children to the wrapper / sibling of the wrapped component.
Changes
CustomComponentLifecycle.ts
CustomComponentLifecycle.test.tsx
types.ts
- AddedCustomComponentLifecycle
toAnyLifecycle
README.md
- Added description of CustomComponentLifecycleWhy is it needed?
Implementation example
As an experiment / Proof of concept i attempted the following: Can I swap the UserMenu component in
matrix-react-sdk
seamlessly, with a custom module with custom elements and behaviours/functionality. Still retaining the original state, children and reactivity?The highlighted elements are (customisations) proof of a "modified" UserMenu. The reactivity from child to expand panel etc, are retained. And since I based my customisation on the existing standard UserMenu all the functionality was transfered (i.e light/dark theme, default menu options etc.)
1. The module custom-usermenu-module
I created a new Module called CustomUserMenuModule with the following dependencies
matrix-react-sdk
andmatrix-js-sdk
allowed me to harness the full type library and stores from those packages. Meaning I could copy the entireUserMenu.ts
file frommatrix-react-sdk
to my modulecustom-usermenu-module
without any errors. I could then make my customisations directly in my module.Implementation of the module:
Note: Notice that the implementation uses the lifecycle proposed in this PR.
2. The Implementation example of the lifecycle in matrix-react-sdk (UserMenu)
πmatrix-react-sdk>src>components>views>SpacePanel.tsx π (Lines with a "π" are relevant in this implementation)
Note: Notice that the implementation uses the lifecycle proposed in this PR.
Signed-off-by: John Tore Simonsen jts@verji.com