return $round->toJson();
        }
 
+       public function delete(Request $request, Round $round) {
+               $this->authorize('delete', $round);
+               if (count($round->results) > 0) {
+                       return response('Forbidden', 403);
+               }
+               $round->load('tournament');
+               $round->delete();
+               Protocol::roundDeleted(
+                       $round->tournament,
+                       $round,
+                       $request->user(),
+               );
+               return $round->toJson();
+       }
+
        public function update(Request $request, Round $round) {
                $this->authorize('update', $round);
 
 
                ProtocolAdded::dispatch($protocol);
        }
 
+       public static function roundDeleted(Tournament $tournament, Round $round, User $user) {
+               $protocol = static::create([
+                       'tournament_id' => $tournament->id,
+                       'user_id' => $user->id,
+                       'type' => 'round.delete',
+                       'details' => [
+                               'tournament' => static::tournamentMemo($tournament),
+                               'round' => static::roundMemo($round),
+                       ],
+               ]);
+               ProtocolAdded::dispatch($protocol);
+       }
+
        public static function roundEdited(Tournament $tournament, Round $round, User $user) {
                $protocol = static::create([
                        'tournament_id' => $tournament->id,
 
 
 namespace App\Models;
 
+use Illuminate\Broadcasting\Channel;
+use Illuminate\Database\Eloquent\BroadcastsEvents;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 
 class Round extends Model
 {
+       use BroadcastsEvents;
        use HasFactory;
 
        public function protocols() {
                return $this->tournament->protocols()->where('details->round->id', '=', $this->id);
        }
 
+       public function broadcastOn($event) {
+               return [
+                       new Channel('Tournament.'.$this->tournament_id),
+               ];
+       }
+
 
        public function isComplete() {
                if (count($this->tournament->participants) == 0) return false;
 
         */
        public function delete(User $user, Round $round)
        {
-               return false;
+               return !$round->tournament->locked && $user->isTournamentAdmin($round->tournament) && count($round->results) == 0;
        }
 
        /**
 
                        </Trans>;
                }
                case 'round.create':
+               case 'round.delete':
                case 'round.edit':
                case 'round.lock':
                case 'round.seed':
                        return <Icon.RESULT />;
                case 'round.create':
                        return <Icon.ADD />;
+               case 'round.delete':
+                       return <Icon.REMOVE />;
                case 'round.lock':
                case 'tournament.close':
                case 'tournament.lock':
 
--- /dev/null
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import DeleteDialog from './DeleteDialog';
+import Icon from '../common/Icon';
+
+const DeleteButton = ({
+       round,
+       tournament,
+}) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       const { t } = useTranslation();
+
+       return <>
+               <DeleteDialog
+                       onHide={() => setShowDialog(false)}
+                       round={round}
+                       show={showDialog}
+                       tournament={tournament}
+               />
+               <Button
+                       onClick={() => setShowDialog(true)}
+                       size="sm"
+                       title={t('rounds.delete')}
+                       variant="outline-danger"
+               >
+                       <Icon.REMOVE title="" />
+               </Button>
+       </>;
+};
+
+DeleteButton.propTypes = {
+       round: PropTypes.shape({
+               locked: PropTypes.bool,
+       }),
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default DeleteButton;
 
--- /dev/null
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Button, Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+const EditDialog = ({
+       onHide,
+       round,
+       show,
+}) => {
+       const { t } = useTranslation();
+
+       const handleDelete = React.useCallback(async() => {
+               try {
+                       await axios.delete(`/api/rounds/${round.id}`);
+                       onHide();
+               } catch (e) {
+                       toastr.error(t('rounds.deleteError'));
+               }
+       }, [onHide, round, t]);
+
+       return <Modal className="edit-dialog" onHide={onHide} show={show}>
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('rounds.delete')}
+                       </Modal.Title>
+               </Modal.Header>
+               <Modal.Body>
+                       <Alert variant="danger">
+                               {t('rounds.deleteConfirmMessage', {
+                                       ...round,
+                                       date: new Date(round.created_at),
+                               })}
+                       </Alert>
+               </Modal.Body>
+               <Modal.Footer>
+                       <Button onClick={onHide} variant="secondary">
+                               {t('button.cancel')}
+                       </Button>
+                       <Button onClick={handleDelete} variant="danger">
+                               {t('button.delete')}
+                       </Button>
+               </Modal.Footer>
+       </Modal>;
+};
+
+EditDialog.propTypes = {
+       onHide: PropTypes.func,
+       round: PropTypes.shape({
+               created_at: PropTypes.string,
+               id: PropTypes.number,
+       }),
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default EditDialog;
 
 import PropTypes from 'prop-types';
 import React, { useState } from 'react';
 import { Button } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
+import { useTranslation } from 'react-i18next';
 
 import EditDialog from './EditDialog';
 import Icon from '../common/Icon';
-import i18n from '../../i18n';
 
 const EditButton = ({
        round,
 }) => {
        const [showDialog, setShowDialog] = useState(false);
 
+       const { t } = useTranslation();
+
        return <>
                <EditDialog
                        onHide={() => setShowDialog(false)}
                <Button
                        onClick={() => setShowDialog(true)}
                        size="sm"
-                       title={i18n.t('rounds.edit')}
+                       title={t('rounds.edit')}
                        variant="outline-secondary"
                >
                        <Icon.EDIT title="" />
        }),
 };
 
-export default withTranslation()(EditButton);
+export default EditButton;
 
 import PropTypes from 'prop-types';
 import React from 'react';
 import { Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
+import { useTranslation } from 'react-i18next';
 
 import EditForm from './EditForm';
-import i18n from '../../i18n';
 
 const EditDialog = ({
        onHide,
        round,
        show,
-}) =>
-<Modal className="edit-dialog" onHide={onHide} show={show}>
-       <Modal.Header closeButton>
-               <Modal.Title>
-                       {i18n.t('rounds.edit')}
-               </Modal.Title>
-       </Modal.Header>
-       <EditForm
-               onCancel={onHide}
-               round={round}
-       />
-</Modal>;
+}) => {
+       const { t } = useTranslation();
+
+       return <Modal className="edit-dialog" onHide={onHide} show={show}>
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('rounds.edit')}
+                       </Modal.Title>
+               </Modal.Header>
+               <EditForm
+                       onCancel={onHide}
+                       round={round}
+               />
+       </Modal>;
+};
 
 EditDialog.propTypes = {
        onHide: PropTypes.func,
        }),
 };
 
-export default withTranslation()(EditDialog);
+export default EditDialog;
 
 import React from 'react';
 import { useTranslation } from 'react-i18next';
 
+import DeleteButton from './DeleteButton';
 import EditButton from './EditButton';
 import LockButton from './LockButton';
 import SeedButton from './SeedButton';
 import List from '../results/List';
 import ReportButton from '../results/ReportButton';
 import {
+       mayDeleteRound,
        mayEditRound,
        mayReportResult,
        mayViewProtocol,
                                        {mayViewProtocol(user, tournament, round) ?
                                                <RoundProtocol roundId={round.id} tournamentId={tournament.id} />
                                        : null}
+                                       {mayDeleteRound(user, tournament, round) ?
+                                               <DeleteButton round={round} tournament={tournament} />
+                                       : null}
                                </div>
                        </div>
                        <List round={round} tournament={tournament} />
 
 import Participant from './Participant';
 import Tournament from './Tournament';
 
+export const hasResults = (round) => {
+       return round && round.results && round.results.length > 0;
+};
+
 export const isComplete = (tournament, round) => {
        if (!tournament || !tournament.participants) return false;
        if (tournament.type === 'open-async') return false;
 };
 
 export default {
+       hasResults,
        isComplete,
        patchResult,
 };
 
        return isRunner(user, tournament);
 };
 
+export const mayDeleteRound = (user, tournament, round) =>
+       !tournament.locked && isTournamentAdmin(user, tournament) && !Round.hasResults(round);
+
 export const mayEditRound = (user, tournament) =>
        !tournament.locked && isTournamentAdmin(user, tournament);
 
 
                        chart: 'Diagramm',
                        close: 'Schließen',
                        confirm: 'Bestätigen',
+                       delete: 'Löschen',
                        edit: 'Bearbeiten',
                        filter: 'Filter',
                        generate: 'Generieren',
                                },
                                round: {
                                        create: 'Runde #{{number}} hinzugefügt',
+                                       delete: 'Runde #{{number}} gelöscht',
                                        edit: 'Runde #{{number}} bearbeitet',
                                        lock: 'Runde #{{number}} gesperrt',
                                        seed: 'Seed für Runde #{{number}} eingetragen',
                rounds: {
                        code: 'Code',
                        date: '{{ date, L }}',
+                       delete: 'Runde löschen',
+                       deleteConfirmMessage: 'Runde #{{ number }} vom {{ date, L }} löschen?',
+                       deleteError: 'Fehler beim Löschen',
+                       deleteSuccess: 'Runde gelöscht',
                        edit: 'Runde bearbeiten',
                        editError: 'Fehler beim Speichern',
                        editSuccess: 'Gespeichert',
 
                        chart: 'Chart',
                        close: 'Close',
                        confirm: 'Confirm',
+                       delete: 'Delete',
                        edit: 'Edit',
                        filter: 'Filter',
                        generate: 'Generate',
                                },
                                round: {
                                        create: 'Added round #{{number}}',
+                                       delete: 'Deleted round #{{number}}',
                                        edit: 'Edited round #{{number}}',
                                        lock: 'Round #{{number}} locked',
                                        seed: 'Set seed for round #{{number}}',
                rounds: {
                        code: 'Code',
                        date: '{{ date, L }}',
+                       delete: 'Delete round',
+                       deleteConfirmMessage: 'Remove round #{{ number }} from {{ date, L }}?',
+                       deleteError: 'Error deleting round',
+                       deleteSuccess: 'Round deleted',
                        edit: 'Edit round',
                        editError: 'Error saving round',
                        editSuccess: 'Saved successfully',
 
                                        setTournament(tournament => patchRound(tournament, e.round));
                                }
                        })
+                       .listen('.RoundDeleted', e => {
+                               if (e.model) {
+                                       setTournament(tournament => ({
+                                               ...tournament,
+                                               rounds: tournament.rounds.filter((r) => r.id !== e.model.id),
+                                       }));
+                               }
+                       })
                        .listen('TournamentChanged', e => {
                                if (e.tournament) {
                                        setTournament(tournament => ({ ...tournament, ...e.tournament }));
 
 
 Route::post('rounds', 'App\Http\Controllers\RoundController@create');
 Route::put('rounds/{round}', 'App\Http\Controllers\RoundController@update');
+Route::delete('rounds/{round}', 'App\Http\Controllers\RoundController@delete');
 Route::post('rounds/{round}/lock', 'App\Http\Controllers\RoundController@lock');
 Route::post('rounds/{round}/setSeed', 'App\Http\Controllers\RoundController@setSeed');
 Route::post('rounds/{round}/unlock', 'App\Http\Controllers\RoundController@unlock');