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
5 changes: 3 additions & 2 deletions admin/src/components/IconButton.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import {FC, JSX, ReactElement} from "react";

export type IconButtonProps = {
style?: React.CSSProperties,
icon: JSX.Element,
title: string|ReactElement,
onClick: ()=>void,
className?: string,
disabled?: boolean
}

export const IconButton:FC<IconButtonProps> = ({icon,className,onClick,title, disabled})=>{
return <button onClick={onClick} className={"icon-button "+ className} disabled={disabled}>
export const IconButton:FC<IconButtonProps> = ({icon,className,onClick,title, disabled, style})=>{
return <button style={style} onClick={onClick} className={"icon-button "+ className} disabled={disabled}>
{icon}
<span>{title}</span>
</button>
Expand Down
27 changes: 27 additions & 0 deletions admin/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ div.menu {
position: fixed;
}

[role="dialog"] h2 {
color: var(--etherpad-color);
}

.icon-button {
display: flex;
Expand All @@ -54,6 +57,26 @@ div.menu {
cursor: pointer;
}

.icon-button:hover {
background-color: #13a37c;
}


.dialog-close-button {
position: absolute;
top: 10px;
right: 10px;
background: none;
border: none;
cursor: pointer;
color: var(--etherpad-color);
}

.icon-button:active {
background-color: #13a37c;
transform: scale(0.98);
}

.icon-button svg {
align-self: center;
}
Expand Down Expand Up @@ -868,3 +891,7 @@ input, button, select, optgroup, textarea {
display: flex;
justify-content: center;
}

.manage-pads-header {
display: flex;
}
69 changes: 66 additions & 3 deletions admin/src/pages/PadPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ import {useDebounce} from "../utils/useDebounce.ts";
import {determineSorting} from "../utils/sorting.ts";
import * as Dialog from "@radix-ui/react-dialog";
import {IconButton} from "../components/IconButton.tsx";
import {ChevronLeft, ChevronRight, Eye, Trash2, FileStack} from "lucide-react";
import {ChevronLeft, ChevronRight, Eye, Trash2, FileStack, PlusIcon} from "lucide-react";
import {SearchField} from "../components/SearchField.tsx";
import {useForm} from "react-hook-form";

type PadCreateProps = {
padName: string
}

export const PadPage = ()=>{
const settingsSocket = useStore(state=>state.settingsSocket)
Expand All @@ -25,6 +30,8 @@ export const PadPage = ()=>{
const [deleteDialog, setDeleteDialog] = useState<boolean>(false)
const [errorText, setErrorText] = useState<string|null>(null)
const [padToDelete, setPadToDelete] = useState<string>('')
const [createPadDialogOpen, setCreatePadDialogOpen] = useState<boolean>(false)
const {register, handleSubmit} = useForm<PadCreateProps>()
const pages = useMemo(()=>{
if(!pads){
return 0;
Expand Down Expand Up @@ -70,8 +77,33 @@ export const PadPage = ()=>{
})
})

type SettingsSocketCreateReponse = {
error: string
} | {
success: string
}

settingsSocket.on('results:createPad', (rep: SettingsSocketCreateReponse)=>{
if ('error' in rep) {
useStore.getState().setToastState({
open: true,
title: rep.error,
success: false
})
} else {
useStore.getState().setToastState({
open: true,
title: rep.success,
success: true
})
setCreatePadDialogOpen(false)
// reload pads
settingsSocket.emit('padLoad', searchParams)
}
})

settingsSocket.on('results:cleanupPadRevisions', (data)=>{
let newPads = useStore.getState().pads?.results ?? []
const newPads = useStore.getState().pads?.results ?? []

if (data.error) {
setErrorText(data.error)
Expand Down Expand Up @@ -99,6 +131,12 @@ export const PadPage = ()=>{
settingsSocket?.emit('cleanupPadRevisions', padID)
}

const onPadCreate = (data: PadCreateProps)=>{
settingsSocket?.emit('createPad', {
padName: data.padName
})
}


return <div>
<Dialog.Root open={deleteDialog}><Dialog.Portal>
Expand Down Expand Up @@ -139,7 +177,32 @@ export const PadPage = ()=>{
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
<h1><Trans i18nKey="ep_admin_pads:ep_adminpads2_manage-pads"/></h1>
<Dialog.Root open={createPadDialogOpen}>
<Dialog.Portal>
<Dialog.Overlay className="dialog-confirm-overlay" />
<Dialog.Content className="dialog-confirm-content">
<Dialog.Title className="dialog-confirm-title"><Trans i18nKey="index.newPad"/></Dialog.Title>
<form onSubmit={handleSubmit(onPadCreate)}>
<button className="dialog-close-button" onClick={()=>{
setCreatePadDialogOpen(false);
}}>x</button>
<div style={{display: 'grid', gap: '10px', gridTemplateColumns: 'auto auto', marginBottom: '1rem'}}>
<label><Trans i18nKey="ep_admin_pads:ep_adminpads2_padname"/></label>
<input {...register('padName', {
required: true
})}/>
</div>
<input type="submit" value={t('admin_settings.createPad')} className="login-button" />
</form>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
<span className="manage-pads-header">
<h1><Trans i18nKey="ep_admin_pads:ep_adminpads2_manage-pads"/></h1>
<span style={{width: '29px', marginBottom: 'auto', marginTop: 'auto', flexGrow: 1}}><IconButton style={{float: 'right'}} icon={<PlusIcon/>} title={<Trans i18nKey="index.newPad"/>} onClick={()=>{
setCreatePadDialogOpen(true)
}}/></span>
</span>
<SearchField value={searchTerm} onChange={v=>setSearchTerm(v.target.value)} placeholder={t('ep_admin_pads:ep_adminpads2_search-heading')}/>
<table>
<thead>
Expand Down
1 change: 1 addition & 0 deletions src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"admin_settings.current_save.value": "Einstellungen speichern",
"admin_settings.page-title": "Einstellungen - Etherpad",
"index.newPad": "Neues Pad",
"admin_settings.createPad": "Erstellen",
"index.createOpenPad": "Pad öffnen",
"index.openPad": "Öffne ein vorhandenes Pad mit folgendem Namen:",
"index.recentPads": "Zuletzt bearbeitete Pads",
Expand Down
19 changes: 19 additions & 0 deletions src/node/hooks/express/adminsettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,25 @@ exports.socketio = (hookName: string, {io}: any) => {
}
})

type PadCreationOptions = {
padName: string,
}

socket.on('createPad', async ({padName}: PadCreationOptions)=>{
const padExists = await padManager.doesPadExists(padName);
if (padExists) {
socket.emit('results:createPad', {
error: 'Pad already exists',
});
return;
}
padManager.getPad(padName);
socket.emit('results:createPad', {
success: `Pad created ${padName}`,
});
return;
})

socket.on('cleanupPadRevisions', async (padId: string) => {
if (!settings.cleanup.enabled) {
socket.emit('results:cleanupPadRevisions', {
Expand Down
Loading