Skip to content

Commit

Permalink
Merge pull request #1 from discoverydesign/management-modal
Browse files Browse the repository at this point in the history
Feature - `->advance()`
  • Loading branch information
discoveryjames authored Sep 1, 2024
2 parents 738c894 + 65fd1cb commit b849098
Show file tree
Hide file tree
Showing 7 changed files with 402 additions and 21 deletions.
98 changes: 96 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ https://packagist.org/packages/discoverydesign/filament-locksmith

## Examples

### Example
### Basic Example
```php
<?php

Expand All @@ -46,7 +46,6 @@ class UserResource extends Resource
PasswordInput::make('password')
->required()
->generatable()
->editable(false)
->friendly()
->copyable()
->revealable(),
Expand All @@ -59,6 +58,28 @@ class UserResource extends Resource
}
```

### Advanced Example
```php
PasswordInput::make('password')
->required()
->advanced()
->copyable()
->revealable(),
```

### Custom Generators Example
```php
PasswordInput::make('password')
->required()
->advanced()
->setGenerators([
new DiscoveryDesign\FilamentLocksmith\Generators\RandomGenerator,
new DiscoveryDesign\FilamentLocksmith\Generators\MemorableGenerator
])
->copyable()
->revealable(),
```


## Docs

Expand Down Expand Up @@ -115,6 +136,79 @@ class UserResource extends Resource
#### Arguments
`func` - (optional, closure | bool) If the password should be revealable. If a closure is passed, this should return a bool.

### `->advanced()`

#### Description
`advanced` will enable advanced mode which allows user configuration of their password, along with a selection of different password types.

#### Arguments
`state` - (optional, bool) If the password should be hashed.

### `->addGenerator($generator)`

#### Description
`addGenerator` can be used to add a generator to the advance mode password generator. You should pass in an instance of a class that extends `DiscoveryDesign\FilamentLocksmith\Generators\BaseGenerator`.

#### Arguments
`generator` - (class, extends BaseGenerator) The generator to add.

### `->setGenerators($generators)`

#### Description
`setGenerators` will override all existing generators assigned to this PasswordInput and instead use the ones passed in. You should pass in an array of instances of a class that extends `DiscoveryDesign\FilamentLocksmith\Generators\BaseGenerator`.

#### Arguments
`generators` - (array) The generators to set.

### `->getGenerators()`

#### Description
`getGenerators` can be used to get an array of all the current generators.


## Creating a generator

If you want to create a generator, you should first start by creating a new class that extends `DiscoveryDesign\FilamentLocksmith\Generators\BaseGenerator`.

Inside your `__construct` you should include any options that you want to use to generate the password. It is encouraged to use a unique name for your form inputs.

The `generate` function should return a string that is the password.

```php
<?php

namespace App\Filament\Locksmith\Generators;

use Filament\Forms;
use DiscoveryDesign\FilamentLocksmith\Generators\BaseGenerator;
use Illuminate\Support\Str;

class MyCustomGenerator extends BaseGenerator
{
public string $name = 'My Custom Generator';

public function __construct()
{

$this->setOptions([
Forms\Components\TextInput::make('mygenerator_length')
->label('length')
->default(20)
->type('number')
->required()
]);
}

public function generate($get)
{
$length = $get('mygenerator_length');

return Str::password($length);
}
}
```

You can then add this generator to your password input with `->addGenerator(new MyCustomGenerator)`.

## Author

Expand Down
21 changes: 20 additions & 1 deletion resources/lang/en/locksmith.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,24 @@

return [
'copied' => 'Password copied',
'generate' => 'Generate Password'
'generate' => 'Generate Password',
'use' => 'Use',

'memorable' => [
'title' => 'Memorable Password',
'words' => 'Words',
'separator' => 'Separator',
],

'pin' => [
'title' => 'Pin Code',
'numbers' => 'Numbers',
],

'random' => [
'title' => 'Random Password',
'length' => 'Length',
'numbers' => 'Numbers',
'symbols' => 'Symbols',
],
];
147 changes: 129 additions & 18 deletions src/Forms/Components/PasswordInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,50 @@

namespace DiscoveryDesign\FilamentLocksmith\Forms\Components;

use Filament\Forms\Components\TextInput;
use DiscoveryDesign\FilamentLocksmith\Generators\MemorableGenerator;
use DiscoveryDesign\FilamentLocksmith\Generators\PinGenerator;
use DiscoveryDesign\FilamentLocksmith\Generators\RandomGenerator;
use Filament\Actions\StaticAction;
use Filament\Forms;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Component;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Get;
use Filament\Forms\Set;
use Filament\Forms\Components\Component;
use Filament\Support\Enums\MaxWidth;
use GenPhrase\Password;

