Skip to content

Commit

Permalink
ui: Add interface to manage integrations
Browse files Browse the repository at this point in the history
  • Loading branch information
nemunaire committed Jun 2, 2023
1 parent 5784582 commit 693476b
Show file tree
Hide file tree
Showing 8 changed files with 624 additions and 0 deletions.
139 changes: 139 additions & 0 deletions internal/ui/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
browserIDContextKey = "browserID"
isSync15Key = "sync15"
docIDParam = "docid"
intIDParam = "intid"
uiLogger = "[ui] "
ui10 = " [10] "
useridParam = "userid"
Expand Down Expand Up @@ -508,3 +509,141 @@ func (app *ReactAppWrapper) createUser(c *gin.Context) {
}
c.Status(http.StatusCreated)
}

func (app *ReactAppWrapper) listIntegrations(c *gin.Context) {
uid := c.GetString(userIDContextKey)

user, err := app.userStorer.GetUser(uid)
if err != nil {
log.Error(err)
c.AbortWithStatus(http.StatusUnauthorized)
return
}

c.JSON(http.StatusOK, user.Integrations)
}

func (app *ReactAppWrapper) createIntegration(c *gin.Context) {
int := model.IntegrationConfig{}
if err := c.ShouldBindJSON(&int); err != nil {
log.Error(err)
badReq(c, err.Error())
return
}

uid := c.GetString(userIDContextKey)

user, err := app.userStorer.GetUser(uid)
if err != nil {
log.Error(err)
c.AbortWithStatus(http.StatusUnauthorized)
return
}

int.ID = uuid.NewString()
user.Integrations = append(user.Integrations, int)

err = app.userStorer.UpdateUser(user)

if err != nil {
log.Error("error updating user", err)
c.AbortWithStatus(http.StatusInternalServerError)
return
}

c.JSON(http.StatusOK, int)
}

func (app *ReactAppWrapper) getIntegration(c *gin.Context) {
uid := c.GetString(userIDContextKey)

intid := common.ParamS(intIDParam, c)

user, err := app.userStorer.GetUser(uid)
if err != nil {
log.Error(err)
c.AbortWithStatus(http.StatusUnauthorized)
return
}

for _, integration := range user.Integrations {
if integration.ID == intid {
c.JSON(http.StatusOK, integration)
return
}
}

c.AbortWithStatus(http.StatusNotFound)
}

func (app *ReactAppWrapper) updateIntegration(c *gin.Context) {
int := model.IntegrationConfig{}
if err := c.ShouldBindJSON(&int); err != nil {
log.Error(err)
badReq(c, err.Error())
return
}

uid := c.GetString(userIDContextKey)

intid := common.ParamS(intIDParam, c)

user, err := app.userStorer.GetUser(uid)
if err != nil {
log.Error(err)
c.AbortWithStatus(http.StatusUnauthorized)
return
}

for idx, integration := range user.Integrations {
if integration.ID == intid {
int.ID = integration.ID
user.Integrations[idx] = int

err = app.userStorer.UpdateUser(user)

if err != nil {
log.Error("error updating user", err)
c.AbortWithStatus(http.StatusInternalServerError)
return
}

c.JSON(http.StatusOK, int)
return
}
}

c.AbortWithStatus(http.StatusNotFound)
}

