Skip to content

Commit 24aa40f

Browse files
authored
Merge pull request #4 from verji/taj/1976-user-search-extension
Taj/1976 user search extension
2 parents 1ec9af8 + d659ed3 commit 24aa40f

14 files changed

+565
-217
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: Main
22
on:
33
push:
4-
branches: [main]
4+
branches: [main, verji-main]
55
pull_request:
66
branches: [main, verji-main]
77
jobs:

.github/workflows/verji-release.yaml

Lines changed: 0 additions & 57 deletions
This file was deleted.

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,14 @@ From the `RuntimeModule` instance, modules can listen for `WrapperLifecycle.Wrap
104104
It would wrap the `MatrixChat` component and let any consumer add a header, a footer.
105105

106106
### Custom components
107+
107108
From the `RuntimeModule` instance, modules can listen for different `CustomComponentLifecycle` events and swap the component
108-
with a custom written component. In principle it works the same way as the `WrapperLifecycle`, but the usecase is different.
109+
with a custom written component. In principle it works the same way as the `WrapperLifecycle`, but the usecase is different.
109110
Instead of wrapping the element, you can intercept it, consume the state of the component including its children, and return
110-
your own customly written component.
111+
your own customly written component.
111112

112113
It is possible to add `matrix-react-sdk`, `matrix-js-sdk` as a dependency into your custom module implementation to gain complete
113-
functionality within your custom components, aswell as the ability to reuse sub-components and styles.
114+
functionality within your custom components, aswell as the ability to reuse sub-components and styles.
114115

115116
## Contributing / developing
116117

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@matrix-org/react-sdk-module-api",
3-
"version": "2.4.0",
3+
"version": "2.4.0-vrj1",
44
"description": "Module API surface for matrix-react-sdk",
55
"main": "lib/index.js",
66
"types": "lib/index.d.ts",
@@ -67,7 +67,8 @@
6767
"typescript": "^4.6.3"
6868
},
6969
"dependencies": {
70-
"@babel/runtime": "^7.17.9"
70+
"@babel/runtime": "^7.17.9",
71+
"matrix-events-sdk": "^2.0.0"
7172
},
7273
"peerDependencies": {
7374
"react": "^17.0.2"

src/extensions/ExtensionsManager.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { DefaultCryptoSetupExtensions, ProvideCryptoSetupExtensions } from "./CryptoSetupExtensions";
2+
import { DefaultExperimentalExtensions, ProvideExperimentalExtensions } from "./ExperimentalExtensions";
3+
import { DefaultUserSearchExtensions, ProvideUserSearchExtensions } from "./UserSearchExtensions";
4+
import { RuntimeModule } from "../RuntimeModule";
5+
6+
/**
7+
* Handles and manages extensions provided by modules.
8+
*/
9+
export class ExtensionsManager {
10+
// Private backing fields for extensions
11+
private cryptoSetupExtension: ProvideCryptoSetupExtensions;
12+
private experimentalExtension: ProvideExperimentalExtensions;
13+
private userSearchExtension: ProvideUserSearchExtensions;
14+
15+
/** `true` if `cryptoSetupExtension` is the default implementation; `false` if it is implemented by a module. */
16+
private hasDefaultCryptoSetupExtension = true;
17+
18+
/** `true` if `userSearchExtension` is the default implementation; `false` if it is implemented by a module. */
19+
private hasDefaultUserSearchExtension = true;
20+
21+
/** `true` if `experimentalExtension` is the default implementation; `false` if it is implemented by a module. */
22+
private hasDefaultExperimentalExtension = true;
23+
24+
/**
25+
* Create a new instance.
26+
*/
27+
public constructor() {
28+
// Set up defaults
29+
this.cryptoSetupExtension = new DefaultCryptoSetupExtensions();
30+
this.experimentalExtension = new DefaultExperimentalExtensions();
31+
this.userSearchExtension = new DefaultUserSearchExtensions();
32+
}
33+
34+
/**
35+
* Provides a crypto setup extension.
36+
*
37+
* @returns The registered extension. If no module provides this extension, a default implementation is returned.
38+
*/
39+
public get cryptoSetup(): ProvideCryptoSetupExtensions {
40+
return this.cryptoSetupExtension;
41+
}
42+
43+
/**
44+
* Provides a user search extension.
45+
*
46+
* @returns The registered extension. If no module provides this extension, a default implementation is returned.
47+
*/
48+
public get userSearch(): ProvideUserSearchExtensions {
49+
return this.userSearchExtension;
50+
}
51+
52+
/**
53+
* Provides an experimental extension.
54+
*
55+
* @remarks
56+
* This method extension is provided to simplify experimentation and development, and is not intended for production code.
57+
*
58+
* @returns The registered extension. If no module provides this extension, a default implementation is returned.
59+
*/
60+
public get experimental(): ProvideExperimentalExtensions {
61+
return this.experimentalExtension;
62+
}
63+
64+
/**
65+
* Add any extensions provided by the module.
66+
*
67+
* @param module - The appModule to check for extensions.
68+
*
69+
* @throws if an extension is provided by more than one module.
70+
*/
71+
public addExtensions(module: RuntimeModule): void {
72+
/* Add the cryptoSetup extension if any */
73+
if (module.extensions?.cryptoSetup) {
74+
if (this.hasDefaultCryptoSetupExtension) {
75+
this.cryptoSetupExtension = module.extensions?.cryptoSetup;
76+
this.hasDefaultCryptoSetupExtension = false;
77+
} else {
78+
throw new Error(
79+
`adding cryptoSetup extension implementation from module ${module.moduleName} but an implementation was already provided.`,
80+
);
81+
}
82+
}
83+
84+
/* Add the userSearch extension if any */
85+
if (module.extensions?.userSearch) {
86+
if (this.hasDefaultUserSearchExtension) {
87+
this.userSearchExtension = module.extensions?.userSearch;
88+
this.hasDefaultUserSearchExtension = false;
89+
} else {
90+
throw new Error(
91+
`adding userSearch extension implementation from module ${module.moduleName} but an implementation was already provided.`,
92+
);
93+
}
94+
}
95+
96+
/* Add the experimental extension if any */
97+
if (module.extensions?.experimental) {
98+
if (this.hasDefaultExperimentalExtension) {
99+
this.experimentalExtension = module.extensions?.experimental;
100+
this.hasDefaultExperimentalExtension = false;
101+
} else {
102+
throw new Error(
103+
`adding experimental extension implementation from module ${module.moduleName} but an implementation was already provided.`,
104+
);
105+
}
106+
}
107+
}
108+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
Copyright 2023 Verji Tech AS
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
import { Optional } from "matrix-events-sdk";
17+
18+
export interface RoomViewStoreProjection {
19+
// The room ID of the room currently being viewed
20+
getRoomId(): Optional<string>;
21+
}
22+
23+
export interface RoomProjection {
24+
// The room ID of the room currently being viewed
25+
roomId: string;
26+
}
27+
28+
export interface SpaceStoreClassProjection {
29+
get activeSpaceRoom(): RoomProjection | null;
30+
}
31+
32+
interface RequestInit {
33+
/**
34+
* Specifies the priority of the fetch request relative to other requests of the same type.
35+
* Must be one of the following strings:
36+
* high: A high priority fetch request relative to other requests of the same type.
37+
* low: A low priority fetch request relative to other requests of the same type.
38+
* auto: Automatically determine the priority of the fetch request relative to other requests of the same type (default).
39+
*
40+
* @see https://html.spec.whatwg.org/multipage/urls-and-fetching.html#fetch-priority-attribute
41+
* @see https://github.com/microsoft/TypeScript/issues/54472
42+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#browser_compatibility
43+
* Not yet supported in Safari or Firefox
44+
*/
45+
priority?: "high" | "low" | "auto";
46+
}
47+
48+
interface RequestOptsProjection extends Pick<RequestInit, "priority"> {
49+
/**
50+
* The alternative base url to use.
51+
* If not specified, uses this.opts.baseUrl
52+
*/
53+
baseUrl?: string;
54+
/**
55+
* The full prefix to use e.g.
56+
* "/_matrix/client/v2_alpha". If not specified, uses this.opts.prefix.
57+
*/
58+
prefix?: string;
59+
/**
60+
* map of additional request headers
61+
*/
62+
headers?: Record<string, string>;
63+
abortSignal?: AbortSignal;
64+
/**
65+
* The maximum amount of time to wait before
66+
* timing out the request. If not specified, there is no timeout.
67+
*/
68+
localTimeoutMs?: number;
69+
keepAlive?: boolean; // defaults to false
70+
json?: boolean; // defaults to true
71+
72+
// Set to true to prevent the request function from emitting a Session.logged_out event.
73+
// This is intended for use on endpoints where M_UNKNOWN_TOKEN is a valid/notable error response,
74+
// such as with token refreshes.
75+
inhibitLogoutEmit?: boolean;
76+
}
77+
78+
/*
79+
* A interface providing a slice/projection of the SdkContextClass in matrix-react-sdk
80+
*/
81+
export interface SdkContextClassProjection {
82+
get roomViewStore(): RoomViewStoreProjection;
83+
get spaceStore(): SpaceStoreClassProjection;
84+
}
85+
86+
/**
87+
* Public api surface used to consume the extension in client code
88+
*/
89+
export interface ProvideUserSearchExtensions {
90+
getSearchContext(client: any, sdkContext: SdkContextClassProjection): Promise<SearchContext>;
91+
}
92+
93+
/**
94+
* Abstract base class which concrete extension implementations will extend/derive from
95+
*/
96+
export abstract class UserSearchExtensionsBase implements ProvideUserSearchExtensions {
97+
public abstract getSearchContext(client: any, sdkContextClass: SdkContextClassProjection): Promise<SearchContext>;
98+
}
99+
100+
/**
101+
* Search context used to augment call to /user-directory/search
102+
*
103+
*/
104+
export interface SearchContext {
105+
extraBodyArgs: { [key: string]: string } | null;
106+
extraRequestOptions: RequestOptsProjection;
107+
}
108+
109+
/**
110+
*
111+
* The default/empty usersearch-extension
112+
* Can (and will) be used if none of the modules has an implementaion of ProvideUserSearchExtensions
113+
*
114+
* */
115+
export class DefaultUserSearchExtensions extends UserSearchExtensionsBase {
116+
public async getSearchContext(client: any, sdkContext: SdkContextClassProjection): Promise<SearchContext> {
117+
console.log("Default resolveSearchContext()");
118+
return {
119+
extraBodyArgs: {},
120+
extraRequestOptions: {},
121+
};
122+
}
123+
}

src/lifecycles/types.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
/*
2-
Copyright 2022 The Matrix.org Foundation C.I.C.
3-
4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
7-
8-
http://www.apache.org/licenses/LICENSE-2.0
9-
10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
15-
*/
16-
17-
import { RoomViewLifecycle } from "./RoomViewLifecycle";
18-
import { WidgetLifecycle } from "./WidgetLifecycle";
19-
import { WrapperLifecycle } from "./WrapperLifecycle";
20-
import { CustomComponentLifecycle } from "./CustomComponentLifecycle";
21-
22-
export type AnyLifecycle = RoomViewLifecycle | WidgetLifecycle | WrapperLifecycle | CustomComponentLifecycle;
1+
/*
2+
Copyright 2022 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { RoomViewLifecycle } from "./RoomViewLifecycle";
18+
import { WidgetLifecycle } from "./WidgetLifecycle";
19+
import { WrapperLifecycle } from "./WrapperLifecycle";
20+
import { CustomComponentLifecycle } from "./CustomComponentLifecycle";
21+
22+
export type AnyLifecycle = RoomViewLifecycle | WidgetLifecycle | WrapperLifecycle | CustomComponentLifecycle;

src/types/extensions.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ See the License for the specific language governing permissions and
1313
limitations under the License.
1414
*/
1515

16-
import { ProvideCryptoSetupExtensions } from "../lifecycles/CryptoSetupExtensions";
17-
import { ProvideExperimentalExtensions } from "../lifecycles/ExperimentalExtensions";
16+
import { ProvideCryptoSetupExtensions } from "../extensions/CryptoSetupExtensions";
17+
import { ProvideExperimentalExtensions } from "../extensions/ExperimentalExtensions";
18+
import { ProvideUserSearchExtensions } from "../extensions/UserSearchExtensions";
1819

1920
export type AllExtensions = {
2021
cryptoSetup?: ProvideCryptoSetupExtensions;
2122
experimental?: ProvideExperimentalExtensions;
23+
userSearch?: ProvideUserSearchExtensions;
2224
};

0 commit comments

Comments
 (0)