Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jahia-test-module/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@jahia/javascript-modules-library": "workspace:^",
"@jahia/vite-plugin": "workspace:^",
"@types/react": "^19.1.12",
"graphql": "^16.11.0",
"i18next": "^25.6.0",
"react-i18next": "^16.1.0",
"typescript": "^5.9.2",
Expand Down
24 changes: 19 additions & 5 deletions jahia-test-module/src/react/server/views/testGQL/TestGQL.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { jahiaComponent, useGQLQuery } from "@jahia/javascript-modules-library";
import { parse } from "graphql";

jahiaComponent(
{
Expand All @@ -13,16 +14,18 @@ jahiaComponent(
"query ($path:String!) { jcr { nodeByPath(path:$path) { name, properties { name, value } } } }",
variables: { path: currentNode.getPath() },
});
const resultFromDocument = useGQLQuery({
query: parse(
"query ($path:String!) { jcr { nodeByPath(path:$path) { name, properties { name, value } } } }",
),
variables: { path: currentNode.getPath() },
});
return (
<>
<div data-testid="react-view">React view working</div>
<hr />

<h3>GraphQL</h3>
<div
data-testid="gql-info-test"
style={{ padding: "10px", margin: "10px", border: "1px solid" }}
>
<div style={{ padding: "10px", margin: "10px", border: "1px solid" }}>
<ul>
{result.data.jcr.nodeByPath.properties.map(
(property: { name: string; value: string }) => (
Expand All @@ -34,6 +37,17 @@ jahiaComponent(
</ul>
</div>
<hr />
<div style={{ padding: "10px", margin: "10px", border: "1px solid" }}>
<ul>
{resultFromDocument.data.jcr.nodeByPath.properties.map(
(property: { name: string; value: string }) => (
<li key={property.name} data-testid={property.name + "-from-document"}>
{property.name}={property.value}
</li>
),
)}
</ul>
</div>
</>
);
},
Expand Down
18 changes: 15 additions & 3 deletions javascript-modules-engine/tests/cypress/e2e/ui/gqlTest.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { addNode } from "@jahia/cypress";
import { addSimplePage } from "../../utils/helpers";
import { GENERIC_SITE_KEY } from '../../support/constants';
import { GENERIC_SITE_KEY } from "../../support/constants";

describe("Test GQL", () => {
before("Create test page and contents", () => {
Expand All @@ -27,8 +27,12 @@ describe("Test GQL", () => {
});
});

beforeEach("Login", () => { cy.login(); });
afterEach('Logout', () => { cy.logout(); });
beforeEach("Login", () => {
cy.login();
});
afterEach("Logout", () => {
cy.logout();
});

it("Check GQL execution in current view", function () {
cy.visit(`/cms/render/default/en/sites/${GENERIC_SITE_KEY}/home/testJGQL.html`);
Expand All @@ -37,5 +41,13 @@ describe("Test GQL", () => {
cy.get('li[data-testid="prop1"]').should("contain", "prop1 value");
cy.get('li[data-testid="prop2"]').should("contain", "prop2 value !@#$%ˆ//{}È");
cy.get('li[data-testid="propRichText"]').should("contain", "Hello this is a sample rich text");
cy.get('li[data-testid="j:nodename-from-document"]').should("contain", "test");
cy.get('li[data-testid="jcr:title-from-document"]').should("contain", "test component");
cy.get('li[data-testid="prop1-from-document"]').should("contain", "prop1 value");
cy.get('li[data-testid="prop2-from-document"]').should("contain", "prop2 value !@#$%ˆ//{}È");
cy.get('li[data-testid="propRichText-from-document"]').should(
"contain",
"Hello this is a sample rich text",
);
});
});
7 changes: 7 additions & 0 deletions javascript-modules-library/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ const { data, errors } = useGQLQuery({
});
```

`useGQLQuery` supports typed document nodes from [@graphql-typed-document-node/core](https://github.com/dotansimha/graphql-typed-document-node), but the JavaScript Modules Library is not prescriptive regarding GraphQL type generation and client-side usage. Here are some tools that can be used to generate types for your GraphQL queries:

- [gql.tada](https://gql-tada.0no.co/)
- [GraphQL Codegen](https://the-guild.dev/graphql/codegen/docs/getting-started)

On the client, you can use your favorite GraphQL client, such as [Apollo Client](https://www.apollographql.com/docs/react/) or [urql](https://nearform.com/open-source/urql/docs/).

### `useJCRQuery`

This hook is used to execute a JCR query on the current Jahia instance.
Expand Down
10 changes: 10 additions & 0 deletions javascript-modules-library/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"dotenv": "^17.2.2"
},
"devDependencies": {
"@0no-co/graphql.web": "^1.2.0",
"@graphql-typed-document-node/core": "^3.2.0",
"@types/react": "^19.1.12",
"devalue": "^5.3.2",
"graphql": "^16.11.0",
Expand All @@ -37,12 +39,20 @@
"typescript": "^5.9.2"
},
"peerDependencies": {
"@graphql-typed-document-node/core": "^3.2.0",
"graphql": "*",
"i18next": "^25.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-i18next": "^15.4.0 || ^16.0.0"
},
"peerDependenciesMeta": {
"@graphql-typed-document-node/core": {
"optional": true
},
"graphql": {
"optional": true
},
"i18next": {
"optional": true
},
Expand Down
33 changes: 26 additions & 7 deletions javascript-modules-library/src/hooks/useGQLQuery.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { print } from "@0no-co/graphql.web";
import type { TypedDocumentNode } from "@graphql-typed-document-node/core";
import type { GraphQLFormattedError } from "graphql";
import { useServerContext } from "./useServerContext.js";

Expand All @@ -6,27 +9,43 @@ import { useServerContext } from "./useServerContext.js";
*
* @returns The result of the query
*/
export const useGQLQuery = ({
export function useGQLQuery<TData = any, TVariables = Record<string, any>>({
query,
variables,
operationName,
}: {
query: TypedDocumentNode<TData, TVariables>;
variables?: TVariables;
operationName?: string;
}): { data: TData; errors?: GraphQLFormattedError[] };
export function useGQLQuery({
query,
variables,
operationName,
}: {
/** The GraphQL query to execute */
query: string;
variables?: Record<string, unknown>;
operationName?: string;
}): { data: any; errors?: GraphQLFormattedError[] };
export function useGQLQuery({
query,
variables,
operationName,
}: {
/** The GraphQL query to execute */
query: string | TypedDocumentNode;
/** The variables to use for the query */
variables?: Record<string, unknown>;
/** The operation name to use for the query */
operationName?: string;
// Data will be any not to cause a breaking change in the type declaration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}): { data: any; errors?: GraphQLFormattedError[] } => {
}) {
const { renderContext } = useServerContext();
return JSON.parse(
server.gql.executeQuerySync({
query,
query: typeof query === "string" ? query : print(query),
variables,
operationName,
renderContext,
}),
);
};
}
30 changes: 30 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ __metadata:
version: 8
cacheKey: 10c0

"@0no-co/graphql.web@npm:^1.2.0":
version: 1.2.0
resolution: "@0no-co/graphql.web@npm:1.2.0"
peerDependencies:
graphql: ^14.0.0 || ^15.0.0 || ^16.0.0
peerDependenciesMeta:
graphql:
optional: true
checksum: 10c0/4eed600962bfab42afb49cddcfb31a47b00502f59707609cf160559920ce0f5cf8874791e4cafc465ede30ae291992f3f892bc757b2a989e80e50e358f71c518
languageName: node
linkType: hard

"@adobe/css-tools@npm:~4.3.1":
version: 4.3.3
resolution: "@adobe/css-tools@npm:4.3.3"
Expand Down Expand Up @@ -463,6 +475,15 @@ __metadata:
languageName: node
linkType: hard

"@graphql-typed-document-node/core@npm:^3.2.0":
version: 3.2.0
resolution: "@graphql-typed-document-node/core@npm:3.2.0"
peerDependencies:
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
checksum: 10c0/94e9d75c1f178bbae8d874f5a9361708a3350c8def7eaeb6920f2c820e82403b7d4f55b3735856d68e145e86c85cbfe2adc444fdc25519cd51f108697e99346c
languageName: node
linkType: hard

"@humanfs/core@npm:^0.19.1":
version: 0.19.1
resolution: "@humanfs/core@npm:0.19.1"
Expand Down Expand Up @@ -530,6 +551,8 @@ __metadata:
version: 0.0.0-use.local
resolution: "@jahia/javascript-modules-library@workspace:javascript-modules-library"
dependencies:
"@0no-co/graphql.web": "npm:^1.2.0"
"@graphql-typed-document-node/core": "npm:^3.2.0"
"@types/react": "npm:^19.1.12"
devalue: "npm:^5.3.2"
dotenv: "npm:^17.2.2"
Expand All @@ -539,11 +562,17 @@ __metadata:
react-i18next: "npm:^16.1.0"
typescript: "npm:^5.9.2"
peerDependencies:
"@graphql-typed-document-node/core": ^3.2.0
graphql: "*"
i18next: ^25.0.0
react: ^19.0.0
react-dom: ^19.0.0
react-i18next: ^15.4.0 || ^16.0.0
peerDependenciesMeta:
"@graphql-typed-document-node/core":
optional: true
graphql:
optional: true
i18next:
optional: true
react:
Expand Down Expand Up @@ -2983,6 +3012,7 @@ __metadata:
"@jahia/javascript-modules-library": "workspace:^"
"@jahia/vite-plugin": "workspace:^"
"@types/react": "npm:^19.1.12"
graphql: "npm:^16.11.0"
i18next: "npm:^25.6.0"
react-i18next: "npm:^16.1.0"
typescript: "npm:^5.9.2"
Expand Down
Loading