Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add /sketch service #11

Merged
merged 128 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
128 commits
Select commit Hold shift + click to select a range
fd62f32
add auth provider for sketch service
Oct 27, 2022
d71cfe5
Merge branch 'ServiceNav' into sketch
Oct 27, 2022
9bf36a9
add sketch swrvice and adapt to multi column layout
Nov 1, 2022
8035f8f
Merge branch 'main' into sketch
Nov 1, 2022
143f196
add layout to sketch
Nov 1, 2022
361a28d
refactor sketch service without folders
Nov 2, 2022
05275ab
add copy to clipboard component to write
Nov 2, 2022
03cd801
cleanup sketch auth provider
Nov 2, 2022
9354184
handle delete error (no user feedback yet)
Nov 2, 2022
ae7c4a7
add optional chaining to content
Nov 2, 2022
fb8aa36
only log to console if in development env
Nov 2, 2022
da167de
remove unused file
Nov 2, 2022
d7cd41f
add translations
Nov 2, 2022
eff209b
more translations
Nov 2, 2022
9197b5a
remove console logs
Nov 3, 2022
187a633
Merge branch 'serviceNav' into sketch
Nov 3, 2022
5f1707d
adapt sketch to service submenu component
Nov 3, 2022
7aa2a10
Merge branch 'serviceNav' into sketch
Jan 10, 2023
d5b1da2
adapt sketch to new iframe layout
Jan 10, 2023
2016253
update sketch page to new application folder logix in Matrix.js
Jan 10, 2023
ce7b750
fix bugs created by adapting code to latest code base
Jan 10, 2023
859493e
add '/' in front of urls for config.nex.js
Jan 10, 2023
727dbed
adapt deleting sletches to new server response
Jan 11, 2023
f35f783
sync sketch pads after creating a new one
Jan 11, 2023
a67ffad
Merge branch 'serviceNav' into sketch
Jan 11, 2023
7e1a019
rename localstorage item to spacedeck convention
Jan 11, 2023
72ab4a0
fix layout
Jan 11, 2023
1c6029a
Merge branch 'write' into sketch
Jan 12, 2023
bc01ca0
adapt to changes in serviceNav
Jan 12, 2023
91c72ed
accept cookie from spacedeck
Jan 17, 2023
1c10368
fix sketch sign out
Jan 17, 2023
1390a2e
remove debug console logs
Jan 17, 2023
40b3848
remove hardcoded dev mail
Jan 17, 2023
2a824a4
update config example with sketch
Jan 17, 2023
0d7fcfe
fix infinite loop error when a user has no sketches yet
Mar 28, 2023
a3744a7
Merge branch 'serviceNav' into sketch
Mar 30, 2023
8735240
add option to bypass sketch url validation
Mar 30, 2023
1707fc7
Merge branch 'serviceNav' into sketch
Mar 30, 2023
34f10e6
add rudimentary url validation when sketch url validation is bypassed
Mar 30, 2023
56a010c
Merge branch 'serviceNav' into sketch
Mar 30, 2023
8c3a6b4
Merge branch 'serviceNav' into sketch
Mar 30, 2023
bcc61e7
Merge branch 'serviceNav' into sketch
Apr 20, 2023
651408d
Merge branch 'serviceNav' into sketch
Apr 20, 2023
54cc3a7
Merge branch 'write' into sketch
fnwbr Apr 28, 2023
59f9ea0
Merge branch 'sketch' of https://github.com/medienhaus/medienhaus-spa…
May 2, 2023
6a72fa2
Merge branch 'write' into sketch
fnwbr May 2, 2023
f8cfdb4
Merge branch 'sketch' of https://github.com/medienhaus/medienhaus-spa…
May 2, 2023
04f4f71
Merge branch 'write' into sketch
fnwbr May 4, 2023
078628b
Merge branch 'write' into sketch
fnwbr May 4, 2023
255b787
Update /sketch to make use of the new ServiceSubmenu structure, which…
fnwbr May 4, 2023
f01d3dd
Also remove "bypassUrlValidation" from /sketch again, just like I did…
fnwbr May 4, 2023
e31e2d0
Merge branch 'sketch' of https://github.com/medienhaus/medienhaus-spa…
May 4, 2023
67ec895
fix loading spinner not correctly displaying when adding an existing …
May 4, 2023
6e13147
add message when sketch server is down plus translation
May 4, 2023
38bcf86
adaot wording and add title as optional parameter
May 5, 2023
72bb95a
remove references to write/pads add CopyToClipboard component and imp…
May 5, 2023
b56ad40
add translations
May 5, 2023
d2384cd
remove unused icons
May 5, 2023
3266982
remove button and replace with clipboard component
May 8, 2023
f62b4f6
Merge branch 'write' into sketch
May 8, 2023
b3339c3
Merge branch 'write' into sketch
fnwbr May 8, 2023
8b0f8e2
Run "npx eslint --fix {components,lib,pages}/**/*.js"
fnwbr May 8, 2023
7639277
Merge branch 'write' into sketch
fnwbr May 8, 2023
1f572c9
Merge branch 'write' into sketch
fnwbr May 11, 2023
e072b67
Merge branch 'write' into sketch
May 30, 2023
c366494
Merge branch 'sketch' of https://github.com/medienhaus/medienhaus-spa…
Jun 27, 2023
e1e7a12
Merge branch 'write' into sketch
Jun 27, 2023
d071046
merge main into sketch
Jul 12, 2023
6908aec
Merge branch 'main' into sketch
Jul 13, 2023
93fcd59
Merge branch 'main' into sketch
Jul 13, 2023
ea7ffb9
remove unused import and change template to `sketch-link`
Jul 13, 2023
766ada2
merge main into sketch
Jul 13, 2023
be1bb39
Merge branch 'main' into sketch
andirueckel Jul 13, 2023
8b4ba82
Merge branch 'main' into sketch
Jul 18, 2023
e7f379c
eslint --fix
Jul 18, 2023
d590eb5
get route names from config
Jul 18, 2023
af34688
refactor sketch route to spacedeck route with customisable path name
Jul 18, 2023
eaf0009
Merge branch 'main' into sketch
Jul 18, 2023
ba2f7aa
update config
Jul 18, 2023
ea2e4c7
conditionally display services in the navigation and add rewrites in …
Jul 19, 2023
cb6340b
rename Sketch to Spacedeck
Jul 19, 2023
ce022f5
Merge branch 'main' into sketch
Jul 19, 2023
cccda10
Merge branch 'main' into sketch
Jul 20, 2023
3e01c85
merge main and fix merge conflict in navigation; map through authProv…
Jul 25, 2023
4a8eaf3
remove unused import
Jul 25, 2023
b88619f
Merge branch 'main' into sketch
fnwbr Jul 27, 2023
e76bb3b
Merge branch 'main' into sketch
Jul 27, 2023
35c88f9
comment out spacedeck and mypads
Aug 15, 2023
28e184b
add copy link to clipboard translation
Aug 15, 2023
41a384d
use same error message schme as etherpad and move translation to defa…
Aug 15, 2023
8b811e0
rename `sketch.json` to `spacedeck.json` and update import
Aug 15, 2023
82dd929
push roomId to router after adding existing sketch
Aug 15, 2023
0021538
reset inpiut field after room was added
Aug 15, 2023
157b4a6
add alert when removing sketch fails and combine two ifs into one
Aug 15, 2023
8cc95be
adapt variables to new naming scheme
Aug 15, 2023
0eacdda
use generalised `ServiceLink` component instead of individual compone…
Aug 23, 2023
382bc4b
use generalised `ServiceLink.js` component and move translation for `…
Aug 23, 2023
12f0b9e
use path variable for links instead of hardcoded values
Aug 23, 2023
f259740
use `LoadingSpinnerInline` for inline element
Aug 23, 2023
c1838a7
use `CopyToClipboard` component and update `TextButton` with missing …
Aug 23, 2023
f59bf0c
Merge branch 'main' into sketch
Aug 23, 2023
9ab2eb5
merge main again after pull...
Aug 23, 2023
b1615ca
adapt `spacedeck` to changes in etherpad using `useRef`
Aug 23, 2023
3087c4f
merge main into sketch after #40
Aug 23, 2023
03d2a7d
merge main into sketch
Aug 29, 2023
75435c9
move actions into seperate files
Aug 30, 2023
9e9db35
add missing translation and shorten button title. Change boolean name…
Aug 30, 2023
75c2ec9
fix typo
Aug 30, 2023
55e410c
adapt comment to generalised component
Aug 30, 2023
d7fde62
improve boolean name
Aug 30, 2023
6aff65c
remove unnecessary useEffect and replace `console` with `logger`
Aug 30, 2023
df2a1ec
stop storing content in separate state and call it directly
Aug 30, 2023
37f6f5e
change `removeLink` function to `removeSketch`
Aug 30, 2023
8d43e8e
Merge branch 'main' into sketch
Aug 30, 2023
a6d0e85
create room with template `spacedeck` instead of `sketch-link`
Aug 30, 2023
e2938c3
remove unnecessary parameter
Aug 31, 2023
0c81335
use correct tranlation file
Aug 31, 2023
6e57d83
update translations
Aug 31, 2023
7fed5a3
merge main into sketch
Sep 6, 2023
c083a64
Merge branch 'main' into sketch
fnwbr Sep 12, 2023
bf08eb4
Merge branch 'main' into sketch
fnwbr Sep 12, 2023
743a1a1
Combine ServiceLink.js's `path` and `roomId` parameters into a single…
fnwbr Sep 12, 2023
a6eeee0
Merge branch 'main' into sketch
fnwbr Sep 13, 2023
3451200
Wording consistency between /write and /sketch
fnwbr Sep 20, 2023
4fad50e
Merge remote-tracking branch 'origin/main' into sketch
fnwbr Sep 20, 2023
2f9c2cd
Add Spacedeck.js to define path once
fnwbr Sep 20, 2023
01970d8
Fix translation issue for "Create sketch"
fnwbr Sep 20, 2023
3acbb9d
Remove "sketch" wording from SpacedeckAuthProvider.js
fnwbr Sep 20, 2023
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
26 changes: 26 additions & 0 deletions components/UI/CopyToClipboard.js
aofn marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';

import Clipboard from '../../assets/icons/clipboard.svg';
import TextButton from './TextButton';

const CopyToClipboard = ({ content, title }) => {
aofn marked this conversation as resolved.
Show resolved Hide resolved
const [wasContentCopied, setWasContentCopied] = useState(false);
const { t } = useTranslation();

const copyToClipboard = async () => {
navigator.clipboard.writeText(content);
setWasContentCopied(true);
await new Promise(r => setTimeout(r, 2000));
setWasContentCopied(false);
};

return (
<TextButton title={title || t('Copy link to clipboard')} onClick={copyToClipboard}>
aofn marked this conversation as resolved.
Show resolved Hide resolved
{ wasContentCopied ?
'✓':
<Clipboard fill="var(--color-fg)" /> }
</TextButton>
);
};
export default CopyToClipboard;
32 changes: 32 additions & 0 deletions components/UI/ServiceLink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { forwardRef } from 'react';
import { useTranslation } from 'react-i18next';
import Link from 'next/link';
import styled from 'styled-components';

import LockIcon from '../../assets/icons/lock.svg';
import { ServiceTable } from './ServiceTable';

const LockIconResized = styled(LockIcon)`
display: block;
transform: scale(0.9);
`;

const ServiceLink = forwardRef(({ name, href, selected, passwordProtected }, ref) => {
const { t } = useTranslation();

return (
<ServiceTable.Row>
<ServiceTable.Cell selected={selected}>
<Link ref={ref} href={href}>{ name }</Link>
</ServiceTable.Cell>
{ /* Show a lock icon if this Link is password protected */ }
{ passwordProtected && (
<ServiceTable.Cell title={t('password protected')}>
<LockIconResized />
</ServiceTable.Cell>
) }
</ServiceTable.Row>
);
});

export default ServiceLink;
1 change: 1 addition & 0 deletions components/UI/TextButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import styled from 'styled-components';
const TextButton = styled.button`
padding: 0;
font: inherit;
color: var(--color-foreground);
cursor: pointer;
background: none;
border: none;
Expand Down
7 changes: 7 additions & 0 deletions components/layouts/partials/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ export default function Navigation({ closeNavigation }) {
</Link>
</li>
) }
{ _.get(getConfig(), 'publicRuntimeConfig.authProviders.spacedeck.path') && (
<li>
<Link href={getConfig().publicRuntimeConfig.authProviders.spacedeck.path}>
{ getConfig().publicRuntimeConfig.authProviders.spacedeck.path }
</Link>
</li>
) }
</List>
<List>
<li><Link href="/logout">/logout</Link></li>
Expand Down
2 changes: 2 additions & 0 deletions lib/Auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import _ from 'lodash';
import MatrixAuthProvider from './auth/MatrixAuthProvider';
import PeerTubeAuthProvider from './auth/PeerTubeAuthProvider';
import MyPadsAuthProvider from './auth/MyPadsAuthProvider';
import SpacedeckAuthProvider from './auth/SpacedeckAuthProvider';

