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
2 changes: 1 addition & 1 deletion app/Http/Controllers/MonitorsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public function store(MonitorRequest $request)
'group_id' => $validated['monitorGroupId'],
]);

if ($monitor) {
if ($monitor && $monitor->domain_check_enabled) {
DomainService::addDomainExpiration($monitor);
}

Expand Down
66 changes: 66 additions & 0 deletions app/Http/Controllers/UsersController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace App\Http\Controllers;

use App\Http\Requests\UserRequest;
use App\User;
use Inertia\Inertia;

class UsersController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}

public function index()
{
return Inertia::render('Users/Index', [
'users' => User::orderBy('name')->get(),
]);
}

public function create()
{
return Inertia::render('Users/Create', []);
}

public function store(UserRequest $request)
{
$validated = $request->validated();
$user = User::create([
'name' => $validated['name'],
'email' => $validated['email'],
'password' => bcrypt($validated['password']),
]);

return redirect()->route('users.index');
}

public function edit(User $user)
{
return Inertia::render('Users/Edit', [
'user' => $user,
]);
}

public function update(UserRequest $request, User $user)
{
$validated = $request->validated();
$user->update([
'name' => $validated['name'],
'email' => $validated['email'],
// Only update password if provided
'password' => $validated['password'] ? bcrypt($validated['password']) : $user->password,
]);

return redirect()->route('users.index');
}

public function destroy(User $user)
{
$user->delete();

return redirect()->route('users.index');
}
}
28 changes: 28 additions & 0 deletions app/Http/Requests/UserRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}