class PasswordInput extends TextInput
{
public bool $isCopyable = false;

public bool $isEditable = false;

public bool $isGeneratable = true;

public bool $isHashed = true;

public bool $isAdvanced = false;

public array $generators = [];

public ?\Closure $generatorFn = null;

protected function setUp(): void
{
$this->password();

$this->generators[] = new RandomGenerator;
$this->generators[] = new MemorableGenerator;
$this->generators[] = new PinGenerator;
}

public function getExtraInputAttributes(): array
{
$extraAttributes = parent::getExtraInputAttributes();

// We do it this way so it doesn't visually mess with the input container
if (!$this->isEditable) {
if (! $this->isEditable) {
$extraAttributes['disabled'] = '';
$this->placeholder(__('filament-locksmith::locksmith.generate'));
}
Expand All @@ -45,7 +62,8 @@ public function copyable($state = true)
->icon('heroicon-m-clipboard')
->color('gray')
->alpineClickHandler(function (Component $component) {
$tooltipText = __("filament-locksmith::locksmith.copied");
$tooltipText = __('filament-locksmith::locksmith.copied');

return <<<JS
window.navigator.clipboard.writeText(\$wire.get('{$component->getStatePath()}'));
Expand All @@ -71,34 +89,127 @@ public function hashed($state = true)
$this->isHashed = $state;

$this->before(function (Set $set, Get $get, Component $component) {
if (!$this->isHashed) return;
if (! $this->isHashed) {
return;
}

$set($component->getName(), \Hash::make($get($component->getName())));
});

return $this;
}

public function advanced($state = true)
{
$this->isAdvanced = $state;
$this->generatable();

return $this;
}

public function addGenerator($generator)
{
$this->generators[] = $generator;

return $this;
}

public function setGenerators(array $generators)
{
$this->generators = $generators;

return $this;
}

public function getGenerators(): array
{
return $this->generators;
}

public function generatable()
{
$this->isGeneratable = true;

$this->suffixAction(
Action::make('generatePassword')
->icon('heroicon-o-arrow-path')
->color('gray')
->action(function(Set $set, Component $component) {
$password = $this->createPassword();

$set($component->getName(), $password);
})
->visible($this->isGeneratable)
);
if ($this->isAdvanced) {
$this->suffixAction(
Action::make('generatePassword')
->icon('heroicon-o-arrow-path')
->color('gray')
->label(__('filament-locksmith::locksmith.generate'))
->form(function () {
$options = [];
$fields = [];
foreach ($this->getGenerators() as $generator) {
$options[$generator->name] = $generator->name;

foreach ($generator->getOptions() as $field) {
$fields[] = $field
->visible(fn ($get) => $get('type') === $generator->name)
->live(debounce: 500)
->afterStateUpdated(function (?string $state, ?string $old, $get, $set) use ($generator) {
$set('password', $generator->generate($get));
});
}
}

return [
Forms\Components\TextInput::make('password')
->label('')
->extraAttributes(['disabled' => ''])
->suffixAction(
Action::make('regenerate')
->icon('heroicon-o-arrow-path')
->color('gray')
->action(function (?string $state, $get, $set) {
$generators = collect($this->getGenerators());
$generator = $generators->first(fn ($generator) => $generator->name === $get('type'));

if ($generator) {
$set('password', $generator->generate($get));
}
})
),
Forms\Components\Select::make('type')
->afterStateUpdated(function (?string $state, $get, $set) {
$generators = collect($this->getGenerators());
$generator = $generators->first(fn ($generator) => $generator->name === $state);

if ($generator) {
$set('password', $generator->generate($get));
}
})
->options($options)
->live(),
...$fields,
];
})
->action(function($data, Set $set, Component $component) {
$set($component->getName(), $data['password']);
})
->modalSubmitAction(fn (StaticAction $action) => $action->label(__('filament-locksmith::locksmith.use')))
->modalWidth(MaxWidth::Medium)
->visible($this->isGeneratable)
);

return $this;
} else {
$this->suffixAction(
Action::make('generatePassword')
->icon('heroicon-o-arrow-path')
->color('gray')
->action(function(Set $set, Component $component) {
$password = $this->createPassword();

$set($component->getName(), $password);
})
->visible($this->isGeneratable)
);
}

return $this;
}

public function generator(\Closure|null $generator = null)
public function generator(?\Closure $generator = null)
{
$this->generatorFn = $generator;

Expand All @@ -109,7 +220,7 @@ public function generator(\Closure|null $generator = null)
public function friendly()
{
$this->generator(function () {
$gen = new Password();
$gen = new Password;
$gen->disableSeparators(true);
$gen->disableWordModifier(true);

Expand Down
26 changes: 26 additions & 0 deletions src/Generators/BaseGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace DiscoveryDesign\FilamentLocksmith\Generators;

class BaseGenerator
{
public string $name = 'Base';
private array $options = [];

public function getOptions(): array
{
return $this->options;
}

public function setOptions(array $options)
{
$this->options = $options;

return $this;
}

public function generate($get)
{
return 'password';
}
}
Loading

0 comments on commit b849098

Please sign in to comment.