Skip to content

Commit

Permalink
Merge pull request #414 from anodyne/global-search
Browse files Browse the repository at this point in the history
Add global search
  • Loading branch information
agentphoenix authored Oct 9, 2024
2 parents 9692521 + aa7f7e8 commit 3eab7af
Show file tree
Hide file tree
Showing 36 changed files with 1,235 additions and 241 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
/public/storage
/public/mix-manifest.json
/storage/*.key
/storage/*.index
/vendor
/.idea
/.vscode
Expand Down
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"laravel/framework": "^11.0",
"laravel/pulse": "^1.2",
"laravel/sanctum": "^4.0",
"laravel/scout": "^10.11",
"laravel/tinker": "^2.7",
"livewire/livewire": "^3.4",
"lorisleiva/laravel-actions": "^2.1",
Expand All @@ -50,6 +51,7 @@
"symfony/http-client": "^7.0",
"symfony/mailgun-mailer": "^7.0",
"symfony/postmark-mailer": "^7.0",
"teamtnt/laravel-scout-tntsearch-driver": "^14.0",
"wire-elements/modal": "^2.0",
"wire-elements/spotlight": "^2.0"
},
Expand Down
591 changes: 443 additions & 148 deletions composer.lock

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions nova/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,8 @@ SCOUT_DRIVER=tntsearch

TNTSEARCH_FUZZINESS=true
TNTSEARCH_BOOLEAN=false
TNTSEARCH_MAX_DOCS=500

LARATRUST_ENABLE_CACHE=true

TELESCOPE_ENABLED=false

CLOCKWORK_ENABLE=false
1 change: 1 addition & 0 deletions nova/bootstrap/providers.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
Nova\PublicSite\Providers\PublicSiteServiceProvider::class,
Nova\Ranks\Providers\RankServiceProvider::class,
Nova\Roles\Providers\RoleServiceProvider::class,
Nova\Search\Providers\SearchServiceProvider::class,
Nova\Settings\Providers\SettingsServiceProvider::class,
Nova\Stories\Providers\PostServiceProvider::class,
Nova\Stories\Providers\PostTypeServiceProvider::class,
Expand Down
218 changes: 218 additions & 0 deletions nova/config/scout.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
<?php

declare(strict_types=1);

return [

/*
|--------------------------------------------------------------------------
| Default Search Engine
|--------------------------------------------------------------------------
|
| This option controls the default search connection that gets used while
| using Laravel Scout. This connection is used when syncing all models
| to the search service. You should adjust this based on your needs.
|
| Supported: "algolia", "meilisearch", "typesense",
| "database", "collection", "null"
|
*/

'driver' => env('SCOUT_DRIVER', 'tntsearch'),

/*
|--------------------------------------------------------------------------
| Index Prefix
|--------------------------------------------------------------------------
|
| Here you may specify a prefix that will be applied to all search index
| names used by Scout. This prefix may be useful if you have multiple
| "tenants" or applications sharing the same search infrastructure.
|
*/

'prefix' => env('SCOUT_PREFIX', ''),

/*
|--------------------------------------------------------------------------
| Queue Data Syncing
|--------------------------------------------------------------------------
|
| This option allows you to control if the operations that sync your data
| with your search engines are queued. When this is set to "true" then
| all automatic data syncing will get queued for better performance.
|
*/

'queue' => env('SCOUT_QUEUE', false),

/*
|--------------------------------------------------------------------------
| Database Transactions
|--------------------------------------------------------------------------
|
| This configuration option determines if your data will only be synced
| with your search indexes after every open database transaction has
| been committed, thus preventing any discarded data from syncing.
|
*/

'after_commit' => true,

/*
|--------------------------------------------------------------------------
| Chunk Sizes
|--------------------------------------------------------------------------
|
| These options allow you to control the maximum chunk size when you are
| mass importing data into the search engine. This allows you to fine
| tune each of these chunk sizes based on the power of the servers.
|
*/

'chunk' => [
'searchable' => 500,
'unsearchable' => 500,
],

/*
|--------------------------------------------------------------------------
| Soft Deletes
|--------------------------------------------------------------------------
|
| This option allows to control whether to keep soft deleted records in
| the search indexes. Maintaining soft deleted records can be useful
| if your application still needs to search for the records later.
|
*/