public function rules(): array
{
$rules = [
'name' => 'required|string',
'email' => 'required|email|unique:users,email'.($this->user ? ','.$this->user->id : ''),
];
if ($this->isMethod('post')) {
$rules['password'] = 'required|string|min:6';
} elseif ($this->isMethod('put') || $this->isMethod('patch')) {
$rules['password'] = 'nullable|string|min:6';
}

return $rules;
}
}
423 changes: 410 additions & 13 deletions public/js/app.js

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions resources/js/Layouts/Authenticated.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,20 @@ export default function Authenticated({ auth, children }) {
</div>

<div className="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<NavLink href={route('monitors.index')} active={route().current('monitors.index')}>
<NavLink href={route('monitors.index')} active={route().current('monitors.*')}>
Monitors
</NavLink>
</div>
<div className="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<NavLink href={route('groups.index')} active={route().current('groups.index')}>
<NavLink href={route('groups.index')} active={route().current('groups.*')}>
Groups
</NavLink>
</div>
<div className="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<NavLink href={route('users.index')} active={route().current('users.*')}>
Users
</NavLink>
</div>
</div>

<div className="hidden sm:flex sm:items-center sm:ml-6">
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Pages/Groups/Create.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function Create(props) {

const handleSubmit = (e) => {
e.preventDefault();
router.post('/groups', form);
router.post(route('groups.store'), form);
};

return (
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Pages/Groups/Edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function Edit(props) {

const handleSubmit = (e) => {
e.preventDefault();
router.put(`/groups/${group.id}`, form);
router.put(route('groups.update', group.id), form);
};

return (
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Pages/Groups/Index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function Index(props) {
<PageHeader>
<div className='flex justify-between items-center'>
<h2 className="font-bold text-xl text-purple-600 leading-tight uppercase">Groups</h2>
<Link href='groups/create'>
<Link href={route('groups.create')}>
<Button>
<PlusIcon className="h-4 w-4 mr-1"/>
<span>Create</span>
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Pages/Monitors/Create.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default function Create(props) {

const handleSubmit = (e) => {
e.preventDefault();
router.post('/monitors', form);
router.post(route('monitors.store'), form);
};

return (
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Pages/Monitors/Edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function Edit(props) {

const handleSubmit = (e) => {
e.preventDefault();
router.put(`/monitors/${monitor.id}`, form);
router.put(route('monitors.update', monitor.id), form);
};

return (
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Pages/Monitors/Index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function Index(props) {
<PageHeader>
<div className='flex justify-between items-center'>
<h2 className="font-bold text-xl text-purple-600 leading-tight uppercase">Monitors</h2>
<Link href='monitors/create'>
<Link href={route('monitors.create')}>
<Button>
<PlusIcon className="h-4 w-4 mr-1"/>
<span>Create</span>
Expand Down
61 changes: 61 additions & 0 deletions resources/js/Pages/Users/Create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { useState } from "react";
import Authenticated from "@/Layouts/Authenticated";
import { Head } from "@inertiajs/react";
import PageHeader from "@/components/PageHeader";
import Button from "@/Components/Button";
import Label from "@/Components/Label";
import Input from "@/Components/Input";
import { router } from '@inertiajs/react'

export default function Create(props) {
const [form, setForm] = useState({
name: "",
email: "",
password: "",
});

const handleChange = (e) => {
const { name, value, type, checked } = e.target;
setForm((prevState) => ({
...prevState,
[name]: type === "checkbox" ? checked : value,
}));
};

const handleSubmit = (e) => {
e.preventDefault();
router.post(route('users.store'), form);
};

return (
<Authenticated auth={props.auth} errors={props.errors}>
<Head title="Create User" />

<PageHeader>
<h2 className="font-bold text-xl text-purple-600 leading-tight uppercase">
Create User
</h2>
</PageHeader>

<div className="mx-auto py-12 w-1/2">
<form onSubmit={handleSubmit}>
<div className="mb-4">
<Label forInput="name">Name</Label>
<Input name="name" value={form.name} required handleChange={handleChange} />
</div>
<div className="mb-4">
<Label forInput="email">Email</Label>
<Input name="email" type="email" value={form.email} required handleChange={handleChange} />
</div>
<div className="mb-4">
<Label forInput="password">Password</Label>
<Input name="password" type="password" value={form.password} required handleChange={handleChange} />
</div>
<div>
<Button>Create</Button>
</div>
</form>
</div>
</Authenticated>
);
}
63 changes: 63 additions & 0 deletions resources/js/Pages/Users/Edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { useState } from "react";
import Authenticated from "@/Layouts/Authenticated";
import { Head, usePage } from "@inertiajs/react";
import PageHeader from "@/components/PageHeader";
import Button from "@/Components/Button";
import Label from "@/Components/Label";
import Input from "@/Components/Input";
import { router } from '@inertiajs/react';

export default function Edit(props) {
const { user } = usePage().props;

const [form, setForm] = useState({
name: user.name,
email: user.email,
password: "",
});

const handleChange = (e) => {
const { name, value, type, checked } = e.target;
setForm((prevState) => ({
...prevState,
[name]: type === "checkbox" ? checked : value,
}));
};

const handleSubmit = (e) => {
e.preventDefault();
router.put(route('users.update', user.id), form);
};

return (
<Authenticated auth={props.auth} errors={props.errors}>
<Head title="Edit User" />

<PageHeader>
<h2 className="font-bold text-xl text-purple-600 leading-tight uppercase">
Edit User
</h2>
</PageHeader>

<div className="mx-auto py-12 w-1/2">
<form onSubmit={handleSubmit}>
<div className="mb-4">
<Label forInput="name">Name</Label>
<Input name="name" value={form.name} required handleChange={handleChange} />
</div>
<div className="mb-4">
<Label forInput="email">Email</Label>
<Input name="email" type="email" value={form.email} required handleChange={handleChange} />
</div>
<div className="mb-4">
<Label forInput="password">Password (leave blank to keep current)</Label>
<Input name="password" type="password" value={form.password} handleChange={handleChange} />
</div>
<div>
<Button>Update</Button>
</div>
</form>
</div>
</Authenticated>
);
}
40 changes: 40 additions & 0 deletions resources/js/Pages/Users/Index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import Authenticated from '@/Layouts/Authenticated';
import { Head, Link, usePage } from '@inertiajs/react';
import UserCard from '@/components/UserCard';
import PageHeader from '@/components/PageHeader';
import Button from '@/Components/Button';
import { PlusIcon } from '@heroicons/react/24/solid';

export default function Index(props) {
const { users } = usePage().props;

return (
<Authenticated
auth={props.auth}
errors={props.errors}
>
<Head title="Users" />

<PageHeader>
<div className='flex justify-between items-center'>
<h2 className="font-bold text-xl text-purple-600 leading-tight uppercase">Users</h2>
<Link href={route('users.create')}>
<Button>
<PlusIcon className="h-4 w-4 mr-1"/>
<span>Create</span>
</Button>
</Link>
</div>
</PageHeader>

<div className="py-12">
<div className="flex flex-wrap max-w-7xl mx-auto sm:px-6 lg:px-8">
{users.map((user, index) => (
<UserCard user={user} key={index} />
))}
</div>
</div>
</Authenticated>
);
}
4 changes: 2 additions & 2 deletions resources/js/components/GroupCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function GroupCard ({ group }) {
e.preventDefault();
if (monitorsCount) return;
if (confirm(`Are you sure you want to remove the group ${group.name}?`)) {
router.delete(`/groups/${group.id}`);
router.delete(route('groups.destroy', group.id));
}
}

Expand All @@ -26,7 +26,7 @@ export default function GroupCard ({ group }) {
</div>
</div>
<div className="flex items-center">
<Link href={`groups/${group.id}/edit`} className="flex items-center rounded-full px-1.5 py-1.5 text-gray-500 hover:bg-purple-200 hover:text-purple-600">
<Link href={route('groups.edit', group.id)} className="flex items-center rounded-full px-1.5 py-1.5 text-gray-500 hover:bg-purple-200 hover:text-purple-600">
<PencilIcon className='h-4 w-4' />
</Link>
{monitorsCount ?
Expand Down
4 changes: 2 additions & 2 deletions resources/js/components/MonitorCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function MonitorCard ({ monitor }) {
const handleDelete = (e) => {
e.preventDefault();
if (confirm(`Are you sure you want to remove ${monitor.name} (${monitor.raw_url}) from monitoring?`)) {
router.delete(`/monitors/${monitor.id}`);
router.delete(route('monitors.destroy', monitor.id));
}
}

Expand All @@ -37,7 +37,7 @@ export default function MonitorCard ({ monitor }) {
</div>
</div>
<div className="flex">
<Link href={`monitors/${monitor.id}/edit`} className="flex items-center rounded-full px-1.5 py-1.5 text-gray-500 hover:bg-purple-200 hover:text-purple-600">
<Link href={route('monitors.edit', monitor.id)} className="flex items-center rounded-full px-1.5 py-1.5 text-gray-500 hover:bg-purple-200 hover:text-purple-600">
<PencilIcon className='h-4 w-4' />
</Link>
<div className="flex items-center rounded-full px-1.5 py-1.5 hover:bg-red-200 text-gray-500 hover:text-red-600 cursor-pointer" onClick={handleDelete}>
Expand Down
Loading