feat: support self hosted grist (#5655)
Co-authored-by: Tom Moor <tom.moor@gmail.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import SettingRow from "./components/SettingRow";
|
||||
|
||||
type FormData = {
|
||||
drawIoUrl: string;
|
||||
gristUrl: string;
|
||||
};
|
||||
|
||||
function SelfHosted() {
|
||||
@@ -23,11 +24,16 @@ function SelfHosted() {
|
||||
const { t } = useTranslation();
|
||||
const { showToast } = useToasts();
|
||||
|
||||
const integration = find(integrations.orderedData, {
|
||||
const integrationDiagrams = find(integrations.orderedData, {
|
||||
type: IntegrationType.Embed,
|
||||
service: IntegrationService.Diagrams,
|
||||
}) as Integration<IntegrationType.Embed> | undefined;
|
||||
|
||||
const integrationGrist = find(integrations.orderedData, {
|
||||
type: IntegrationType.Embed,
|
||||
service: IntegrationService.Grist,
|
||||
}) as Integration<IntegrationType.Embed> | undefined;
|
||||
|
||||
const {
|
||||
register,
|
||||
reset,
|
||||
@@ -36,7 +42,8 @@ function SelfHosted() {
|
||||
} = useForm<FormData>({
|
||||
mode: "all",
|
||||
defaultValues: {
|
||||
drawIoUrl: integration?.settings.url,
|
||||
drawIoUrl: integrationDiagrams?.settings.url,
|
||||
gristUrl: integrationGrist?.settings.url,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -47,15 +54,18 @@ function SelfHosted() {
|
||||
}, [integrations]);
|
||||
|
||||
React.useEffect(() => {
|
||||
reset({ drawIoUrl: integration?.settings.url });
|
||||
}, [integration, reset]);
|
||||
reset({
|
||||
drawIoUrl: integrationDiagrams?.settings.url,
|
||||
gristUrl: integrationGrist?.settings.url,
|
||||
});
|
||||
}, [integrationDiagrams, integrationGrist, reset]);
|
||||
|
||||
const handleSubmit = React.useCallback(
|
||||
async (data: FormData) => {
|
||||
try {
|
||||
if (data.drawIoUrl) {
|
||||
await integrations.save({
|
||||
id: integration?.id,
|
||||
id: integrationDiagrams?.id,
|
||||
type: IntegrationType.Embed,
|
||||
service: IntegrationService.Diagrams,
|
||||
settings: {
|
||||
@@ -63,7 +73,20 @@ function SelfHosted() {
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await integration?.delete();
|
||||
await integrationDiagrams?.delete();
|
||||
}
|
||||
|
||||
if (data.gristUrl) {
|
||||
await integrations.save({
|
||||
id: integrationGrist?.id,
|
||||
type: IntegrationType.Embed,
|
||||
service: IntegrationService.Grist,
|
||||
settings: {
|
||||
url: data.gristUrl,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await integrationGrist?.delete();
|
||||
}
|
||||
|
||||
showToast(t("Settings saved"), {
|
||||
@@ -75,7 +98,7 @@ function SelfHosted() {
|
||||
});
|
||||
}
|
||||
},
|
||||
[integrations, integration, t, showToast]
|
||||
[integrations, integrationDiagrams, integrationGrist, t, showToast]
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -98,6 +121,19 @@ function SelfHosted() {
|
||||
/>
|
||||
</SettingRow>
|
||||
|
||||
<SettingRow
|
||||
label={t("Grist deployment")}
|
||||
name="gristUrl"
|
||||
description={t("Add your self-hosted grist installation URL here.")}
|
||||
border={false}
|
||||
>
|
||||
<Input
|
||||
placeholder="https://docs.getgrist.com/"
|
||||
pattern="https?://.*"
|
||||
{...register("gristUrl")}
|
||||
/>
|
||||
</SettingRow>
|
||||
|
||||
<Button type="submit" disabled={formState.isSubmitting}>
|
||||
{formState.isSubmitting ? `${t("Saving")}…` : t("Save")}
|
||||
</Button>
|
||||
|
||||
@@ -18,6 +18,7 @@ import Fix from "./decorators/Fix";
|
||||
|
||||
export enum UserCreatableIntegrationService {
|
||||
Diagrams = "diagrams",
|
||||
Grist = "grist",
|
||||
GoogleAnalytics = "google-analytics",
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ describe("#integrations.update", () => {
|
||||
expect(res.status).toEqual(403);
|
||||
});
|
||||
|
||||
it("should succeed with status 200 ok when settings are updated", async () => {
|
||||
it("should succeed with status 200 ok when diagram integration settings are updated", async () => {
|
||||
const admin = await buildAdmin();
|
||||
|
||||
const integration = await buildIntegration({
|
||||
@@ -72,6 +72,30 @@ describe("#integrations.update", () => {
|
||||
expect(body.data.id).toEqual(integration.id);
|
||||
expect(body.data.settings.url).toEqual("https://foo.bar");
|
||||
});
|
||||
|
||||
it("should succeed with status 200 ok when grist integration settings are updated", async () => {
|
||||
const admin = await buildAdmin();
|
||||
|
||||
const integration = await buildIntegration({
|
||||
userId: admin.id,
|
||||
teamId: admin.teamId,
|
||||
service: IntegrationService.Grist,
|
||||
type: IntegrationType.Embed,
|
||||
settings: { url: "https://example.com" },
|
||||
});
|
||||
|
||||
const res = await server.post("/api/integrations.update", {
|
||||
body: {
|
||||
token: admin.getJwtToken(),
|
||||
id: integration.id,
|
||||
settings: { url: "https://grist.example.com" },
|
||||
},
|
||||
});
|
||||
|
||||
const body = await res.json();
|
||||
expect(body.data.id).toEqual(integration.id);
|
||||
expect(body.data.settings.url).toEqual("https://grist.example.com");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#integrations.create", () => {
|
||||
@@ -111,6 +135,25 @@ describe("#integrations.create", () => {
|
||||
expect(body.data.settings).not.toBeFalsy();
|
||||
expect(body.data.settings.measurementId).toEqual("123");
|
||||
});
|
||||
|
||||
it("should succeed with status 200 ok for an grist integration", async () => {
|
||||
const admin = await buildAdmin();
|
||||
|
||||
const res = await server.post("/api/integrations.create", {
|
||||
body: {
|
||||
token: admin.getJwtToken(),
|
||||
type: IntegrationType.Embed,
|
||||
service: UserCreatableIntegrationService.Grist,
|
||||
settings: { url: "https://grist.example.com" },
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
expect(res.status).toEqual(200);
|
||||
expect(body.data.type).toEqual(IntegrationType.Embed);
|
||||
expect(body.data.service).toEqual(UserCreatableIntegrationService.Grist);
|
||||
expect(body.data.settings).not.toBeFalsy();
|
||||
expect(body.data.settings.url).toEqual("https://grist.example.com");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#integrations.delete", () => {
|
||||
|
||||
@@ -24,4 +24,6 @@ function Grist(props: Props) {
|
||||
|
||||
Grist.ENABLED = [new RegExp("^https?://([a-z.-]+\\.)?getgrist\\.com/(.+)$")];
|
||||
|
||||
Grist.URL_PATH_REGEX = /(.+)/;
|
||||
|
||||
export default Grist;
|
||||
|
||||
@@ -851,6 +851,8 @@
|
||||
"Allow members to create new collections within the knowledge base": "Allow members to create new collections within the knowledge base",
|
||||
"Draw.io deployment": "Draw.io deployment",
|
||||
"Add your self-hosted draw.io installation url here to enable automatic embedding of diagrams within documents.": "Add your self-hosted draw.io installation url here to enable automatic embedding of diagrams within documents.",
|
||||
"Grist deployment": "Grist deployment",
|
||||
"Add your self-hosted grist installation URL here.": "Add your self-hosted grist installation URL here.",
|
||||
"Sharing is currently disabled.": "Sharing is currently disabled.",
|
||||
"You can globally enable and disable public document sharing in the <em>security settings</em>.": "You can globally enable and disable public document sharing in the <em>security settings</em>.",
|
||||
"Documents that have been shared are listed below. Anyone that has the public link can access a read-only version of the document until the link has been revoked.": "Documents that have been shared are listed below. Anyone that has the public link can access a read-only version of the document until the link has been revoked.",
|
||||
|
||||
@@ -79,6 +79,7 @@ export enum IntegrationType {
|
||||
|
||||
export enum IntegrationService {
|
||||
Diagrams = "diagrams",
|
||||
Grist = "grist",
|
||||
Slack = "slack",
|
||||
GoogleAnalytics = "google-analytics",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user