/*
Mapping of authentication provider types and which corresponding class should be used to actually perform
Expand All @@ -16,6 +17,7 @@ const AuthProviders = {
matrix: MatrixAuthProvider,
peerTube: PeerTubeAuthProvider,
etherpad: MyPadsAuthProvider,
spacedeck: SpacedeckAuthProvider,
};

function useAuthProvider() {
Expand Down
5 changes: 5 additions & 0 deletions lib/Spacedeck.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import getConfig from 'next/config';

const path = getConfig().publicRuntimeConfig.authProviders.spacedeck.path || '/spacedeck';

export { path };
215 changes: 215 additions & 0 deletions lib/auth/SpacedeckAuthProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
import _ from 'lodash';
class SpacedeckAuthProvider {
constructor(configuration) {
this.allSpaces = {};
this.allFolder = {};
this.structure = {};
this.url = configuration.baseUrl;
if (typeof window !== 'undefined' && window.localStorage.getItem('x-spacedeck-auth')) {
this.token = window.localStorage.getItem('x-spacedeck-auth');
}
}

async signin(usr, pwd) {
const login = await this._login(this.url, usr, pwd);
if (!login) return;
this.token = login.token;
window.localStorage.setItem('x-spacedeck-auth', this.token);

this.user_id = login.user_id;
this.pwd = '';
this.userData = await this._getInititalUserData();

this.homeFolderId = this.userData?.home_folder_id;

this.structure = await this._getData(this.url, this.token);
}

async signout() {
const response = await fetch(this.url + '/api/sessions/current', {
method: 'DELETE',
headers: {
'X-Spacedeck-Auth': this.token,
},
});
if (!response) return;
}

async _getInititalUserData() {
const response = await fetch(this.url + '/api/users/current', {
method: 'GET',
headers: {
'X-Spacedeck-Auth': this.token,
},
});
if (!response) return;
const content = await response?.json();

return content;
}

async _getData(baseUrl = this.url, token = this.token, parentId) {
const structure = {};
structure.children = {};
let requestUrl = '';
if (parentId) {
requestUrl = baseUrl + '/api/spaces?parent_space_id=' + parentId;
} else {
requestUrl = baseUrl + '/api/spaces';
}
const response = await fetch(requestUrl, {
method: 'get',
headers: {
'X-Spacedeck-Auth': token,
},
});
if (!response) return;
const content = await response?.json();
await Promise.all(_.map(content, async (element) => {
structure.children[element._id] = {
name: element.name,
id: element._id,
access_mode: element.access_mode,
password: element.password ? element.password : '',
created_at: element.created_at,
updated_at: element.updated_at,
creator: element.creator,
};
if (element.space_type === 'space') {
structure.children[element._id].type = 'space';
structure.children[element._id].thumbnail_url = element.thumbnail_url ? element.thumbnail_url : '';
structure.children[element._id].thumbnail_updated_at = element.thumbnail_updated_at ? element.thumbnail_updated_at : '';
structure.children[element._id].width = element.width;
structure.children[element._id].height = element.height;
structure.children[element._id].shareUrl = baseUrl + 's/' + element.edit_hash + '-' + element.name;
structure.children[element._id].access_mode = element.access_mode;
this.allSpaces[element._id] = element;
this.allSpaces[element._id].id = element._id;
} else if (element.space_type === 'folder') {
structure.children[element._id] = await this._getData(baseUrl, token, element._id);
structure.children[element._id].type = 'folder';
structure.children[element._id].name = element.name;
structure.children[element._id].id = element._id;
this.allFolder[element._id] = element;
}
}));

return structure.children;
}

async _login(baseUrl, usr, password) {
const response = await fetch(baseUrl + '/api/sessions', {
method: 'POST',
body: JSON.stringify({
email: usr,
password: password,
}),
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
});
const data = await response.json();
if (data?.user_id && data?.token) {
return data;
}
}

async _createElement(name, parentFolderId = this.homeFolderId, type = 'space') {
const response = await fetch(this.url + '/api/spaces', {
method: 'post',
headers: {
'X-Spacedeck-Auth': this.token,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: name,
space_type: type,
parent_space_id: parentFolderId,
}),
});

if (!response) return;
const content = await response?.json();
if (!content) return;

return content;
}

// Public functions

getAllSpaces() {
return this.allSpaces;
}

getStructure() {
return this.structure;
}

async createSpace(spaceName, parentFolderId = this.homeFolderId) {
const data = this._createElement(spaceName, parentFolderId, 'space');
if (!data) return;
this.allSpaces[data._id] = data;
await this.syncAllSpaces();

return data;
}

async deleteSpaceById(spaceId) {
if (!this.getSpaceById(spaceId)) return;
const response = await fetch(this.url + '/api/spaces/' + spaceId, {
method: 'DELETE',
headers: {
'x-spacedeck-auth': this.token,
},
}).catch((e) => {
console.log(e);
});

return response;
}

getElementById(id) {
let foundElement = this.getSpaceById(id);
if (foundElement) {
return foundElement;
} else {
foundElement = this.getFolderById(id);
if (foundElement) return foundElement;
}
}

getSpaceById(id) {
return _.find(this.allSpaces, { id: id });
}

getFolderById(id) {
return _.find(this.allFolder, { id: id });
}

getFolderByName(name) {
return _.filter(this.allFolder, { name: name });
}

getSpaceByName(name) {
return _.filter(this.allSpaces, { name: name });
}

getElementByName(name) {
let foundElement = this.getSpaceByName(name);
if (foundElement) {
return foundElement;
} else {
foundElement = this.getFolderByName(name);
if (foundElement) return foundElement;
}
}

async syncAllSpaces() {
this.structure = await this._getData(this.url, this.token);

return this.structure;
}
}

export default SpacedeckAuthProvider;
38 changes: 29 additions & 9 deletions next.config.example.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ module.exports = {
// important: path has to start with "/"
path: '/write',
baseUrl: 'https://pad.riseup.net/p',
myPads: {
api: 'http://etherpad.localhost/mypads/api',
spacesGroupName: '/spaces', // optional, defaults to publicRuntimeConfig.name
},
// myPads: {
// api: 'http://etherpad.localhost/mypads/api',
// spacesGroupName: '/spaces', // optional, defaults to publicRuntimeConfig.name

// },
},
aofn marked this conversation as resolved.
Show resolved Hide resolved
// spacedeck: {
// path: '/sketch',
// baseUrl: 'http://spacedeck.localhost',
// },
},
contextRootSpaceRoomId: '!gB.....Ewlvdq:matrix.org',
account: {
Expand All @@ -26,17 +31,32 @@ module.exports = {
pathToElement: '//localhost/element',
},
},
async rewrites() {
return [
{
rewrites() {
const rewriteConfig = [];

if (this.publicRuntimeConfig.authProviders.etherpad) {
rewriteConfig.push({
source: this.publicRuntimeConfig.authProviders.etherpad.path,
destination: '/etherpad',
},
{
source: this.publicRuntimeConfig.authProviders.etherpad.path + '/:roomId',
destination: '/etherpad/:roomId',
},
];
});
}
if (this.publicRuntimeConfig.authProviders.spacedeck) {
rewriteConfig.push(
{
source: this.publicRuntimeConfig.authProviders.spacedeck.path,
destination: '/spacedeck',
},
{
source: this.publicRuntimeConfig.authProviders.spacedeck.path + '/:roomId',
destination: '/spacedeck/:roomId',
});
}

return rewriteConfig;
},
webpack: WebpackConfig,
};
Loading