'soft_delete' => false,

/*
|--------------------------------------------------------------------------
| Identify User
|--------------------------------------------------------------------------
|
| This option allows you to control whether to notify the search engine
| of the user performing the search. This is sometimes useful if the
| engine supports any analytics based on this application's users.
|
| Supported engines: "algolia"
|
*/

'identify' => env('SCOUT_IDENTIFY', false),

/*
|--------------------------------------------------------------------------
| Algolia Configuration
|--------------------------------------------------------------------------
|
| Here you may configure your Algolia settings. Algolia is a cloud hosted
| search engine which works great with Scout out of the box. Just plug
| in your application ID and admin API key to get started searching.
|
*/

'algolia' => [
'id' => env('ALGOLIA_APP_ID', ''),
'secret' => env('ALGOLIA_SECRET', ''),
],

/*
|--------------------------------------------------------------------------
| Meilisearch Configuration
|--------------------------------------------------------------------------
|
| Here you may configure your Meilisearch settings. Meilisearch is an open
| source search engine with minimal configuration. Below, you can state
| the host and key information for your own Meilisearch installation.
|
| See: https://www.meilisearch.com/docs/learn/configuration/instance_options#all-instance-options
|
*/

'meilisearch' => [
'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'),
'key' => env('MEILISEARCH_KEY'),
'index-settings' => [
// 'users' => [
// 'filterableAttributes'=> ['id', 'name', 'email'],
// ],
],
],

/*
|--------------------------------------------------------------------------
| Typesense Configuration
|--------------------------------------------------------------------------
|
| Here you may configure your Typesense settings. Typesense is an open
| source search engine using minimal configuration. Below, you will
| state the host, key, and schema configuration for the instance.
|
*/

'typesense' => [
'client-settings' => [
'api_key' => env('TYPESENSE_API_KEY', 'xyz'),
'nodes' => [
[
'host' => env('TYPESENSE_HOST', 'localhost'),
'port' => env('TYPESENSE_PORT', '8108'),
'path' => env('TYPESENSE_PATH', ''),
'protocol' => env('TYPESENSE_PROTOCOL', 'http'),
],
],
'nearest_node' => [
'host' => env('TYPESENSE_HOST', 'localhost'),
'port' => env('TYPESENSE_PORT', '8108'),
'path' => env('TYPESENSE_PATH', ''),
'protocol' => env('TYPESENSE_PROTOCOL', 'http'),
],
'connection_timeout_seconds' => env('TYPESENSE_CONNECTION_TIMEOUT_SECONDS', 2),
'healthcheck_interval_seconds' => env('TYPESENSE_HEALTHCHECK_INTERVAL_SECONDS', 30),
'num_retries' => env('TYPESENSE_NUM_RETRIES', 3),
'retry_interval_seconds' => env('TYPESENSE_RETRY_INTERVAL_SECONDS', 1),
],
// 'max_total_results' => env('TYPESENSE_MAX_TOTAL_RESULTS', 1000),
'model-settings' => [
// User::class => [
// 'collection-schema' => [
// 'fields' => [
// [
// 'name' => 'id',
// 'type' => 'string',
// ],
// [
// 'name' => 'name',
// 'type' => 'string',
// ],
// [
// 'name' => 'created_at',
// 'type' => 'int64',
// ],
// ],
// 'default_sorting_field' => 'created_at',
// ],
// 'search-parameters' => [
// 'query_by' => 'name'
// ],
// ],
],
],

'tntsearch' => [
'storage' => storage_path(),
'fuzziness' => env('TNTSEARCH_FUZZINESS', true),
'fuzzy' => [
'prefix_length' => 2,
'max_expansions' => 50,
'distance' => 2,
],
'asYouType' => false,
'searchBoolean' => env('TNTSEARCH_BOOLEAN', false),
'maxDocs' => env('TNTSEARCH_MAX_DOCS', 500),
],

];
26 changes: 22 additions & 4 deletions nova/foundation/Environment/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,21 @@ class Database
public function __construct()
{
try {
$this->driver = DB::connection()->getPdo()->getAttribute(PDO::ATTR_DRIVER_NAME);
$this->version = DB::connection()->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION);
$pdo = DB::connection()->getPdo();

$this->version = $pdo->getAttribute(PDO::ATTR_SERVER_VERSION);

if (str($this->version)->contains('mariadb', ignoreCase: true)) {
$this->driver = 'mariadb';
$this->hasMysql = false;
} else {
$this->driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
$this->hasMysql = in_array('mysql', PDO::getAvailableDrivers());
}
} catch (Throwable $th) {
//throw $th;
$this->hasMysql = in_array('mysql', PDO::getAvailableDrivers());
}