func (app *ReactAppWrapper) deleteIntegration(c *gin.Context) {
uid := c.GetString(userIDContextKey)

intid := common.ParamS(intIDParam, c)

user, err := app.userStorer.GetUser(uid)
if err != nil {
log.Error(err)
c.AbortWithStatus(http.StatusUnauthorized)
return
}

for idx, integration := range user.Integrations {
if integration.ID == intid {
user.Integrations = append(user.Integrations[:idx], user.Integrations[idx+1:]...)

err = app.userStorer.UpdateUser(user)

if err != nil {
log.Error("error updating user", err)
c.AbortWithStatus(http.StatusInternalServerError)
return
}

c.Status(http.StatusAccepted)
return
}
}

c.AbortWithStatus(http.StatusNotFound)
}
7 changes: 7 additions & 0 deletions internal/ui/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ func (app *ReactAppWrapper) RegisterRoutes(router *gin.Engine) {
auth.POST("folders", app.createFolder)
auth.GET("documents/:docid/metadata", app.getDocumentMetadata)

// integrations
auth.GET("integrations", app.listIntegrations)
auth.POST("integrations", app.createIntegration)
auth.GET("integrations/:intid", app.getIntegration)
auth.PUT("integrations/:intid", app.updateIntegration)
auth.DELETE("integrations/:intid", app.deleteIntegration)

//admin
admin := auth.Group("")
admin.Use(app.adminMiddleware())
Expand Down
2 changes: 2 additions & 0 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { AuthProvider } from "./common/useAuthContext";
import { PrivateRoute } from "./components/PrivateRoute";
import CodeGenerator from "./components/CodeGenerator";
import Integrations from "./components/Integrations";
import ResetPassword from "./components/ResetPassword";
import Role from "./common/Role";
import apiService from "./services/api.service";
Expand All @@ -33,6 +34,7 @@ export default function App() {
<PrivateRoute exact path="/" component={Home} />
<PrivateRoute path="/documents" component={Documents} />
<PrivateRoute path="/generatecode" component={CodeGenerator} />
<PrivateRoute path="/integrations" component={Integrations} />
<PrivateRoute path="/resetPassword" component={ResetPassword} />
<PrivateRoute path="/users/:userid" component={UserProfile} />
<PrivateRoute path="/users" roles={[Role.Admin]} component={UserList} />
Expand Down
172 changes: 172 additions & 0 deletions ui/src/components/IntegrationModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import React, { useState } from "react";
import Form from "react-bootstrap/Form";
import { Button, Card } from "react-bootstrap";
import apiService from "../services/api.service";

import { Alert } from "react-bootstrap";

export default function IntegrationModal(params) {
const { integration, onSave, headerText, onClose } = params;

const [formErrors, setFormErrors] = useState({});
const [integrationForm, setIntegrationForm] = useState({
name: integration?.Name,
provider: integration?.Provider,
email: integration?.email,
username: integration?.Username,
password: integration?.Password,
address: integration?.Address,
insecure: integration?.Insecure,
accesstoken: integration?.Accesstoken,
path: integration?.Path,
});

function handleChange({ target }) {
setIntegrationForm({ ...integrationForm, [target.name]: target.value });
}

function formIsValid() {
const _errors = {};

if (!integrationForm.name) _errors.error = "name is required";

setFormErrors(_errors);

return Object.keys(_errors).length === 0;
}

async function handleSubmit(event) {
event.preventDefault();

if (!formIsValid()) return;

try {
await apiService.updateintegration({
id: integration.ID,
name: integrationForm.name,
provider: integrationForm.provider,
username: integrationForm.username,
password: integrationForm.password,
address: integrationForm.address,
insecure: integrationForm.insecure,
accesstoken: integrationForm.accesstoken,
path: integrationForm.path,
});
onSave();
} catch (e) {
setFormErrors({ error: e.toString() });
}
}

if (!integration) return null;
return (
<Form onSubmit={handleSubmit}>
<Card bg="dark" text="white">
<Card.Header>
<span>{headerText}</span>
</Card.Header>
<Card.Body>
<div>
<Alert variant="danger" hidden={!formErrors.error}>
<Alert.Heading>An Error Occurred</Alert.Heading>
{formErrors.error}
</Alert>

<Form.Label>IntegrationID</Form.Label>
<Form.Control
className="font-weight-bold"
placeholder=""
value={integration.ID}
disabled
/>

<Form.Label>Provider</Form.Label>
<Form.Control
as="select"
name="provider"
value={integrationForm.provider}
onChange={handleChange}
>
<option value="localfs">Directory in file system</option>
<option value="webdav">WebDAV</option>
<option value="dropbox">Dropbox</option>
</Form.Control>

<Form.Label>Name</Form.Label>
<Form.Control
placeholder="Integration name"
value={integrationForm.name}
name="name"
onChange={handleChange}
/>

{integrationForm.provider === "webdav" && (
<>
<Form.Label>Address</Form.Label>
<Form.Control
placeholder="Server URL"
value={integrationForm.address}
name="address"
onChange={handleChange}
/>
</>
)}
{integrationForm.provider === "webdav" && (
<>
<Form.Label>Username</Form.Label>
<Form.Control
placeholder="Username"
value={integrationForm.username}
name="username"
onChange={handleChange}
/>
</>
)}
{integrationForm.provider === "webdav" && (
<>
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
placeholder="Password"
value={integrationForm.password}
name="password"
onChange={handleChange}
/>
</>
)}

{integrationForm.provider === "localfs" && (
<>
<Form.Label>Path</Form.Label>
<Form.Control
placeholder="Path"
value={integrationForm.path}
name="path"
onChange={handleChange}
/>
</>
)}

{integrationForm.provider === "dropbox" && (
<>
<Form.Label>Access Token</Form.Label>
<Form.Control
placeholder="Access Token"
value={integrationForm.accesstoken}
name="accesstoken"
onChange={handleChange}
/>
</>
)}
</div>
</Card.Body>
<Card.Footer style={{ display: "flex", flex: "10", gap: "15px" }}>
<Button variant="primary" type="submit">
Save
</Button>
<Button variant="secondary" onClick={onClose}>Cancel</Button>
</Card.Footer>
</Card>
</Form>
);
}
Loading

0 comments on commit 693476b

Please sign in to comment.