$this->hasMysql = in_array('mysql', PDO::getAvailableDrivers());
}

public function driverName(): string
Expand All @@ -40,6 +48,16 @@ public function driverName(): string
};
}

public function versionNumber(): string
{
return str($this->version)->before('-')->toString();
}

public function platform(): string
{
return sprintf('%s %s', $this->driverName(), $this->versionNumber());
}

public function fails(): bool
{
return ! $this->passes();
Expand Down
3 changes: 3 additions & 0 deletions nova/resources/views/components/navbar/item.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
// Active
'active:bg-gray-950/5 data-[slot=icon]:*:active:text-gray-950',
// Focus
'focus:outline-none',
// Dark mode
'dark:text-white dark:data-[slot=icon]:*:text-gray-400',
'dark:hover:bg-white/5 dark:data-[slot=icon]:*:hover:text-white',
Expand Down
3 changes: 3 additions & 0 deletions nova/resources/views/components/sidebar/item.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
// Active
'active:bg-gray-950/5 data-[slot=icon]:*:active:text-gray-950',
// Focus
'focus:outline-none',
// Current
'data-[current]:bg-gray-950/5 data-[slot=icon]:*:data-[current]:text-gray-950',
'dark:data-[current]:bg-white/5 dark:data-[slot=icon]:*:data-[current]:text-white',
Expand Down
5 changes: 3 additions & 2 deletions nova/resources/views/layouts/admin.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class="block h-8 w-auto"
</x-sidebar.section>

<x-sidebar.section>
<x-sidebar.item href="#">
<x-sidebar.item type="button" x-on:click="$dispatch('toggle-search')">
<x-icon name="search"></x-icon>
<x-sidebar.label>Search</x-sidebar.label>
</x-sidebar.item>
Expand Down Expand Up @@ -544,7 +544,7 @@ class="text-gray-400 dark:text-gray-600"
<x-navbar.spacer></x-navbar.spacer>

<x-navbar.section>
<x-navbar.item>
<x-navbar.item type="button" x-on:click="$dispatch('toggle-search')">
<x-icon name="search"></x-icon>
</x-navbar.item>

Expand Down Expand Up @@ -638,6 +638,7 @@ class="relative grow p-6 lg:rounded-lg lg:bg-white lg:p-10 lg:shadow-sm lg:ring-
@livewire('notifications')
@livewire('scribble.renderer')
@livewire('scribble.modals')
@livewire('global-search')

{{ NovaView::renderHook('admin::scripts.before') }}

Expand Down
10 changes: 10 additions & 0 deletions nova/resources/views/livewire/search/announcements.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<li class="group relative cursor-default select-none px-4 py-2 hover:bg-primary-500" role="option" tabindex="-1">
<a href="{{ route('admin.announcements.show', $result) }}" class="absolute inset-0"></a>

<div class="space-y-1">
<h3 class="font-semibold text-gray-900 group-hover:text-white">{{ $result->title }}</h3>
<p class="text-xs/5 text-gray-600 group-hover:text-primary-200">
{{ str($result->content)->stripTags()->words(50) }}
</p>
</div>
</li>
10 changes: 10 additions & 0 deletions nova/resources/views/livewire/search/characters.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<li class="group relative cursor-default select-none px-4 py-2 hover:bg-primary-500" role="option" tabindex="-1">
<a href="{{ route('admin.characters.show', $result) }}" class="absolute inset-0"></a>

<div class="space-y-1">
<h3 class="font-semibold text-gray-900 group-hover:text-white">{{ $result->display_name }}</h3>
<p class="text-xs/5 text-gray-600 group-hover:text-primary-200">
{{ $result->positions->implode('name', ' & ') }}
</p>
</div>
</li>
Loading

0 comments on commit 3eab7af

Please sign in to comment.