Compare commits

...

147 Commits

Author SHA1 Message Date
snipe
2d3d1724bb Updated some packages
Signed-off-by: snipe <snipe@snipe.net>
2025-07-28 07:35:56 +01:00
snipe
257d58c236 Moved privacy policy link in settings
Signed-off-by: snipe <snipe@snipe.net>
2025-07-28 03:30:10 +01:00
snipe
015f3d936c Merge pull request #17459 from grokability/#17441-add-status-to-id
Fixed #17441 - hardware listings "remembered" page numbers between statuses
2025-07-24 15:54:33 +01:00
snipe
18d2a0ffd7 Fixed #17441 - added status to table IDs
Signed-off-by: snipe <snipe@snipe.net>
2025-07-24 15:47:26 +01:00
snipe
24afde0e46 Updated hash and minor version
Signed-off-by: snipe <snipe@snipe.net>
2025-07-24 15:35:33 +01:00
snipe
8499faa55a Fixed #17458 - use item_id instead of target_id for user history
Signed-off-by: snipe <snipe@snipe.net>
2025-07-24 15:29:36 +01:00
snipe
c60dd809b8 Removed debugging
Signed-off-by: snipe <snipe@snipe.net>
2025-07-24 13:06:57 +01:00
snipe
297b8e33f2 Merge pull request #17436 from Godmartinz/fix-acceptance-markdown
Fixed #17394 - Changes the acceptance letter salutation to target
2025-07-23 22:55:05 +01:00
Godfrey M
b670b2014c accidentally removed a line 2025-07-23 09:56:19 -07:00
Godfrey M
440e969f52 remove unnecessary spacing 2025-07-23 09:47:03 -07:00
snipe
14b79f2f1c Fixed typo in id name
Signed-off-by: snipe <snipe@snipe.net>
2025-07-23 17:00:09 +01:00
snipe
00cf49a61f Bumped version
Signed-off-by: snipe <snipe@snipe.net>
2025-07-23 16:10:47 +01:00
snipe
4f534e0e84 Bumped version/hash
Signed-off-by: snipe <snipe@snipe.net>
2025-07-23 16:02:51 +01:00
snipe
83a19fbbbf Merge pull request #17454 from uberbrady/de_flake_action_log_tests
Enforce order by ID for actionlog tests
2025-07-23 15:06:09 +01:00
snipe
610cb884fc Merge pull request #17452 from uberbrady/de_flake_tls_cert_file_test
This test was flaky, probably due to the PHP statcache.
2025-07-23 15:00:59 +01:00
snipe
ba92cec62b Merge pull request #17453 from grokability/#17316-checkbox-format-on-checkin-checkout
Fixed #17316 - handle checkboxes correctly in checkin/checkout
2025-07-23 14:56:24 +01:00
Brady Wetherington
d92e961a52 enforce order by ID for actionlog tests 2025-07-23 14:55:42 +01:00
snipe
b13e74756a Fixed #17316 - handle checkboxes correctly in checkin/checkout
Signed-off-by: snipe <snipe@snipe.net>
2025-07-23 14:51:34 +01:00
Brady Wetherington
4ef3072766 This test was flaky, probably due to the PHP statcache. 2025-07-23 14:15:52 +01:00
snipe
e96e2461d3 Merge pull request #17450 from grokability/copy-decrypted-custom-fields-to-clipboard
Fixed #17447 - decrypt before copying to clipboard
2025-07-23 12:41:02 +01:00
snipe
7a2e2be169 Fixed #17447 - decrypt before copying to clipboard
Signed-off-by: snipe <snipe@snipe.net>
2025-07-23 12:39:54 +01:00
snipe
8d2a5a7e4a Added location and defaultLoc to searchable relations in audit log
Signed-off-by: snipe <snipe@snipe.net>
2025-07-23 12:28:23 +01:00
snipe
b7b0e4fab5 Merge pull request #17447 from Godmartinz/make-custom-fields-copyable
Adds #17133 Copy ability to all Custom fields
2025-07-23 12:11:47 +01:00
Godfrey M
a624a79b30 add terenary 2025-07-22 16:36:19 -07:00
Godfrey M
313135da6f Merge branch 'develop' into make-custom-fields-copyable 2025-07-22 16:26:57 -07:00
Godfrey M
58d27d1247 move copy button to front 2025-07-22 16:17:52 -07:00
snipe
edfb28168f Merge pull request #17446 from marcusmoore/snipe-it-17445-move-jobtitle-under-assigned_to-in-assettransformer
Fixed #17445 - move jobtitle under assigned_to in AssetTransformer
2025-07-22 20:27:01 +01:00
Godfrey M
8d0e03bb06 fix copy target 2025-07-22 11:57:46 -07:00
Marcus Moore
855f6f77cf Re-add sorting 2025-07-22 11:49:32 -07:00
Godfrey M
6236cffe14 adds copy links for filled custom fields 2025-07-22 11:49:11 -07:00
Marcus Moore
322a71fbb8 Add jobtitleFormatter 2025-07-22 11:37:34 -07:00
Marcus Moore
4d9f8476f3 Update field key in AssetPresenter 2025-07-22 11:07:58 -07:00
Marcus Moore
d7d93b14b2 Move jobtitle under assigned_to 2025-07-22 11:02:26 -07:00
snipe
d1af3ece6e One more tweak to login checkbox
Signed-off-by: snipe <snipe@snipe.net>
2025-07-22 15:25:09 +01:00
snipe
8153b20984 Check for demo mode on UI for able to login
Signed-off-by: snipe <snipe@snipe.net>
2025-07-22 15:18:34 +01:00
snipe
a50f605c29 Merge pull request #17443 from grokability/added-not-allowed-cursor
Adds disabled cursor on uneditable fields in user create/edit
2025-07-22 15:13:14 +01:00
snipe
daf23edd10 Adds disabled cursor on uneditable fields in user create/edit
Signed-off-by: snipe <snipe@snipe.net>
2025-07-22 15:10:27 +01:00
snipe
2eaaeb8259 Merge pull request #17423 from grokability/tighter-permissions-on-non-admins
Tighter permissions on non-admins and demo modes
2025-07-22 14:32:50 +01:00
snipe
a02c62d62c Fixed tests
Signed-off-by: snipe <snipe@snipe.net>
2025-07-22 14:12:51 +01:00
snipe
e0232a8e84 Renamed gate
Signed-off-by: snipe <snipe@snipe.net>
2025-07-22 14:02:18 +01:00
snipe
6ea5693b2f Updated comment, removed log error statement
Signed-off-by: snipe <snipe@snipe.net>
2025-07-22 13:59:58 +01:00
snipe
030c2114d1 Merge pull request #17442 from grokability/user-api-eula-fix
Fixed FD-49886 - Optimize user queries
2025-07-22 13:39:36 +01:00
snipe
2cb18e3668 Remove fields from query - eulas was querying actionlogs
Signed-off-by: snipe <snipe@snipe.net>
2025-07-22 13:25:41 +01:00
snipe
cd9f8be563 Optimize for when we already have the counts
Signed-off-by: snipe <snipe@snipe.net>
2025-07-22 13:25:16 +01:00
snipe
a02792e9bf Merge pull request #17300 from uberbrady/add_actionlog_tests
Fixed #17071 - Adding various tests of the contents of ActionLogs for lots of events
2025-07-22 10:51:30 +01:00
snipe
41bb422244 Merge pull request #17439 from marcusmoore/component-file-test-fix
Attempt to fix flaky file upload tests pt2
2025-07-21 23:16:03 +01:00
Marcus Moore
54663d3342 Pass order to api in test 2025-07-21 15:10:35 -07:00
snipe
2529f7369f Merge pull request #17438 from grokability/file-upload-tests-fix
Attempt to fix flaky file upload tests
2025-07-21 22:48:38 +01:00
snipe
909c33dccf Fixed order location
Signed-off-by: snipe <snipe@snipe.net>
2025-07-21 22:45:17 +01:00
snipe
1adc9f1aa9 Attempt to fix flaky tests
Signed-off-by: snipe <snipe@snipe.net>
2025-07-21 22:18:15 +01:00
Godfrey M
49da9e58fd changed markdown to point to assignedto name 2025-07-21 12:00:00 -07:00
snipe
f3e288d078 Updated language strings
Signed-off-by: snipe <snipe@snipe.net>
2025-07-21 17:46:49 +01:00
snipe
988000952e Fixed RB-3997
Signed-off-by: snipe <snipe@snipe.net>
2025-07-21 13:48:01 +01:00
snipe
6537f3794b Merge pull request #17292 from Godmartinz/fail_with_inputs
FIXED: #17194 Return to bulk edit with errors and inputs
2025-07-21 12:03:52 +01:00
snipe
d31718ba8a Merge pull request #17389 from grokability/use-transformer-for-api-asset-model-response
Use standard model transformer for asset model API response
2025-07-21 11:52:25 +01:00
snipe
9dd4bc5fa8 Merge pull request #17391 from Godmartinz/add-components-notifications
FIXED: #13844 Adds Webhook and Mail Notifications for Components
2025-07-21 11:51:30 +01:00
snipe
df5f1bd522 Merge pull request #17434 from grokability/dependabot/github_actions/develop/codacy/codacy-analysis-cli-action-4.4.7
Bump codacy/codacy-analysis-cli-action from 4.4.5 to 4.4.7
2025-07-21 11:45:04 +01:00
dependabot[bot]
ddffab9169 Bump codacy/codacy-analysis-cli-action from 4.4.5 to 4.4.7
Bumps [codacy/codacy-analysis-cli-action](https://github.com/codacy/codacy-analysis-cli-action) from 4.4.5 to 4.4.7.
- [Release notes](https://github.com/codacy/codacy-analysis-cli-action/releases)
- [Commits](https://github.com/codacy/codacy-analysis-cli-action/compare/v4.4.5...v4.4.7)

---
updated-dependencies:
- dependency-name: codacy/codacy-analysis-cli-action
  dependency-version: 4.4.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 09:26:25 +00:00
snipe
0c34073582 Namespace fix for presenter
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 17:17:04 +01:00
snipe
14674947cb Fixed test namespace
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 17:15:51 +01:00
snipe
51bccdbd66 Merge pull request #17424 from marcusmoore/chore/livewire-ugprade
Bumped livewire to v3.6.4
2025-07-18 17:12:14 +01:00
snipe
f0fbb3cf36 Uncomment permissions test
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 16:31:31 +01:00
Brady Wetherington
0cc47aacbe Got tests to pass by making them match our current reality, rather than wishes 2025-07-18 16:14:32 +01:00
snipe
fafd592290 Wrap groups and activated into the other canEditAuthFields gate
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 16:03:43 +01:00
snipe
40e754b8c3 Additional criteria for the canEditAuthFields gate
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 16:03:22 +01:00
snipe
483301db7a Changed some of the gating logic for demo mode. Sigh.
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 16:02:59 +01:00
snipe
218606fbd6 Updated view permissions
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 16:02:41 +01:00
snipe
c601b8e62c Updated test
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 16:02:11 +01:00
snipe
2bd68ec991 Uncommented importer gate
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 13:17:25 +01:00
snipe
66842648ed Removed debugging
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 13:17:10 +01:00
snipe
ce54b9a7b5 Removed duplicate alert
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 13:16:59 +01:00
Brady Wetherington
8a5f6d2a5d Refactor base test into Trait, clean test output for easier comparison 2025-07-18 13:16:35 +01:00
snipe
1d86a5476f Updated language
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 12:45:43 +01:00
snipe
ca4d3f6bce Changed gate name, removed debugging
Signed-off-by: snipe <snipe@snipe.net>
2025-07-18 12:45:32 +01:00
Godfrey M
2812f2ce92 remove log 2025-07-17 15:04:42 -07:00
Godfrey M
5c623db798 fix redirect 2025-07-17 14:57:00 -07:00
Marcus Moore
edaf005fe1 Bump livewire to v3.6.4 2025-07-17 14:15:10 -07:00
snipe
4f6e407247 More consistent language degarding the demo
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 21:13:13 +01:00
snipe
e30881239c A few more clean ups for demo mode
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 21:08:50 +01:00
snipe
bbde2cc4b2 Use history blade component
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 21:04:11 +01:00
snipe
16d18c79d7 Fixed email editable field
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 21:03:20 +01:00
snipe
a0d2cb8a03 Clearer (if longer) gate name
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 20:47:20 +01:00
snipe
1bb5dc7e69 Added one more test
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 20:40:01 +01:00
Brady Wetherington
58759acfe4 Think I hit _all_ of the tests we need to mess with here 2025-07-17 20:15:01 +01:00
snipe
0cd5136052 Added translations
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 20:12:52 +01:00
snipe
b3c6fe5369 Use both new gates in user edit
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 20:12:46 +01:00
snipe
599718f84e Use new gates in controllers
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 20:12:32 +01:00
snipe
d9a5452388 Defined new gates
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 20:12:10 +01:00
snipe
0fe49e04bf Attempt to use a gate here?
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 20:09:27 +01:00
snipe
a98d3fb4dc Check for the format of the permissions (string, object, array)
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 20:09:17 +01:00
Godfrey M
8c670d1832 clean up 2025-07-17 12:08:49 -07:00
snipe
c232f490bc Show user log
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 20:08:40 +01:00
snipe
c7280953dd Added/updated tests
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 20:08:32 +01:00
Godfrey M
8f4c606c64 remove var dumps 2025-07-17 12:04:33 -07:00
Godfrey M
6740afab42 radio buttons values return correctly 2025-07-17 11:59:09 -07:00
Godfrey M
5df22b3e6a checkboxes properly check 2025-07-17 11:56:52 -07:00
snipe
3d9d18a0d5 Fixed weird CSS quirk
Signed-off-by: snipe <snipe@snipe.net>
2025-07-17 19:22:23 +01:00
Godfrey M
fc469707a3 clean up 2025-07-16 10:51:33 -07:00
snipe
77fdc370c7 Merge pull request #17415 from uberbrady/clean_unaccepted_assets_report
[FD-47386, FD-49095] New Artisan command to clean checkout acceptances
2025-07-16 17:34:49 +01:00
snipe
301290fb6d Send emails on acceptance even if signature is not required
Signed-off-by: snipe <snipe@snipe.net>
2025-07-16 17:02:04 +01:00
snipe
07fffe2f79 Merge pull request #17410 from grokability/remove-password-from-welcome
Remove password from welcome email, prompt for reset instead
2025-07-16 16:54:07 +01:00
snipe
0227a63fa5 Slightly clearer language
Signed-off-by: snipe <snipe@snipe.net>
2025-07-16 16:31:45 +01:00
snipe
27764b863c Updated language
Signed-off-by: snipe <snipe@snipe.net>
2025-07-16 16:25:36 +01:00
snipe
032fd75f9e Added default invite password token timeout
Signed-off-by: snipe <snipe@snipe.net>
2025-07-16 16:23:51 +01:00
snipe
0bf4f861f3 Nicer debugging
Signed-off-by: snipe <snipe@snipe.net>
2025-07-16 16:23:25 +01:00
snipe
fd8f90cb52 Added new password broker for longer toekn lifetime
Signed-off-by: snipe <snipe@snipe.net>
2025-07-16 16:23:11 +01:00
snipe
b6c6b025c8 Added expiry language
Signed-off-by: snipe <snipe@snipe.net>
2025-07-16 16:20:26 +01:00
snipe
3d89e98d1f Small tweaks to welcome email blade
Signed-off-by: snipe <snipe@snipe.net>
2025-07-16 16:20:15 +01:00
Brady Wetherington
7c5110ed5d Add more action logs tests everywhere I can think of it. 2025-07-16 16:20:06 +01:00
Brady Wetherington
0a474f48ad WIP: Adding various tests of the contents of ActionLogs for lots of events 2025-07-16 16:20:06 +01:00
Brady Wetherington
c409bfd5be New Artisan command to clean checkout acceptances and a migration that runs it 2025-07-16 16:06:23 +01:00
snipe
39d5d5b2e0 Merge branch 'develop' into remove-password-from-welcome 2025-07-16 15:05:13 +01:00
snipe
8a80d9009d Refomatted hidden array
Signed-off-by: snipe <snipe@snipe.net>
2025-07-16 12:24:48 +01:00
Godfrey M
f62b5df566 use ternaries instead of optionals 2025-07-15 15:40:21 -07:00
Godfrey M
214757ab0b fix mailable 2025-07-15 12:04:36 -07:00
Godfrey M
f130186b37 add Component Checkin Mail 2025-07-15 11:56:34 -07:00
Godfrey M
2244eebc3b add Component Checkout Mail 2025-07-15 11:00:39 -07:00
snipe
4176792f2d Translate field
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 16:32:17 +01:00
snipe
1e6cef52c9 Fixed tests
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 15:17:08 +01:00
snipe
a0f4f30a50 Added try/catch
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 15:13:33 +01:00
snipe
4cbf6ac393 Re-add /setup crential email
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:20:13 +01:00
snipe
af7425d8e6 Remove unused variable
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:19:12 +01:00
snipe
3fea909d3f Removed send credentials option from user controller
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:14:10 +01:00
snipe
7c37d40677 Use plaintext in the database so that the password will never be valid
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:13:50 +01:00
snipe
3a97c27350 Removed logging
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:13:29 +01:00
snipe
e0516a52a8 Formatting change
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:12:55 +01:00
snipe
a85ec6efb3 Set token in welcome email constructor
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:12:42 +01:00
snipe
3795c74814 Added string
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:12:26 +01:00
snipe
27954dc6d3 Use password reset token
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:12:18 +01:00
snipe
68c4187a09 Removed email creds option from user create
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:11:15 +01:00
snipe
b9834231f3 Remove email credentials chexkbox
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 14:08:36 +01:00
snipe
2be343ea1c More specific no password
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 13:11:45 +01:00
snipe
109fe1b62c Use no password as temp password
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 13:11:18 +01:00
snipe
63d691a63c Removed noisy log
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 13:10:48 +01:00
snipe
6f57d6b876 Merge pull request #17407 from grokability/fixes-signature-pad-chrome
Fixed display of acceptance button if signature is not required
2025-07-15 10:58:34 +01:00
snipe
e0bad99ea1 Fixes display of acceptannce button if signature is not required
Signed-off-by: snipe <snipe@snipe.net>
2025-07-15 10:55:30 +01:00
snipe
e39eb09cfb Merge pull request #17390 from Godmartinz/unhandled-redirect-error
FIXED redirect option being NULL
2025-07-10 19:41:40 +01:00
Godfrey M
64d397c3f3 add component notification tests 2025-07-10 11:26:10 -07:00
Godfrey M
465ac1d1e1 remove ternary 2025-07-10 08:39:13 -07:00
Godfrey M
18d6becebc populate other_redirect in store method 2025-07-10 08:36:15 -07:00
Godfrey M
3bbd0fdbcd google notifications fires properly 2025-07-09 17:02:51 -07:00
Godfrey M
8214b11da5 MS teams fires properly 2025-07-09 11:44:53 -07:00
Godfrey M
36090bf83e checked in notification fires, updated icon translation usage 2025-07-09 11:35:24 -07:00
Godfrey M
bffb2fe82f checkout notification fires 2025-07-09 11:23:27 -07:00
Godfrey M
500cbf5d92 add component checkout notification, update checkout blade, update listener 2025-07-09 11:12:18 -07:00
Godfrey M
c8b213c190 remove some changes, move error bag 2025-06-24 13:10:32 -07:00
Godfrey M
942de9dce5 got validation to redirect back to form and display 2025-06-24 12:42:07 -07:00
538 changed files with 4905 additions and 3228 deletions

View File

@@ -168,6 +168,7 @@ AWS_DEFAULT_REGION=null
LOGIN_MAX_ATTEMPTS=5 LOGIN_MAX_ATTEMPTS=5
LOGIN_LOCKOUT_DURATION=60 LOGIN_LOCKOUT_DURATION=60
RESET_PASSWORD_LINK_EXPIRES=900 RESET_PASSWORD_LINK_EXPIRES=900
INVITE_PASSWORD_LINK_EXPIRES=1500
# -------------------------------------------- # --------------------------------------------
# OPTIONAL: MISC # OPTIONAL: MISC

View File

@@ -174,6 +174,7 @@ LOGIN_AUTOCOMPLETE=false
RESET_PASSWORD_LINK_EXPIRES=15 RESET_PASSWORD_LINK_EXPIRES=15
PASSWORD_CONFIRM_TIMEOUT=10800 PASSWORD_CONFIRM_TIMEOUT=10800
PASSWORD_RESET_MAX_ATTEMPTS_PER_MIN=50 PASSWORD_RESET_MAX_ATTEMPTS_PER_MIN=50
INVITE_PASSWORD_LINK_EXPIRES=1500
# -------------------------------------------- # --------------------------------------------
# OPTIONAL: MISC # OPTIONAL: MISC

View File

@@ -36,7 +36,7 @@ jobs:
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI - name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@v4.4.5 uses: codacy/codacy-analysis-cli-action@v4.4.7
with: with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations # You can also omit the token and run the tools that support default configurations

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Console\Commands;
use App\Models\CheckoutAcceptance;
use App\Models\LicenseSeat;
use App\Models\User;
use Illuminate\Console\Command;
class CleanIncorrectCheckoutAcceptances extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:clean-checkout-acceptances';
/**
* The console command description.
*
* @var string
*/
protected $description = "Delete checkout acceptances for checkouts to non-users";
/**
* Execute the console command.
*/
public function handle()
{
$deletions = 0;
$skips = 0;
// This walks *every* checkoutacceptance. That's gnarly. But necessary
$this->withProgressBar(CheckoutAcceptance::all(), function ($checkoutAcceptance) use (&$deletions, &$skips) {
$item = $checkoutAcceptance->checkoutable;
$checkout_to_id = $checkoutAcceptance->assigned_to_id;
if(is_null($item)) {
$this->info("'Checkoutable' Item is null, going to next record");
return; //'false' allegedly breaks execution entirely, so 'true' maybe doesn't? hrm. just straight return maybe?
}
if(get_class($item) == LicenseSeat::class) {
$item = $item->license;
}
foreach($item->assetlog()->where('action_type','checkout')->get() as $assetlog) {
if ($assetlog->target_id == $checkout_to_id && $assetlog->target_type != User::class) {
//We have a checkout-to an ID for a non-User, which matches to an ID in the checkout_acceptances table
//now, let's compare the _times_ - are they close?
//I'm picking `created_at` over `action_date` because I'm more interested in when the actionlogs
//were _created_, not when they were alleged to have happened - those created_at times need to be within 'X' seconds of
//each other (currently 5)
if ($assetlog->created_at->diffInSeconds($checkoutAcceptance->created_at, true) <= 5) { //we're allowing for five _ish_ seconds of slop
$deletions++;
$checkoutAcceptance->forceDelete(); // HARD delete this record; it should have never been
return;
} else {
//$this->info("The two records are too far apart");
}
} else {
//$this->info("No match! checkout to id: " . $checkout_to_id." target_id: ".$assetlog->target_id." target_type: ".$assetlog->target_type);
}
}
$skips++;
});
$this->error("Final deletion count: $deletions, and skip count: $skips");
}
}

View File

@@ -133,8 +133,17 @@ class Handler extends ExceptionHandler
// This is traaaaash but it handles models that are not found while using route model binding :( // This is traaaaash but it handles models that are not found while using route model binding :(
// The only alternative is to set that at *each* route, which is crazypants // The only alternative is to set that at *each* route, which is crazypants
if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) { if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
$ids = method_exists($e, 'getIds') ? $e->getIds() : [];
// This gets the MVC model name from the exception and formats in a way that's less fugly if (in_array('bulkedit', $ids, true)) {
$error_array = session()->get('bulk_asset_errors');
return redirect()
->route('hardware.bulkedit')
->withErrors($error_array, 'bulk_asset_errors')
->withInput();
}
// This gets the MVC model name from the exception and formats in a way that's less fugly
$model_name = strtolower(implode(" ", preg_split('/(?=[A-Z])/', last(explode('\\', $e->getModel()))))); $model_name = strtolower(implode(" ", preg_split('/(?=[A-Z])/', last(explode('\\', $e->getModel())))));
$route = str_plural(strtolower(last(explode('\\', $e->getModel())))).'.index'; $route = str_plural(strtolower(last(explode('\\', $e->getModel())))).'.index';

View File

@@ -93,6 +93,7 @@ class UploadedFilesController extends Controller
'id', 'id',
'filename', 'filename',
'action_type', 'action_type',
'action_date',
'note', 'note',
'created_at', 'created_at',
]; ];

View File

@@ -23,6 +23,7 @@ use App\Notifications\CurrentInventory;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -81,7 +82,12 @@ class UsersController extends Controller
'users.autoassign_licenses', 'users.autoassign_licenses',
'users.website', 'users.website',
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy', 'managesUsers', 'managedLocations', 'eulas') ])->with('manager')
->with('groups')
->with('userloc')
->with('company')
->with('department')
->with('createdBy')
->withCount([ ->withCount([
'assets as assets_count' => function(Builder $query) { 'assets as assets_count' => function(Builder $query) {
$query->withoutTrashed(); $query->withoutTrashed();
@@ -475,8 +481,25 @@ class UsersController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager')); return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager'));
} }
if ($request->filled('password')) { // check for permissions related fields and pull them out if the current user cannot edit them
$user->password = bcrypt($request->input('password')); if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
}
if ($request->filled('username')) {
$user->username = $request->input('username');
}
if ($request->filled('email')) {
$user->email = $request->input('email');
}
if ($request->filled('activated')) {
$user->activated = $request->input('activated');
}
} }
// We need to use has() instead of filled() // We need to use has() instead of filled()

View File

@@ -227,7 +227,10 @@ class AssetsController extends Controller
} }
} }
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]); session()->put(['redirect_option' => $request->get('redirect_option'),
'checkout_to_type' => $request->get('checkout_to_type'),
'other_redirect' => 'model' ]);
if ($successes) { if ($successes) {

View File

@@ -161,6 +161,7 @@ class BulkAssetsController extends Controller
$models = $assets->unique('model_id'); $models = $assets->unique('model_id');
$modelNames = []; $modelNames = [];
foreach($models as $model) { foreach($models as $model) {
$modelNames[] = $model->model->name; $modelNames[] = $model->model->name;
} }
@@ -196,7 +197,6 @@ class BulkAssetsController extends Controller
case 'edit': case 'edit':
$this->authorize('update', Asset::class); $this->authorize('update', Asset::class);
return view('hardware/bulk') return view('hardware/bulk')
->with('assets', $asset_ids) ->with('assets', $asset_ids)
->with('statuslabel_list', Helper::statusLabelList()) ->with('statuslabel_list', Helper::statusLabelList())
@@ -224,11 +224,8 @@ class BulkAssetsController extends Controller
$error_array = array(); $error_array = array();
// Get the back url from the session and then destroy the session // Get the back url from the session and then destroy the session
$bulk_back_url = route('hardware.index');
if ($request->session()->has('bulk_back_url')) { $bulk_back_url = $request->session()->pull('bulk_back_url', url()->previous());
$bulk_back_url = $request->session()->pull('bulk_back_url');
}
$custom_field_columns = CustomField::all()->pluck('db_column')->toArray(); $custom_field_columns = CustomField::all()->pluck('db_column')->toArray();
@@ -543,7 +540,13 @@ class BulkAssetsController extends Controller
} // end asset foreach } // end asset foreach
if ($has_errors > 0) { if ($has_errors > 0) {
return redirect($bulk_back_url)->with('bulk_asset_errors', $error_array); session()->put('bulkedit_ids', $request->input('ids'));
session()->put('bulk_asset_errors',$error_array);
return redirect()
->route('hardware.bulkedit')
->with('bulk_asset_errors', $error_array)
->withInput();
} }
return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.update.success')); return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.update.success'));
@@ -735,4 +738,33 @@ class BulkAssetsController extends Controller
} }
return false; return false;
} }
public function bulkEditForm(): View|RedirectResponse
{
$this->authorize('update', Asset::class);
$asset_ids = session()->pull('bulkedit_ids', []);
if (empty($asset_ids)) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.update.no_assets_selected'));
}
$assets = Asset::with('model')->withTrashed()->whereIn('id', $asset_ids)->get();
if ($assets->isEmpty()) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.update.assets_do_not_exist_or_are_invalid'));
}
$models = $assets->unique('model_id');
$modelNames = [];
foreach ($models as $model) {
$modelNames[] = $model->model->name;
}
return view('hardware/bulk')
->with('assets', $asset_ids)
->with('statuslabel_list', Helper::statusLabelList())
->with('models', $models->pluck(['model']))
->with('modelNames', $modelNames);
}
} }

View File

@@ -13,15 +13,8 @@ use App\Models\Company;
use App\Models\Group; use App\Models\Group;
use App\Models\Setting; use App\Models\Setting;
use App\Models\User; use App\Models\User;
use App\Notifications\WelcomeNotification;
use Illuminate\Support\Facades\Auth;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Password; use Illuminate\Support\Facades\Password;
use Illuminate\Support\Facades\Storage;
use Redirect;
use Str;
use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpFoundation\StreamedResponse;
use App\Notifications\CurrentInventory; use App\Notifications\CurrentInventory;
@@ -130,7 +123,7 @@ class UsersController extends Controller
} }
$user->permissions = json_encode($permissions_array); $user->permissions = json_encode($permissions_array);
// we have to invoke the // we have to invoke the form request here to handle image uploads
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar'); app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
session()->put(['redirect_option' => $request->get('redirect_option')]); session()->put(['redirect_option' => $request->get('redirect_option')]);
@@ -142,18 +135,6 @@ class UsersController extends Controller
$user->groups()->sync([]); $user->groups()->sync([]);
} }
if (($request->input('email_user') == 1) && ($request->filled('email'))) {
// Send the credentials through email
$data = [];
$data['email'] = e($request->input('email'));
$data['username'] = e($request->input('username'));
$data['first_name'] = e($request->input('first_name'));
$data['last_name'] = e($request->input('last_name'));
$data['password'] = e($request->input('password'));
$user->notify(new WelcomeNotification($data));
}
return Helper::getRedirectOption($request, $user->id, 'Users') return Helper::getRedirectOption($request, $user->id, 'Users')
->with('success', trans('admin/users/message.success.create')); ->with('success', trans('admin/users/message.success.create'));
} }
@@ -248,20 +229,14 @@ class UsersController extends Controller
} }
} }
// Only save groups if the user is a superuser
if (auth()->user()->isSuperUser()) {
$user->groups()->sync($request->input('groups'));
}
// Update the user fields // Update the user fields
$user->username = trim($request->input('username'));
$user->email = trim($request->input('email'));
$user->first_name = $request->input('first_name'); $user->first_name = $request->input('first_name');
$user->last_name = $request->input('last_name'); $user->last_name = $request->input('last_name');
$user->two_factor_optin = $request->input('two_factor_optin') ?: 0; $user->two_factor_optin = $request->input('two_factor_optin') ?: 0;
$user->locale = $request->input('locale'); $user->locale = $request->input('locale');
$user->employee_num = $request->input('employee_num'); $user->employee_num = $request->input('employee_num');
$user->activated = $request->input('activated', 0);
$user->jobtitle = $request->input('jobtitle', null); $user->jobtitle = $request->input('jobtitle', null);
$user->phone = $request->input('phone'); $user->phone = $request->input('phone');
$user->location_id = $request->input('location_id', null); $user->location_id = $request->input('location_id', null);
@@ -273,8 +248,6 @@ class UsersController extends Controller
$user->city = $request->input('city', null); $user->city = $request->input('city', null);
$user->state = $request->input('state', null); $user->state = $request->input('state', null);
$user->country = $request->input('country', null); $user->country = $request->input('country', null);
// if a user is editing themselves we should always keep activated true
$user->activated = $request->input('activated', $request->user()->is($user) ? 1 : 0);
$user->zip = $request->input('zip', null); $user->zip = $request->input('zip', null);
$user->remote = $request->input('remote', 0); $user->remote = $request->input('remote', 0);
$user->vip = $request->input('vip', 0); $user->vip = $request->input('vip', 0);
@@ -283,30 +256,49 @@ class UsersController extends Controller
$user->end_date = $request->input('end_date', null); $user->end_date = $request->input('end_date', null);
$user->autoassign_licenses = $request->input('autoassign_licenses', 0); $user->autoassign_licenses = $request->input('autoassign_licenses', 0);
// Set this here so that we can overwrite it later if the user is an admin or superadmin
$user->activated = $request->input('activated', auth()->user()->is($user) ? 1 : $user->activated);
// Update the location of any assets checked out to this user // Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class) Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id) ->where('assigned_to', $user->id)
->update(['location_id' => $request->input('location_id', null)]); ->update(['location_id' => $request->input('location_id', null)]);
// Do we want to update the user password? // check for permissions related fields and only set them if the user has permission to edit them
if ($request->filled('password')) { if (auth()->user()->can('canEditAuthFields', $user) && auth()->user()->can('editableOnDemo')) {
$user->password = bcrypt($request->input('password'));
$user->username = trim($request->input('username'));
$user->email = trim($request->input('email'));
$user->activated = $request->input('activated', $request->user()->is($user) ? 1 : 0);
// Do we want to update the user password?
if ($request->filled('password')) {
$user->password = bcrypt($request->input('password'));
}
$permissions_array = $request->input('permission');
// Strip out the superuser permission if the user isn't a superadmin
if (! auth()->user()->isSuperUser()) {
unset($permissions_array['superuser']);
$permissions_array['superuser'] = $orig_superuser;
}
$user->permissions = json_encode($permissions_array);
// Only save groups if the user is a superuser
if (auth()->user()->isSuperUser()) {
$user->groups()->sync($request->input('groups'));
}
} }
// Update the location of any assets checked out to this user // Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class) Asset::where('assigned_type', User::class)
->where('assigned_to', $user->id) ->where('assigned_to', $user->id)
->update(['location_id' => $user->location_id]); ->update(['location_id' => $user->location_id]);
$permissions_array = $request->input('permission');
// Strip out the superuser permission if the user isn't a superadmin
if (! auth()->user()->isSuperUser()) {
unset($permissions_array['superuser']);
$permissions_array['superuser'] = $orig_superuser;
}
$user->permissions = json_encode($permissions_array);
// Handle uploaded avatar // Handle uploaded avatar
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar'); app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');

View File

@@ -80,9 +80,20 @@ class UploadFileRequest extends Request
{ {
$attributes = []; $attributes = [];
if ($this->file) { if (($this->file) && (is_array($this->file))) {
for ($i = 0; $i < count($this->file); $i++) { for ($i = 0; $i < count($this->file); $i++) {
$attributes['file.'.$i] = $this->file[$i]->getClientOriginalName();
try {
if ($this->file[$i]) {
$attributes['file.'.$i] = $this->file[$i]->getClientOriginalName();
}
} catch (\Exception $e) {
$attributes['file.'.$i] = 'Invalid file';
}
} }
} }

View File

@@ -80,7 +80,6 @@ class AssetsTransformer
'qr' => ($setting->qr_code=='1') ? config('app.url').'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'-'.str_slug($asset->id).'.png' : null, 'qr' => ($setting->qr_code=='1') ? config('app.url').'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'-'.str_slug($asset->id).'.png' : null,
'alt_barcode' => ($setting->alt_barcode_enabled=='1') ? config('app.url').'/uploads/barcodes/'.str_slug($setting->alt_barcode).'-'.str_slug($asset->asset_tag).'.png' : null, 'alt_barcode' => ($setting->alt_barcode_enabled=='1') ? config('app.url').'/uploads/barcodes/'.str_slug($setting->alt_barcode).'-'.str_slug($asset->asset_tag).'.png' : null,
'assigned_to' => $this->transformAssignedTo($asset), 'assigned_to' => $this->transformAssignedTo($asset),
'jobtitle' => $asset->assigned ? e($asset->assigned->jobtitle) : null,
'warranty_months' => ($asset->warranty_months > 0) ? e($asset->warranty_months.' '.trans('admin/hardware/form.months')) : null, 'warranty_months' => ($asset->warranty_months > 0) ? e($asset->warranty_months.' '.trans('admin/hardware/form.months')) : null,
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null, 'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
'created_by' => ($asset->adminuser) ? [ 'created_by' => ($asset->adminuser) ? [
@@ -204,6 +203,7 @@ class AssetsTransformer
'last_name'=> ($asset->assigned->last_name) ? e($asset->assigned->last_name) : null, 'last_name'=> ($asset->assigned->last_name) ? e($asset->assigned->last_name) : null,
'email'=> ($asset->assigned->email) ? e($asset->assigned->email) : null, 'email'=> ($asset->assigned->email) ? e($asset->assigned->email) : null,
'employee_number' => ($asset->assigned->employee_num) ? e($asset->assigned->employee_num) : null, 'employee_number' => ($asset->assigned->employee_num) ? e($asset->assigned->employee_num) : null,
'jobtitle' => $asset->assigned->jobtitle ? e($asset->assigned->jobtitle) : null,
'type' => 'user', 'type' => 'user',
] : null; ] : null;
} }

View File

@@ -133,7 +133,7 @@ abstract class Importer
} else { } else {
$this->csv = Reader::createFromString($file); $this->csv = Reader::createFromString($file);
} }
$this->tempPassword = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 40); $this->tempPassword = '*** NO PASSWORD - IMPORTED VIA CSV ***';
} }
// Cached Values for import lookups // Cached Values for import lookups

View File

@@ -7,7 +7,9 @@ use App\Models\Department;
use App\Models\Setting; use App\Models\Setting;
use App\Models\User; use App\Models\User;
use App\Notifications\WelcomeNotification; use App\Notifications\WelcomeNotification;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Password;
/** /**
* This is ONLY used for the User Import. When we are importing users * This is ONLY used for the User Import. When we are importing users
@@ -80,6 +82,7 @@ class UserImporter extends ItemImporter
$this->item['username'] = $user_formatted_array['username']; $this->item['username'] = $user_formatted_array['username'];
} }
// Check if a numeric ID was passed. If it does, use that above all else. // Check if a numeric ID was passed. If it does, use that above all else.
if ((array_key_exists('id', $this->item) && ($this->item['id'] != "") && (is_numeric($this->item['id'])))) { if ((array_key_exists('id', $this->item) && ($this->item['id'] != "") && (is_numeric($this->item['id'])))) {
$user = User::find($this->item['id']); $user = User::find($this->item['id']);
@@ -89,12 +92,25 @@ class UserImporter extends ItemImporter
if ($user) { if ($user) {
// If the user does not want to update existing values, only add new ones, bail out
if (! $this->updating) { if (! $this->updating) {
Log::debug('A matching User '.$this->item['name'].' already exists. '); Log::debug('A matching User '.$this->item['name'].' already exists. ');
return; return;
} }
$this->log('Updating User'); $this->log('Updating User');
// Todo - check that this works
if (!Gate::allows('canEditAuthFields', $user)) {
unset($user->username);
unset($user->email);
unset($user->password);
unset($user->activated);
}
$user->update($this->sanitizeItemForUpdating($user)); $user->update($this->sanitizeItemForUpdating($user));
// Why do we have to do this twice? Update should
$user->save(); $user->save();
// Update the location of any assets checked out to this user // Update the location of any assets checked out to this user
@@ -110,28 +126,32 @@ class UserImporter extends ItemImporter
// This needs to be applied after the update logic, otherwise we'll overwrite user passwords // This needs to be applied after the update logic, otherwise we'll overwrite user passwords
// Issue #5408 // Issue #5408
$this->item['password'] = bcrypt($this->tempPassword); $this->item['password'] = $this->tempPassword;
$this->log('No matching user, creating one'); $this->log('No matching user, creating one');
$user = new User(); $user = new User();
$user->created_by = auth()->id(); $user->created_by = auth()->id();
$user->fill($this->sanitizeItemForStoring($user)); $user->fill($this->sanitizeItemForStoring($user));
// TODO - check for gate here I guess
if ($user->save()) { if ($user->save()) {
$this->log('User '.$this->item['name'].' was created'); $this->log('User '.$this->item['name'].' was created');
if (($user->email) && ($user->activated == '1')) { if (($user->email) && ($user->activated == '1')) {
$data = [
'email' => $user->email,
'username' => $user->username,
'first_name' => $user->first_name,
'last_name' => $user->last_name,
'password' => $this->tempPassword,
];
if ($this->send_welcome) { if ($this->send_welcome) {
$user->notify(new WelcomeNotification($data));
try {
$user->notify(new WelcomeNotification($user));
} catch (\Exception $e) {
Log::warning('Could not send welcome notification for user: ' . $e->getMessage());
}
} }
} }
$user = null; $user = null;
$this->item = null; $this->item = null;
@@ -140,9 +160,9 @@ class UserImporter extends ItemImporter
} }
$this->logError($user, 'User'); $this->logError($user, 'User');
return;
} }
/** /**
* Fetch an existing department, or create new if it doesn't exist * Fetch an existing department, or create new if it doesn't exist
* *

View File

@@ -4,10 +4,12 @@ namespace App\Listeners;
use App\Events\CheckoutableCheckedOut; use App\Events\CheckoutableCheckedOut;
use App\Mail\CheckinAccessoryMail; use App\Mail\CheckinAccessoryMail;
use App\Mail\CheckinComponentMail;
use App\Mail\CheckinLicenseMail; use App\Mail\CheckinLicenseMail;
use App\Mail\CheckoutAccessoryMail; use App\Mail\CheckoutAccessoryMail;
use App\Mail\CheckoutAssetMail; use App\Mail\CheckoutAssetMail;
use App\Mail\CheckinAssetMail; use App\Mail\CheckinAssetMail;
use App\Mail\CheckoutComponentMail;
use App\Mail\CheckoutConsumableMail; use App\Mail\CheckoutConsumableMail;
use App\Mail\CheckoutLicenseMail; use App\Mail\CheckoutLicenseMail;
use App\Models\Accessory; use App\Models\Accessory;
@@ -22,9 +24,11 @@ use App\Models\Setting;
use App\Models\User; use App\Models\User;
use App\Notifications\CheckinAccessoryNotification; use App\Notifications\CheckinAccessoryNotification;
use App\Notifications\CheckinAssetNotification; use App\Notifications\CheckinAssetNotification;
use App\Notifications\CheckinComponentNotification;
use App\Notifications\CheckinLicenseSeatNotification; use App\Notifications\CheckinLicenseSeatNotification;
use App\Notifications\CheckoutAccessoryNotification; use App\Notifications\CheckoutAccessoryNotification;
use App\Notifications\CheckoutAssetNotification; use App\Notifications\CheckoutAssetNotification;
use App\Notifications\CheckoutComponentNotification;
use App\Notifications\CheckoutConsumableNotification; use App\Notifications\CheckoutConsumableNotification;
use App\Notifications\CheckoutLicenseSeatNotification; use App\Notifications\CheckoutLicenseSeatNotification;
use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\ClientException;
@@ -39,7 +43,7 @@ use Osama\LaravelTeamsNotification\TeamsNotification;
class CheckoutableListener class CheckoutableListener
{ {
private array $skipNotificationsFor = [ private array $skipNotificationsFor = [
Component::class, // Component::class,
]; ];
/** /**
@@ -145,7 +149,6 @@ class CheckoutableListener
$shouldSendEmailToUser = $this->checkoutableCategoryShouldSendEmail($event->checkoutable); $shouldSendEmailToUser = $this->checkoutableCategoryShouldSendEmail($event->checkoutable);
$shouldSendEmailToAlertAddress = $this->shouldSendEmailToAlertAddress(); $shouldSendEmailToAlertAddress = $this->shouldSendEmailToAlertAddress();
$shouldSendWebhookNotification = $this->shouldSendWebhookNotification(); $shouldSendWebhookNotification = $this->shouldSendWebhookNotification();
if (!$shouldSendEmailToUser && !$shouldSendEmailToAlertAddress && !$shouldSendWebhookNotification) { if (!$shouldSendEmailToUser && !$shouldSendEmailToAlertAddress && !$shouldSendWebhookNotification) {
return; return;
} }
@@ -269,6 +272,9 @@ class CheckoutableListener
case LicenseSeat::class: case LicenseSeat::class:
$notificationClass = CheckinLicenseSeatNotification::class; $notificationClass = CheckinLicenseSeatNotification::class;
break; break;
case Component::class:
$notificationClass = CheckinComponentNotification::class;
break;
} }
Log::debug('Notification class: '.$notificationClass); Log::debug('Notification class: '.$notificationClass);
@@ -299,6 +305,9 @@ class CheckoutableListener
case LicenseSeat::class: case LicenseSeat::class:
$notificationClass = CheckoutLicenseSeatNotification::class; $notificationClass = CheckoutLicenseSeatNotification::class;
break; break;
case Component::class:
$notificationClass = CheckoutComponentNotification::class;
break;
} }
@@ -310,6 +319,7 @@ class CheckoutableListener
Asset::class => CheckoutAssetMail::class, Asset::class => CheckoutAssetMail::class,
LicenseSeat::class => CheckoutLicenseMail::class, LicenseSeat::class => CheckoutLicenseMail::class,
Consumable::class => CheckoutConsumableMail::class, Consumable::class => CheckoutConsumableMail::class,
Component::class => CheckoutComponentMail::class,
]; ];
$mailable= $lookup[get_class($event->checkoutable)]; $mailable= $lookup[get_class($event->checkoutable)];
@@ -322,8 +332,8 @@ class CheckoutableListener
Accessory::class => CheckinAccessoryMail::class, Accessory::class => CheckinAccessoryMail::class,
Asset::class => CheckinAssetMail::class, Asset::class => CheckinAssetMail::class,
LicenseSeat::class => CheckinLicenseMail::class, LicenseSeat::class => CheckinLicenseMail::class,
Component::class => CheckinComponentMail::class,
]; ];
$mailable= $lookup[get_class($event->checkoutable)]; $mailable= $lookup[get_class($event->checkoutable)];
return new $mailable($event->checkoutable, $event->checkedOutTo, $event->checkedInBy, $event->note); return new $mailable($event->checkoutable, $event->checkedOutTo, $event->checkedInBy, $event->note);
@@ -469,7 +479,8 @@ class CheckoutableListener
return match (true) { return match (true) {
$checkoutable instanceof Asset => $checkoutable->model->category, $checkoutable instanceof Asset => $checkoutable->model->category,
$checkoutable instanceof Accessory, $checkoutable instanceof Accessory,
$checkoutable instanceof Consumable => $checkoutable->category, $checkoutable instanceof Consumable,
$checkoutable instanceof Component => $checkoutable->category,
$checkoutable instanceof LicenseSeat => $checkoutable->license->category, $checkoutable instanceof LicenseSeat => $checkoutable->license->category,
}; };
} }

View File

@@ -0,0 +1,71 @@
<?php
namespace App\Mail;
use App\Models\Accessory;
use App\Models\Component;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class CheckinComponentMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct(Component $component, $checkedOutTo, User $checkedInby, $note)
{
$this->item = $component;
$this->target = $checkedOutTo;
$this->admin = $checkedInby;
$this->note = $note;
$this->settings = Setting::getSettings();
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
$from = new Address(config('mail.from.address'), config('mail.from.name'));
return new Envelope(
from: $from,
subject: trans('mail.Confirm_component_checkin'),
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
markdown: 'mail.markdown.checkin-component',
with: [
'item' => $this->item,
'admin' => $this->admin,
'note' => $this->note,
'target' => $this->target,
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace App\Mail;
use App\Models\Component;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Address;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class CheckoutComponentMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct(Component $component, $checkedOutTo, User $checkedOutBy, $acceptance, $note)
{
$this->item = $component;
$this->admin = $checkedOutBy;
$this->note = $note;
$this->target = $checkedOutTo;
$this->acceptance = $acceptance;
$this->qty = $component->assets->first()?->pivot?->assigned_qty;
$this->settings = Setting::getSettings();
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
$from = new Address(config('mail.from.address'), config('mail.from.name'));
return new Envelope(
from: $from,
subject: trans('mail.Confirm_component_delivery'),
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
$eula = $this->item->getEula();
$req_accept = $this->item->requireAcceptance();
$accept_url = is_null($this->acceptance) ? null : route('account.accept.item', $this->acceptance);
return new Content(
markdown: 'mail.markdown.checkout-component',
with: [
'item' => $this->item,
'admin' => $this->admin,
'note' => $this->note,
'target' => $this->target,
'eula' => $eula,
'req_accept' => $req_accept,
'accept_url' => $accept_url,
'qty' => $this->qty,
]
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}

View File

@@ -74,6 +74,8 @@ class Actionlog extends SnipeModel
'assets' => ['asset_tag','name', 'serial', 'order_number', 'notes', 'purchase_date'], 'assets' => ['asset_tag','name', 'serial', 'order_number', 'notes', 'purchase_date'],
'assets.model' => ['name', 'model_number', 'eol', 'notes'], 'assets.model' => ['name', 'model_number', 'eol', 'notes'],
'assets.model.category' => ['name', 'notes'], 'assets.model.category' => ['name', 'notes'],
'assets.location' => ['name'],
'assets.defaultLoc' => ['name'],
'assets.model.manufacturer' => ['name', 'notes'], 'assets.model.manufacturer' => ['name', 'notes'],
'licenses' => ['name', 'serial', 'notes', 'order_number', 'license_email', 'license_name', 'purchase_order', 'purchase_date'], 'licenses' => ['name', 'serial', 'notes', 'order_number', 'license_email', 'license_name', 'purchase_order', 'purchase_date'],
'licenses.category' => ['name', 'notes'], 'licenses.category' => ['name', 'notes'],

View File

@@ -15,6 +15,8 @@ use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
@@ -421,12 +423,34 @@ class Asset extends Depreciable
{ {
// Check to see if any of the custom fields were included on the form and if they have any values // Check to see if any of the custom fields were included on the form and if they have any values
if (($this->model) && ($this->model->fieldset) && ($this->model->fieldset->fields)) { if (($this->model) && ($this->model->fieldset) && ($this->model->fieldset->fields)) {
foreach ($this->model->fieldset->fields as $field) { foreach ($this->model->fieldset->fields as $field) {
if (($field->{$checkin_checkout} == 1) && (request()->has($field->db_column))) { if (($field->{$checkin_checkout} == 1) && (request()->has($field->db_column))) {
$this->{$field->db_column} = request()->get($field->db_column);
if ($field->field_encrypted == '1') {
if (Gate::allows('assets.view.encrypted_custom_fields')) {
if (is_array(request()->input($field->db_column))) {
$this->{$field->db_column} = Crypt::encrypt(implode(', ', request()->input($field->db_column)));
} else {
$this->{$field->db_column} = Crypt::encrypt(request()->get($field->db_column));
}
}
} else {
if (is_array(request()->input($field->db_column))) {
$this->{$field->db_column} = implode(', ', request()->input($field->db_column));
} else {
$this->{$field->db_column} = request()->input($field->db_column);
}
}
} }
} }
} }
} }

View File

@@ -2,12 +2,14 @@
namespace App\Models; namespace App\Models;
use App\Helpers\Helper;
use App\Models\Traits\HasUploads; use App\Models\Traits\HasUploads;
use App\Models\Traits\Searchable; use App\Models\Traits\Searchable;
use App\Presenters\Presentable; use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
/** /**
@@ -203,6 +205,36 @@ class Component extends SnipeModel
{ {
return $this->belongsTo(\App\Models\Manufacturer::class, 'manufacturer_id'); return $this->belongsTo(\App\Models\Manufacturer::class, 'manufacturer_id');
} }
/**
* Determine whether this asset requires acceptance by the assigned user
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return bool
*/
public function requireAcceptance()
{
return $this->category->require_acceptance;
}
/**
* Checks for a category-specific EULA, and if that doesn't exist,
* checks for a settings level EULA
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return string | false
*/
public function getEula()
{
if ($this->category->eula_text) {
return Helper::parseEscapedMarkedown($this->category->eula_text);
} elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) {
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
} else {
return null;
}
}
/** /**
* Establishes the component -> action logs relationship * Establishes the component -> action logs relationship
@@ -248,6 +280,19 @@ class Component extends SnipeModel
} }
/**
* Determine whether to send a checkin/checkout email based on
* asset model category
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v4.0]
* @return bool
*/
public function checkin_email()
{
return $this->category?->checkin_email;
}
/** /**
* Check how many items within a component are remaining * Check how many items within a component are remaining

View File

@@ -23,6 +23,7 @@ use Illuminate\Support\Str;
use Laravel\Passport\HasApiTokens; use Laravel\Passport\HasApiTokens;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use App\Presenters\UserPresenter;
class User extends SnipeModel implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, HasLocalePreference class User extends SnipeModel implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, HasLocalePreference
{ {
@@ -30,7 +31,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
use CompanyableTrait; use CompanyableTrait;
use HasUploads; use HasUploads;
protected $presenter = \App\Presenters\UserPresenter::class; protected $presenter = UserPresenter::class;
use SoftDeletes, ValidatingTrait, Loggable; use SoftDeletes, ValidatingTrait, Loggable;
use Authenticatable, Authorizable, CanResetPassword, HasApiTokens; use Authenticatable, Authorizable, CanResetPassword, HasApiTokens;
use UniqueUndeletedTrait; use UniqueUndeletedTrait;
@@ -38,7 +39,16 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
use Presentable; use Presentable;
use Searchable; use Searchable;
protected $hidden = ['password', 'remember_token', 'permissions', 'reset_password_code', 'persist_code']; protected $hidden = [
'password',
'remember_token',
'permissions',
'reset_password_code',
'persist_code',
'two_factor_secret',
'activation_code',
];
protected $table = 'users'; protected $table = 'users';
protected $injectUniqueIdentifier = true; protected $injectUniqueIdentifier = true;
@@ -193,11 +203,19 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
{ {
$user_groups = $this->groups; $user_groups = $this->groups;
if (($this->permissions == '') && (count($user_groups) == 0)) { if (($this->permissions == '') && (count($user_groups) == 0)) {
return false; return false;
} }
$user_permissions = json_decode($this->permissions, true); $user_permissions = $this->permissions;
if (is_object($this->permissions)) {
$user_permissions = json_decode(json_encode($this->permissions), true);
}
if (is_string($this->permissions)) {
$user_permissions = json_decode($this->permissions, true);
}
$is_user_section_permissions_set = ($user_permissions != '') && array_key_exists($section, $user_permissions); $is_user_section_permissions_set = ($user_permissions != '') && array_key_exists($section, $user_permissions);
//If the user is explicitly granted, return true //If the user is explicitly granted, return true
@@ -251,6 +269,18 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
return $this->checkPermissionSection('superuser'); return $this->checkPermissionSection('superuser');
} }
/**
* Checks if the user is an admin
*
* @author A. Gianotto <snipe@snipe.net>
* @since [v8.1.18]
* @return bool
*/
public function isAdmin()
{
return $this->checkPermissionSection('admin');
}
/** /**
* Checks if the user can edit their own profile * Checks if the user can edit their own profile
@@ -278,13 +308,15 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
*/ */
public function isDeletable() public function isDeletable()
{ {
return Gate::allows('delete', $this) return Gate::allows('delete', $this)
&& ($this->assets->count() === 0) && (($this->assets_count ?? $this->assets()->count()) === 0)
&& ($this->licenses->count() === 0) && (($this->accessories_count ?? $this->accessories()->count()) === 0)
&& ($this->consumables->count() === 0) && (($this->licenses_count ?? $this->licenses()->count()) === 0)
&& ($this->accessories->count() === 0) && (($this->consumables_count ?? $this->consumables()->count()) === 0)
&& ($this->managedLocations->count() === 0) && (($this->accessories_count ?? $this->accessories()->count()) === 0)
&& ($this->managesUsers->count() === 0) && (($this->manages_users_count ?? $this->managesUsers()->count()) === 0)
&& (($this->manages_locations_count ?? $this->managedLocations()->count()) === 0)
&& ($this->deleted_at == ''); && ($this->deleted_at == '');
} }

View File

@@ -0,0 +1,165 @@
<?php
namespace App\Notifications;
use App\Models\Component;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Channels\SlackWebhookChannel;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Str;
use NotificationChannels\GoogleChat\Card;
use NotificationChannels\GoogleChat\GoogleChatChannel;
use NotificationChannels\GoogleChat\GoogleChatMessage;
use NotificationChannels\GoogleChat\Section;
use NotificationChannels\GoogleChat\Widgets\KeyValue;
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
class CheckinComponentNotification extends Notification
{
use Queueable;
/**
* @var
*/
private $params;
/**
* Create a new notification instance.
*
* @param $params
*/
public function __construct(Component $component, $checkedOutTo, User $checkedInBy, $note)
{
$this->target = $checkedOutTo;
$this->item = $component;
$this->admin = $checkedInBy;
$this->note = $note;
$this->settings = Setting::getSettings();
}
/**
* Get the notification's delivery channels.
*
* @return array
*/
public function via()
{
$notifyBy = [];
if (Setting::getSettings()->webhook_selected == 'google' && Setting::getSettings()->webhook_endpoint) {
$notifyBy[] = GoogleChatChannel::class;
}
if (Setting::getSettings()->webhook_selected == 'microsoft' && Setting::getSettings()->webhook_endpoint) {
$notifyBy[] = MicrosoftTeamsChannel::class;
}
if (Setting::getSettings()->webhook_selected == 'slack' || Setting::getSettings()->webhook_selected == 'general' ) {
$notifyBy[] = SlackWebhookChannel::class;
}
return $notifyBy;
}
public function toSlack()
{
$target = $this->target;
$admin = $this->admin;
$item = $this->item;
$note = $this->note;
$botname = ($this->settings->webhook_botname) ? $this->settings->webhook_botname : 'Snipe-Bot';
$channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : '';
if ($admin) {
$fields = [
trans('general.from') => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>',
trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>',
];
if ($item->location) {
$fields[trans('general.location')] = $item->location->name;
}
if ($item->company) {
$fields[trans('general.company')] = $item->company->name;
}
} else {
$fields = [
'To' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>',
'By' => 'CLI tool',
];
}
return (new SlackMessage)
->content(':arrow_down: :package: '.trans('mail.Component_checkin_notification'))
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
}
public function toMicrosoftTeams()
{
$target = $this->target;
$admin = $this->admin;
$item = $this->item;
$note = $this->note;
if(!Str::contains(Setting::getSettings()->webhook_endpoint, 'workflows')) {
return MicrosoftTeamsMessage::create()
->to($this->settings->webhook_endpoint)
->type('success')
->addStartGroupToSection('activityTitle')
->title(trans('mail.Component_checkin_notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->present()->name), '', 'header')
->fact(trans('mail.Component_checkin_notification')." by ", $admin->present()->fullName() ?: 'CLI tool')
->fact(trans('mail.checkedin_from'), $target->present()->fullName())
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
->fact(trans('mail.notes'), $note ?: '');
}
$message = trans('mail.Component_checkin_notification');
$details = [
trans('mail.checkedin_from')=> $target->present()->fullName(),
trans('mail.Component_checkin_notification')." by " => $admin->present()->fullName() ?: 'CLI tool',
trans('admin/consumables/general.remaining') => $item->numRemaining(),
trans('mail.notes') => $note ?: '',
];
return array($message, $details);
}
public function toGoogleChat()
{
$target = $this->target;
$item = $this->item;
$note = $this->note;
return GoogleChatMessage::create()
->to($this->settings->webhook_endpoint)
->card(
Card::create()
->header(
'<strong>'.trans('mail.Component_checkin_notification').'</strong>' ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
KeyValue::create(
trans('mail.checkedin_from') ?: '',
$target->present()->fullName() ?: '',
trans('admin/consumables/general.remaining').': '.$item->numRemaining(),
)
->onClick(route('components.show', $item->id))
)
)
);
}
}

View File

@@ -0,0 +1,164 @@
<?php
namespace App\Notifications;
use App\Models\Component;
use App\Models\Setting;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Channels\SlackWebhookChannel;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Str;
use NotificationChannels\GoogleChat\Card;
use NotificationChannels\GoogleChat\GoogleChatChannel;
use NotificationChannels\GoogleChat\GoogleChatMessage;
use NotificationChannels\GoogleChat\Section;
use NotificationChannels\GoogleChat\Widgets\KeyValue;
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
class CheckoutComponentNotification extends Notification
{
use Queueable;
/**
* @var
*/
private $params;
/**
* Create a new notification instance.
*
* @param $params
*/
public function __construct(Component $component, $checkedOutTo, User $checkedOutBy, $acceptance, $note)
{
$this->item = $component;
$this->admin = $checkedOutBy;
$this->note = $note;
$this->target = $checkedOutTo;
$this->acceptance = $acceptance;
$this->qty = $component->checkout_qty;
$this->settings = Setting::getSettings();
}
/**`
* Get the notification's delivery channels.
*
* @return array
*/
public function via()
{
$notifyBy = [];
if (Setting::getSettings()->webhook_selected == 'google' && Setting::getSettings()->webhook_endpoint) {
$notifyBy[] = GoogleChatChannel::class;
}
if (Setting::getSettings()->webhook_selected == 'microsoft' && Setting::getSettings()->webhook_endpoint) {
$notifyBy[] = MicrosoftTeamsChannel::class;
}
if (Setting::getSettings()->webhook_selected == 'slack' || Setting::getSettings()->webhook_selected == 'general' ) {
$notifyBy[] = SlackWebhookChannel::class;
}
return $notifyBy;
}
public function toSlack()
{
$target = $this->target;
$admin = $this->admin;
$item = $this->item;
$note = $this->note;
$botname = ($this->settings->webhook_botname) ? $this->settings->webhook_botname : 'Snipe-Bot';
$channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : '';
$fields = [
trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>',
trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>',
];
if ($item->location) {
$fields[trans('general.location')] = $item->location->name;
}
if ($item->company) {
$fields[trans('general.company')] = $item->company->name;
}
return (new SlackMessage)
->content(':arrow_up: :package: '.trans('mail.Component_checkout_notification'))
->from($botname)
->to($channel)
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
->fields($fields)
->content($note);
});
}
public function toMicrosoftTeams()
{
$target = $this->target;
$admin = $this->admin;
$item = $this->item;
$note = $this->note;
if(!Str::contains(Setting::getSettings()->webhook_endpoint, 'workflows')) {
return MicrosoftTeamsMessage::create()
->to($this->settings->webhook_endpoint)
->type('success')
->addStartGroupToSection('activityTitle')
->title(trans('mail.Component_checkout_notification'))
->addStartGroupToSection('activityText')
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
->fact(trans('mail.Component_checkout_notification')." by ", $admin->present()->fullName())
->fact(trans('mail.assigned_to'), $target->present()->fullName())
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
->fact(trans('mail.notes'), $note ?: '');
}
$message = trans('mail.Component_checkout_notification');
$details = [
trans('mail.assigned_to') => $target->present()->fullName(),
trans('mail.item') => htmlspecialchars_decode($item->present()->name),
trans('mail.Component_checkout_notification').' by' => $admin->present()->fullName(),
trans('admin/consumables/general.remaining') => $item->numRemaining(),
trans('mail.notes') => $note ?: '',
];
return array($message, $details);
}
public function toGoogleChat()
{
$target = $this->target;
$item = $this->item;
$note = $this->note;
return GoogleChatMessage::create()
->to($this->settings->webhook_endpoint)
->card(
Card::create()
->header(
'<strong>'.trans('mail.Component_checkout_notification').'</strong>' ?: '',
htmlspecialchars_decode($item->present()->name) ?: '',
)
->section(
Section::create(
KeyValue::create(
trans('mail.assigned_to') ?: '',
$target->present()->fullName() ?: '',
trans('admin/consumables/general.remaining').': '.$item->numRemaining(),
)
->onClick(route('api.assets.show', $target->id))
)
)
);
}
}

View File

@@ -5,26 +5,23 @@ namespace App\Notifications;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification; use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Password;
use App\Models\User;
class WelcomeNotification extends Notification class WelcomeNotification extends Notification
{ {
use Queueable; use Queueable;
private $_data = []; public $expire_date;
/** /**
* Create a new notification instance. * Create a new notification instance.
* *
* @return void * @return void
*/ */
public function __construct(array $content) public function __construct(public User $user)
{ {
$this->_data['email'] = htmlspecialchars_decode($content['email']); $this->user->token = Password::broker('invites')->createToken($user);
$this->_data['first_name'] = htmlspecialchars_decode($content['first_name']); $this->user->expire_date = now()->addMinutes((int) config('auth.passwords.invites.expire', 2880))->format('F j, Y, g:i a');
$this->_data['last_name'] = htmlspecialchars_decode($content['last_name']);
$this->_data['username'] = htmlspecialchars_decode($content['username']);
$this->_data['password'] = htmlspecialchars_decode($content['password']);
$this->_data['url'] = config('app.url');
} }
/** /**
@@ -44,8 +41,9 @@ class WelcomeNotification extends Notification
*/ */
public function toMail() public function toMail()
{ {
return (new MailMessage()) return (new MailMessage())
->subject(trans('mail.welcome', ['name' => $this->_data['first_name'].' '.$this->_data['last_name']])) ->subject(trans('mail.welcome', ['name' => $this->user->first_name.' '.$this->user->last_name]))
->markdown('notifications.Welcome', $this->_data); ->markdown('notifications.Welcome', $this->user->toArray());
} }
} }

View File

@@ -115,6 +115,7 @@ class AssetPresenter extends Presenter
'sortable' => true, 'sortable' => true,
'title' => trans('admin/users/table.title'), 'title' => trans('admin/users/table.title'),
'visible' => false, 'visible' => false,
'formatter' => 'jobtitleFormatter',
], [ ], [
'field' => 'location', 'field' => 'location',
'searchable' => true, 'searchable' => true,

View File

@@ -5,7 +5,7 @@ namespace App\Presenters;
/** /**
* Class AccessoryPresenter * Class AccessoryPresenter
*/ */
class UploadsPresenter extends Presenter class UploadedFilesPresenter extends Presenter
{ {
/** /**
* Json Column Layout for bootstrap table * Json Column Layout for bootstrap table

View File

@@ -101,13 +101,21 @@ class AuthServiceProvider extends ServiceProvider
* This is where we set the superadmin permission to allow superadmins to be able to do everything within the system. * This is where we set the superadmin permission to allow superadmins to be able to do everything within the system.
* *
*/ */
Gate::before(function ($user) { Gate::before(function ($user, $ability) {
// Disallow even superadmins to edit non-editable things when in demo mode.
// (We have to do this to prevent jerks from trying to break the demo by editing things they shouldn't.)
if (($ability == 'editableOnDemo') && (config('app.lock_passwords'))) {
return false;
}
if ($user->isSuperUser()) { if ($user->isSuperUser()) {
return true; return true;
} }
}); });
/** /**
* GENERAL GATES * GENERAL GATES
* *
@@ -115,6 +123,45 @@ class AuthServiceProvider extends ServiceProvider
* use in our controllers to determine if a user has access to a certain area. * use in our controllers to determine if a user has access to a certain area.
*/ */
Gate::define('canEditAuthFields', function ($user, $item) {
if ($item instanceof User) {
// if they can only edit users, deny them if the user is admin or superadmin
if (($user->hasAccess('users.edit')) && (!$user->isAdmin()) && (!$user->isAdmin())) {
if ($item->isAdmin() || $item->isSuperUser()) {
return false;
}
return true;
}
// if they are an admin, deny them only if the user is a superadmin
if ($user->hasAccess('admin')) {
if ($item->isSuperUser()) {
return false;
}
return true;
}
return false;
}
return false;
});
/**
* Define the demo mode gate so we have an easy way to use @can and Gate::allows()
*/
Gate::define('editableOnDemo', function () {
if (config('app.lock_passwords')) {
return false;
}
return true;
});
Gate::define('admin', function ($user) { Gate::define('admin', function ($user) {
if ($user->hasAccess('admin')) { if ($user->hasAccess('admin')) {
return true; return true;
@@ -249,5 +296,6 @@ class AuthServiceProvider extends ServiceProvider
return $user->canEditProfile(); return $user->canEditProfile();
}); });
} }
} }

28
composer.lock generated
View File

@@ -4532,23 +4532,23 @@
}, },
{ {
"name": "livewire/livewire", "name": "livewire/livewire",
"version": "v3.5.18", "version": "v3.6.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/livewire/livewire.git", "url": "https://github.com/livewire/livewire.git",
"reference": "62f0fa6b340a467c25baa590a567d9a134b357da" "reference": "ef04be759da41b14d2d129e670533180a44987dc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/livewire/livewire/zipball/62f0fa6b340a467c25baa590a567d9a134b357da", "url": "https://api.github.com/repos/livewire/livewire/zipball/ef04be759da41b14d2d129e670533180a44987dc",
"reference": "62f0fa6b340a467c25baa590a567d9a134b357da", "reference": "ef04be759da41b14d2d129e670533180a44987dc",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"illuminate/database": "^10.0|^11.0", "illuminate/database": "^10.0|^11.0|^12.0",
"illuminate/routing": "^10.0|^11.0", "illuminate/routing": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0", "illuminate/support": "^10.0|^11.0|^12.0",
"illuminate/validation": "^10.0|^11.0", "illuminate/validation": "^10.0|^11.0|^12.0",
"laravel/prompts": "^0.1.24|^0.2|^0.3", "laravel/prompts": "^0.1.24|^0.2|^0.3",
"league/mime-type-detection": "^1.9", "league/mime-type-detection": "^1.9",
"php": "^8.1", "php": "^8.1",
@@ -4557,11 +4557,11 @@
}, },
"require-dev": { "require-dev": {
"calebporzio/sushi": "^2.1", "calebporzio/sushi": "^2.1",
"laravel/framework": "^10.15.0|^11.0", "laravel/framework": "^10.15.0|^11.0|^12.0",
"mockery/mockery": "^1.3.1", "mockery/mockery": "^1.3.1",
"orchestra/testbench": "^8.21.0|^9.0", "orchestra/testbench": "^8.21.0|^9.0|^10.0",
"orchestra/testbench-dusk": "^8.24|^9.1", "orchestra/testbench-dusk": "^8.24|^9.1|^10.0",
"phpunit/phpunit": "^10.4", "phpunit/phpunit": "^10.4|^11.5",
"psy/psysh": "^0.11.22|^0.12" "psy/psysh": "^0.11.22|^0.12"
}, },
"type": "library", "type": "library",
@@ -4596,7 +4596,7 @@
"description": "A front-end framework for Laravel.", "description": "A front-end framework for Laravel.",
"support": { "support": {
"issues": "https://github.com/livewire/livewire/issues", "issues": "https://github.com/livewire/livewire/issues",
"source": "https://github.com/livewire/livewire/tree/v3.5.18" "source": "https://github.com/livewire/livewire/tree/v3.6.4"
}, },
"funding": [ "funding": [
{ {
@@ -4604,7 +4604,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2024-12-23T15:05:02+00:00" "time": "2025-07-17T05:12:15+00:00"
}, },
{ {
"name": "masterminds/html5", "name": "masterminds/html5",

View File

@@ -104,6 +104,16 @@ return [
] ]
], ],
'invites' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => env('INVITE_PASSWORD_LINK_EXPIRES', 2880),
'throttle' => [
'max_attempts' => env('LOGIN_MAX_ATTEMPTS', 5),
'lockout_duration' => env('LOGIN_LOCKOUT_DURATION', 60),
]
],
], ],
/* /*

View File

@@ -1,10 +1,10 @@
<?php <?php
return array ( return array (
'app_version' => 'v8.1.18', 'app_version' => 'v8.2.1',
'full_app_version' => 'v8.1.18 - build 18876-g4c6249eb9', 'full_app_version' => 'v8.2.1 - build 19068-g6ca49a20c',
'build_version' => '18876', 'build_version' => '19068',
'prerelease_version' => '', 'prerelease_version' => '',
'hash_version' => 'g4c6249eb9', 'hash_version' => 'g6ca49a20c',
'full_hash' => 'v8.1.18-77-g4c6249eb9', 'full_hash' => 'v8.2.1-10-g6ca49a20c',
'branch' => 'develop', 'branch' => 'develop',
); );

View File

@@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
//
Artisan::call("snipeit:clean-checkout-acceptances");
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};

View File

@@ -51,8 +51,6 @@ class AssetModelSeeder extends Seeder
$del_files = Storage::files($dst); $del_files = Storage::files($dst);
foreach ($del_files as $del_file) { // iterate files foreach ($del_files as $del_file) { // iterate files
$file_to_delete = str_replace($src, '', $del_file);
Log::debug('Deleting: '.$file_to_delete);
try { try {
Storage::disk('public')->delete($dst.$del_file); Storage::disk('public')->delete($dst.$del_file);
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -63,7 +61,6 @@ class AssetModelSeeder extends Seeder
$add_files = glob($src.'/*.*'); $add_files = glob($src.'/*.*');
foreach ($add_files as $add_file) { foreach ($add_files as $add_file) {
$file_to_copy = str_replace($src, '', $add_file); $file_to_copy = str_replace($src, '', $add_file);
Log::debug('Copying: '.$file_to_copy);
try { try {
Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy)); Storage::disk('public')->put($dst.$file_to_copy, file_get_contents($src.$file_to_copy));
} catch (\Exception $e) { } catch (\Exception $e) {

1941
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -18,11 +18,11 @@
"devDependencies": { "devDependencies": {
"all-contributors-cli": "^6.26.1", "all-contributors-cli": "^6.26.1",
"axios": "^1.7.2", "axios": "^1.7.2",
"babel-preset-latest": "^6.24.1",
"jquery": "<3.6.0", "jquery": "<3.6.0",
"laravel-mix": "^6.0.49", "laravel-mix": "^6.0.49",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"postcss": "^8.4.5" "postcss": "^8.4.5",
"webpack": "^5.2.2"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^6.7.2", "@fortawesome/fontawesome-free": "^6.7.2",
@@ -37,7 +37,7 @@
"bootstrap-less": "^3.3.8", "bootstrap-less": "^3.3.8",
"bootstrap-table": "1.24.1", "bootstrap-table": "1.24.1",
"canvas-confetti": "^1.9.3", "canvas-confetti": "^1.9.3",
"chart.js": "^2.9.4", "chart.js": "4.5.0",
"clipboard": "^2.0.11", "clipboard": "^2.0.11",
"css-loader": "^5.0.0", "css-loader": "^5.0.0",
"ekko-lightbox": "^5.1.1", "ekko-lightbox": "^5.1.1",
@@ -46,7 +46,7 @@
"jquery-ui": "^1.14.1", "jquery-ui": "^1.14.1",
"jquery-validation": "^1.21.0", "jquery-validation": "^1.21.0",
"jquery.iframe-transport": "^1.0.0", "jquery.iframe-transport": "^1.0.0",
"jspdf-autotable": "^3.8.4", "jspdf-autotable": "^5.0.2",
"less": "^4.2.2", "less": "^4.2.2",
"less-loader": "^6.0", "less-loader": "^6.0",
"list.js": "^1.5.0", "list.js": "^1.5.0",
@@ -55,8 +55,7 @@
"select2": "4.0.13", "select2": "4.0.13",
"sheetjs": "^2.0.0", "sheetjs": "^2.0.0",
"signature_pad": "^4.2.0", "signature_pad": "^4.2.0",
"tableexport.jquery.plugin": "1.32.0", "tableexport.jquery.plugin": "^1.9.9",
"tether": "^1.4.0", "tether": "^1.4.0"
"webpack": "^5.98.0"
} }
} }

View File

@@ -1266,7 +1266,6 @@ label.form-control {
} }
label.form-control--disabled { label.form-control--disabled {
color: #959495; color: #959495;
pointer-events: none;
cursor: not-allowed; cursor: not-allowed;
} }
/** --------------------------------------- **/ /** --------------------------------------- **/
@@ -1429,6 +1428,9 @@ input[type="radio"]:checked::before {
.bootstrap-table .fixed-table-container .table tbody tr .card-view { .bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: table-row !important; display: table-row !important;
} }
.form-control-static {
padding-top: 0px;
}
td.text-right.text-padding-number-cell { td.text-right.text-padding-number-cell {
padding-right: 30px !important; padding-right: 30px !important;
white-space: nowrap; white-space: nowrap;

View File

@@ -887,7 +887,6 @@ label.form-control {
} }
label.form-control--disabled { label.form-control--disabled {
color: #959495; color: #959495;
pointer-events: none;
cursor: not-allowed; cursor: not-allowed;
} }
/** --------------------------------------- **/ /** --------------------------------------- **/
@@ -1050,6 +1049,9 @@ input[type="radio"]:checked::before {
.bootstrap-table .fixed-table-container .table tbody tr .card-view { .bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: table-row !important; display: table-row !important;
} }
.form-control-static {
padding-top: 0px;
}
td.text-right.text-padding-number-cell { td.text-right.text-padding-number-cell {
padding-right: 30px !important; padding-right: 30px !important;
white-space: nowrap; white-space: nowrap;

View File

@@ -22601,7 +22601,6 @@ label.form-control {
} }
label.form-control--disabled { label.form-control--disabled {
color: #959495; color: #959495;
pointer-events: none;
cursor: not-allowed; cursor: not-allowed;
} }
/** --------------------------------------- **/ /** --------------------------------------- **/
@@ -22764,6 +22763,9 @@ input[type="radio"]:checked::before {
.bootstrap-table .fixed-table-container .table tbody tr .card-view { .bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: table-row !important; display: table-row !important;
} }
.form-control-static {
padding-top: 0px;
}
td.text-right.text-padding-number-cell { td.text-right.text-padding-number-cell {
padding-right: 30px !important; padding-right: 30px !important;
white-space: nowrap; white-space: nowrap;
@@ -24174,7 +24176,6 @@ label.form-control {
} }
label.form-control--disabled { label.form-control--disabled {
color: #959495; color: #959495;
pointer-events: none;
cursor: not-allowed; cursor: not-allowed;
} }
/** --------------------------------------- **/ /** --------------------------------------- **/
@@ -24337,6 +24338,9 @@ input[type="radio"]:checked::before {
.bootstrap-table .fixed-table-container .table tbody tr .card-view { .bootstrap-table .fixed-table-container .table tbody tr .card-view {
display: table-row !important; display: table-row !important;
} }
.form-control-static {
padding-top: 0px;
}
td.text-right.text-padding-number-cell { td.text-right.text-padding-number-cell {
padding-right: 30px !important; padding-right: 30px !important;
white-space: nowrap; white-space: nowrap;

View File

@@ -2,8 +2,8 @@
"/js/build/app.js": "/js/build/app.js?id=19253af36b58ed3fb6770c7bb944f079", "/js/build/app.js": "/js/build/app.js?id=19253af36b58ed3fb6770c7bb944f079",
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=78bfb1c7b5782df4fb0ac7e36f80f847", "/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=78bfb1c7b5782df4fb0ac7e36f80f847",
"/css/dist/skins/_all-skins.css": "/css/dist/skins/_all-skins.css?id=503d0b09e157a22f555e3670d1ec9bb5", "/css/dist/skins/_all-skins.css": "/css/dist/skins/_all-skins.css?id=503d0b09e157a22f555e3670d1ec9bb5",
"/css/build/overrides.css": "/css/build/overrides.css?id=2bfc7b71d951c5ac026dbc034f7373b1", "/css/build/overrides.css": "/css/build/overrides.css?id=a2147e7a0e0117ab3d20cce276e362e5",
"/css/build/app.css": "/css/build/app.css?id=4b4c2f1225d59efa7a22b76f7bbe39d8", "/css/build/app.css": "/css/build/app.css?id=80d437dcee5ae27fc5e68f85beea4b09",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=4ea0068716c1bb2434d87a16d51b98c9", "/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=4ea0068716c1bb2434d87a16d51b98c9",
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=7b315b9612b8fde8f9c5b0ddb6bba690", "/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=7b315b9612b8fde8f9c5b0ddb6bba690",
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=f6b2e7fa795596ac4754500c9c30eacc", "/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=f6b2e7fa795596ac4754500c9c30eacc",
@@ -19,7 +19,7 @@
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=a82b065847bf3cd5d713c04ee8dc86c6", "/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=a82b065847bf3cd5d713c04ee8dc86c6",
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=7aacfabbafd138c5af6420609f97820d", "/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=7aacfabbafd138c5af6420609f97820d",
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=76482123f6c70e866d6b971ba91de7bb", "/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=76482123f6c70e866d6b971ba91de7bb",
"/css/dist/all.css": "/css/dist/all.css?id=12e96a25d0dc3ee39e9d3ce97044fbbf", "/css/dist/all.css": "/css/dist/all.css?id=c357227b5654c50afb9797141ac32dff",
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7", "/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7", "/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
"/js/select2/i18n/af.js": "/js/select2/i18n/af.js?id=4f6fcd73488ce79fae1b7a90aceaecde", "/js/select2/i18n/af.js": "/js/select2/i18n/af.js?id=4f6fcd73488ce79fae1b7a90aceaecde",

View File

@@ -2863,7 +2863,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}); });
return obj; return obj;
} }
var Alpine20 = { var Alpine23 = {
get reactive() { get reactive() {
return reactive; return reactive;
}, },
@@ -2876,7 +2876,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
get raw() { get raw() {
return raw; return raw;
}, },
version: "3.14.8", version: "3.14.9",
flushAndStopDeferringMutations, flushAndStopDeferringMutations,
dontAutoEvaluateFunctions, dontAutoEvaluateFunctions,
disableEffectScheduling, disableEffectScheduling,
@@ -2929,7 +2929,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
data, data,
bind: bind2 bind: bind2
}; };
var alpine_default = Alpine20; var alpine_default = Alpine23;
var import_reactivity10 = __toESM2(require_reactivity()); var import_reactivity10 = __toESM2(require_reactivity());
magic("nextTick", () => nextTick); magic("nextTick", () => nextTick);
magic("dispatch", (el) => dispatch3.bind(dispatch3, el)); magic("dispatch", (el) => dispatch3.bind(dispatch3, el));
@@ -3857,8 +3857,8 @@ var require_module_cjs2 = __commonJS({
default: () => module_default default: () => module_default
}); });
module.exports = __toCommonJS(module_exports); module.exports = __toCommonJS(module_exports);
function src_default(Alpine20) { function src_default(Alpine23) {
Alpine20.directive("collapse", collapse3); Alpine23.directive("collapse", collapse3);
collapse3.inline = (el, { modifiers }) => { collapse3.inline = (el, { modifiers }) => {
if (!modifiers.includes("min")) if (!modifiers.includes("min"))
return; return;
@@ -3878,7 +3878,7 @@ var require_module_cjs2 = __commonJS({
if (!el._x_isShown) if (!el._x_isShown)
el.style.overflow = "hidden"; el.style.overflow = "hidden";
let setFunction = (el2, styles) => { let setFunction = (el2, styles) => {
let revertFunction = Alpine20.setStyles(el2, styles); let revertFunction = Alpine23.setStyles(el2, styles);
return styles.height ? () => { return styles.height ? () => {
} : revertFunction; } : revertFunction;
}; };
@@ -3901,7 +3901,7 @@ var require_module_cjs2 = __commonJS({
if (current === full) { if (current === full) {
current = floor; current = floor;
} }
Alpine20.transition(el, Alpine20.setStyles, { Alpine23.transition(el, Alpine23.setStyles, {
during: transitionStyles, during: transitionStyles,
start: { height: current + "px" }, start: { height: current + "px" },
end: { height: full + "px" } end: { height: full + "px" }
@@ -3915,7 +3915,7 @@ var require_module_cjs2 = __commonJS({
}, after = () => { }, after = () => {
}) { }) {
let full = el.getBoundingClientRect().height; let full = el.getBoundingClientRect().height;
Alpine20.transition(el, setFunction, { Alpine23.transition(el, setFunction, {
during: transitionStyles, during: transitionStyles,
start: { height: full + "px" }, start: { height: full + "px" },
end: { height: floor + "px" } end: { height: floor + "px" }
@@ -4751,14 +4751,14 @@ var require_module_cjs3 = __commonJS({
module.exports = __toCommonJS(module_exports); module.exports = __toCommonJS(module_exports);
var import_focus_trap = __toESM2(require_focus_trap()); var import_focus_trap = __toESM2(require_focus_trap());
var import_tabbable = __toESM2(require_dist()); var import_tabbable = __toESM2(require_dist());
function src_default(Alpine20) { function src_default(Alpine23) {
let lastFocused; let lastFocused;
let currentFocused; let currentFocused;
window.addEventListener("focusin", () => { window.addEventListener("focusin", () => {
lastFocused = currentFocused; lastFocused = currentFocused;
currentFocused = document.activeElement; currentFocused = document.activeElement;
}); });
Alpine20.magic("focus", (el) => { Alpine23.magic("focus", (el) => {
let within = el; let within = el;
return { return {
__noscroll: false, __noscroll: false,
@@ -4862,7 +4862,7 @@ var require_module_cjs3 = __commonJS({
} }
}; };
}); });
Alpine20.directive("trap", Alpine20.skipDuringClone((el, { expression, modifiers }, { effect, evaluateLater, cleanup }) => { Alpine23.directive("trap", Alpine23.skipDuringClone((el, { expression, modifiers }, { effect, evaluateLater, cleanup }) => {
let evaluator = evaluateLater(expression); let evaluator = evaluateLater(expression);
let oldValue = false; let oldValue = false;
let options = { let options = {
@@ -4980,7 +4980,7 @@ var require_module_cjs4 = __commonJS({
persist: () => src_default persist: () => src_default
}); });
module.exports = __toCommonJS(module_exports); module.exports = __toCommonJS(module_exports);
function src_default(Alpine20) { function src_default(Alpine23) {
let persist3 = () => { let persist3 = () => {
let alias; let alias;
let storage; let storage;
@@ -4995,11 +4995,11 @@ var require_module_cjs4 = __commonJS({
setItem: dummy.set.bind(dummy) setItem: dummy.set.bind(dummy)
}; };
} }
return Alpine20.interceptor((initialValue, getter, setter, path, key) => { return Alpine23.interceptor((initialValue, getter, setter, path, key) => {
let lookup = alias || `_x_${path}`; let lookup = alias || `_x_${path}`;
let initial = storageHas(lookup, storage) ? storageGet(lookup, storage) : initialValue; let initial = storageHas(lookup, storage) ? storageGet(lookup, storage) : initialValue;
setter(initial); setter(initial);
Alpine20.effect(() => { Alpine23.effect(() => {
let value = getter(); let value = getter();
storageSet(lookup, value, storage); storageSet(lookup, value, storage);
setter(value); setter(value);
@@ -5015,12 +5015,12 @@ var require_module_cjs4 = __commonJS({
}; };
}); });
}; };
Object.defineProperty(Alpine20, "$persist", { get: () => persist3() }); Object.defineProperty(Alpine23, "$persist", { get: () => persist3() });
Alpine20.magic("persist", persist3); Alpine23.magic("persist", persist3);
Alpine20.persist = (key, { get, set }, storage = localStorage) => { Alpine23.persist = (key, { get, set }, storage = localStorage) => {
let initial = storageHas(key, storage) ? storageGet(key, storage) : get(); let initial = storageHas(key, storage) ? storageGet(key, storage) : get();
set(initial); set(initial);
Alpine20.effect(() => { Alpine23.effect(() => {
let value = get(); let value = get();
storageSet(key, value, storage); storageSet(key, value, storage);
set(value); set(value);
@@ -5069,8 +5069,8 @@ var require_module_cjs5 = __commonJS({
intersect: () => src_default intersect: () => src_default
}); });
module.exports = __toCommonJS(module_exports); module.exports = __toCommonJS(module_exports);
function src_default(Alpine20) { function src_default(Alpine23) {
Alpine20.directive("intersect", Alpine20.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater, cleanup }) => { Alpine23.directive("intersect", Alpine23.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater, cleanup }) => {
let evaluate = evaluateLater(expression); let evaluate = evaluateLater(expression);
let options = { let options = {
rootMargin: getRootMargin(modifiers), rootMargin: getRootMargin(modifiers),
@@ -5151,8 +5151,8 @@ var require_module_cjs6 = __commonJS({
resize: () => src_default resize: () => src_default
}); });
module.exports = __toCommonJS(module_exports); module.exports = __toCommonJS(module_exports);
function src_default(Alpine20) { function src_default(Alpine23) {
Alpine20.directive("resize", Alpine20.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater, cleanup }) => { Alpine23.directive("resize", Alpine23.skipDuringClone((el, { value, expression, modifiers }, { evaluateLater, cleanup }) => {
let evaluator = evaluateLater(expression); let evaluator = evaluateLater(expression);
let evaluate = (width, height) => { let evaluate = (width, height) => {
evaluator(() => { evaluator(() => {
@@ -6396,20 +6396,20 @@ var require_module_cjs7 = __commonJS({
platform: platformWithCache platform: platformWithCache
}); });
}; };
function src_default(Alpine20) { function src_default(Alpine23) {
Alpine20.magic("anchor", (el) => { Alpine23.magic("anchor", (el) => {
if (!el._x_anchor) if (!el._x_anchor)
throw "Alpine: No x-anchor directive found on element using $anchor..."; throw "Alpine: No x-anchor directive found on element using $anchor...";
return el._x_anchor; return el._x_anchor;
}); });
Alpine20.interceptClone((from, to) => { Alpine23.interceptClone((from, to) => {
if (from && from._x_anchor && !to._x_anchor) { if (from && from._x_anchor && !to._x_anchor) {
to._x_anchor = from._x_anchor; to._x_anchor = from._x_anchor;
} }
}); });
Alpine20.directive("anchor", Alpine20.skipDuringClone((el, { expression, modifiers, value }, { cleanup, evaluate: evaluate2 }) => { Alpine23.directive("anchor", Alpine23.skipDuringClone((el, { expression, modifiers, value }, { cleanup, evaluate: evaluate2 }) => {
let { placement, offsetValue, unstyled } = getOptions(modifiers); let { placement, offsetValue, unstyled } = getOptions(modifiers);
el._x_anchor = Alpine20.reactive({ x: 0, y: 0 }); el._x_anchor = Alpine23.reactive({ x: 0, y: 0 });
let reference = evaluate2(expression); let reference = evaluate2(expression);
if (!reference) if (!reference)
throw "Alpine: no element provided to x-anchor..."; throw "Alpine: no element provided to x-anchor...";
@@ -6784,7 +6784,8 @@ var require_module_cjs8 = __commonJS({
return swapElements(from2, to); return swapElements(from2, to);
} }
let updateChildrenOnly = false; let updateChildrenOnly = false;
if (shouldSkip(updating, from2, to, () => updateChildrenOnly = true)) let skipChildren = false;
if (shouldSkipChildren(updating, () => skipChildren = true, from2, to, () => updateChildrenOnly = true))
return; return;
if (from2.nodeType === 1 && window.Alpine) { if (from2.nodeType === 1 && window.Alpine) {
window.Alpine.cloneNode(from2, to); window.Alpine.cloneNode(from2, to);
@@ -6801,7 +6802,9 @@ var require_module_cjs8 = __commonJS({
patchAttributes(from2, to); patchAttributes(from2, to);
} }
updated(from2, to); updated(from2, to);
patchChildren(from2, to); if (!skipChildren) {
patchChildren(from2, to);
}
} }
function differentElementNamesTypesOrKeys(from2, to) { function differentElementNamesTypesOrKeys(from2, to) {
return from2.nodeType != to.nodeType || from2.nodeName != to.nodeName || getKey(from2) != getKey(to); return from2.nodeType != to.nodeType || from2.nodeName != to.nodeName || getKey(from2) != getKey(to);
@@ -7015,6 +7018,11 @@ var require_module_cjs8 = __commonJS({
hook(...args, () => skip = true); hook(...args, () => skip = true);
return skip; return skip;
} }
function shouldSkipChildren(hook, skipChildren, ...args) {
let skip = false;
hook(...args, () => skip = true, skipChildren);
return skip;
}
var patched = false; var patched = false;
function createElement(html) { function createElement(html) {
const template = document.createElement("template"); const template = document.createElement("template");
@@ -7095,8 +7103,8 @@ var require_module_cjs8 = __commonJS({
to.setAttribute("id", fromId); to.setAttribute("id", fromId);
to.id = fromId; to.id = fromId;
} }
function src_default(Alpine20) { function src_default(Alpine23) {
Alpine20.morph = morph3; Alpine23.morph = morph3;
} }
var module_default = src_default; var module_default = src_default;
} }
@@ -7129,8 +7137,8 @@ var require_module_cjs9 = __commonJS({
stripDown: () => stripDown stripDown: () => stripDown
}); });
module.exports = __toCommonJS(module_exports); module.exports = __toCommonJS(module_exports);
function src_default(Alpine20) { function src_default(Alpine23) {
Alpine20.directive("mask", (el, { value, expression }, { effect, evaluateLater, cleanup }) => { Alpine23.directive("mask", (el, { value, expression }, { effect, evaluateLater, cleanup }) => {
let templateFn = () => expression; let templateFn = () => expression;
let lastInputValue = ""; let lastInputValue = "";
queueMicrotask(() => { queueMicrotask(() => {
@@ -7139,7 +7147,7 @@ var require_module_cjs9 = __commonJS({
effect(() => { effect(() => {
templateFn = (input) => { templateFn = (input) => {
let result; let result;
Alpine20.dontAutoEvaluateFunctions(() => { Alpine23.dontAutoEvaluateFunctions(() => {
evaluator((value2) => { evaluator((value2) => {
result = typeof value2 === "function" ? value2(input) : value2; result = typeof value2 === "function" ? value2(input) : value2;
}, { scope: { }, { scope: {
@@ -8188,6 +8196,7 @@ var aliases = {
"on": "$on", "on": "$on",
"el": "$el", "el": "$el",
"id": "$id", "id": "$id",
"js": "$js",
"get": "$get", "get": "$get",
"set": "$set", "set": "$set",
"call": "$call", "call": "$call",
@@ -8259,6 +8268,14 @@ wireProperty("$el", (component) => {
wireProperty("$id", (component) => { wireProperty("$id", (component) => {
return component.id; return component.id;
}); });
wireProperty("$js", (component) => {
let fn = component.addJsAction.bind(component);
let jsActions = component.getJsActions();
Object.keys(jsActions).forEach((name) => {
fn[name] = component.getJsAction(name);
});
return fn;
});
wireProperty("$set", (component) => async (property, value, live = true) => { wireProperty("$set", (component) => async (property, value, live = true) => {
dataSet(component.reactive, property, value); dataSet(component.reactive, property, value);
if (live) { if (live) {
@@ -8354,6 +8371,7 @@ var Component = class {
this.ephemeral = extractData(deepClone(this.snapshot.data)); this.ephemeral = extractData(deepClone(this.snapshot.data));
this.reactive = Alpine.reactive(this.ephemeral); this.reactive = Alpine.reactive(this.ephemeral);
this.queuedUpdates = {}; this.queuedUpdates = {};
this.jsActions = {};
this.$wire = generateWireObject(this, this.reactive); this.$wire = generateWireObject(this, this.reactive);
this.cleanups = []; this.cleanups = [];
this.processEffects(this.effects); this.processEffects(this.effects);
@@ -8429,6 +8447,18 @@ var Component = class {
} }
el.setAttribute("wire:effects", JSON.stringify(effects)); el.setAttribute("wire:effects", JSON.stringify(effects));
} }
addJsAction(name, action) {
this.jsActions[name] = action;
}
hasJsAction(name) {
return this.jsActions[name] !== void 0;
}
getJsAction(name) {
return this.jsActions[name].bind(this.$wire);
}
getJsActions() {
return this.jsActions;
}
addCleanup(cleanup) { addCleanup(cleanup) {
this.cleanups.push(cleanup); this.cleanups.push(cleanup);
} }
@@ -9111,6 +9141,7 @@ var attributesExemptFromScriptTagHashing = [
]; ];
function swapCurrentPageWithNewHtml(html, andThen) { function swapCurrentPageWithNewHtml(html, andThen) {
let newDocument = new DOMParser().parseFromString(html, "text/html"); let newDocument = new DOMParser().parseFromString(html, "text/html");
let newHtml = newDocument.documentElement;
let newBody = document.adoptNode(newDocument.body); let newBody = document.adoptNode(newDocument.body);
let newHead = document.adoptNode(newDocument.head); let newHead = document.adoptNode(newDocument.head);
oldBodyScriptTagHashes = oldBodyScriptTagHashes.concat(Array.from(document.body.querySelectorAll("script")).map((i) => { oldBodyScriptTagHashes = oldBodyScriptTagHashes.concat(Array.from(document.body.querySelectorAll("script")).map((i) => {
@@ -9118,6 +9149,7 @@ function swapCurrentPageWithNewHtml(html, andThen) {
})); }));
let afterRemoteScriptsHaveLoaded = () => { let afterRemoteScriptsHaveLoaded = () => {
}; };
replaceHtmlAttributes(newHtml);
mergeNewHead(newHead).finally(() => { mergeNewHead(newHead).finally(() => {
afterRemoteScriptsHaveLoaded(); afterRemoteScriptsHaveLoaded();
}); });
@@ -9137,6 +9169,21 @@ function prepNewBodyScriptTagsToRun(newBody, oldBodyScriptTagHashes2) {
i.replaceWith(cloneScriptTag(i)); i.replaceWith(cloneScriptTag(i));
}); });
} }
function replaceHtmlAttributes(newHtmlElement) {
let currentHtmlElement = document.documentElement;
Array.from(newHtmlElement.attributes).forEach((attr) => {
const name = attr.name;
const value = attr.value;
if (currentHtmlElement.getAttribute(name) !== value) {
currentHtmlElement.setAttribute(name, value);
}
});
Array.from(currentHtmlElement.attributes).forEach((attr) => {
if (!newHtmlElement.hasAttribute(attr.name)) {
currentHtmlElement.removeAttribute(attr.name);
}
});
}
function mergeNewHead(newHead) { function mergeNewHead(newHead) {
let children = Array.from(document.head.children); let children = Array.from(document.head.children);
let headChildrenHtmlLookup = children.map((i) => i.outerHTML); let headChildrenHtmlLookup = children.map((i) => i.outerHTML);
@@ -9240,8 +9287,8 @@ var enablePersist = true;
var showProgressBar = true; var showProgressBar = true;
var restoreScroll = true; var restoreScroll = true;
var autofocus = false; var autofocus = false;
function navigate_default(Alpine20) { function navigate_default(Alpine23) {
Alpine20.navigate = (url) => { Alpine23.navigate = (url) => {
let destination = createUrlObjectFromString(url); let destination = createUrlObjectFromString(url);
let prevented = fireEventForOtherLibrariesToHookInto("alpine:navigate", { let prevented = fireEventForOtherLibrariesToHookInto("alpine:navigate", {
url: destination, url: destination,
@@ -9252,11 +9299,11 @@ function navigate_default(Alpine20) {
return; return;
navigateTo(destination); navigateTo(destination);
}; };
Alpine20.navigate.disableProgressBar = () => { Alpine23.navigate.disableProgressBar = () => {
showProgressBar = false; showProgressBar = false;
}; };
Alpine20.addInitSelector(() => `[${Alpine20.prefixed("navigate")}]`); Alpine23.addInitSelector(() => `[${Alpine23.prefixed("navigate")}]`);
Alpine20.directive("navigate", (el, { modifiers }) => { Alpine23.directive("navigate", (el, { modifiers }) => {
let shouldPrefetchOnHover = modifiers.includes("hover"); let shouldPrefetchOnHover = modifiers.includes("hover");
shouldPrefetchOnHover && whenThisLinkIsHoveredFor(el, 60, () => { shouldPrefetchOnHover && whenThisLinkIsHoveredFor(el, 60, () => {
let destination = extractDestinationFromLink(el); let destination = extractDestinationFromLink(el);
@@ -9293,7 +9340,7 @@ function navigate_default(Alpine20) {
showProgressBar && finishAndHideProgressBar(); showProgressBar && finishAndHideProgressBar();
cleanupAlpineElementsOnThePageThatArentInsideAPersistedElement(); cleanupAlpineElementsOnThePageThatArentInsideAPersistedElement();
updateCurrentPageHtmlInHistoryStateForLaterBackButtonClicks(); updateCurrentPageHtmlInHistoryStateForLaterBackButtonClicks();
preventAlpineFromPickingUpDomChanges(Alpine20, (andAfterAllThis) => { preventAlpineFromPickingUpDomChanges(Alpine23, (andAfterAllThis) => {
enablePersist && storePersistantElementsForLater((persistedEl) => { enablePersist && storePersistantElementsForLater((persistedEl) => {
packUpPersistedTeleports(persistedEl); packUpPersistedTeleports(persistedEl);
packUpPersistedPopovers(persistedEl); packUpPersistedPopovers(persistedEl);
@@ -9315,7 +9362,7 @@ function navigate_default(Alpine20) {
setTimeout(() => { setTimeout(() => {
autofocus && autofocusElementsWithTheAutofocusAttribute(); autofocus && autofocusElementsWithTheAutofocusAttribute();
}); });
nowInitializeAlpineOnTheNewPage(Alpine20); nowInitializeAlpineOnTheNewPage(Alpine23);
fireEventForOtherLibrariesToHookInto("alpine:navigated"); fireEventForOtherLibrariesToHookInto("alpine:navigated");
}); });
}); });
@@ -9348,7 +9395,7 @@ function navigate_default(Alpine20) {
storeScrollInformationInHtmlBeforeNavigatingAway(); storeScrollInformationInHtmlBeforeNavigatingAway();
fireEventForOtherLibrariesToHookInto("alpine:navigating"); fireEventForOtherLibrariesToHookInto("alpine:navigating");
updateCurrentPageHtmlInSnapshotCacheForLaterBackButtonClicks(currentPageUrl, currentPageKey); updateCurrentPageHtmlInSnapshotCacheForLaterBackButtonClicks(currentPageUrl, currentPageKey);
preventAlpineFromPickingUpDomChanges(Alpine20, (andAfterAllThis) => { preventAlpineFromPickingUpDomChanges(Alpine23, (andAfterAllThis) => {
enablePersist && storePersistantElementsForLater((persistedEl) => { enablePersist && storePersistantElementsForLater((persistedEl) => {
packUpPersistedTeleports(persistedEl); packUpPersistedTeleports(persistedEl);
packUpPersistedPopovers(persistedEl); packUpPersistedPopovers(persistedEl);
@@ -9363,7 +9410,7 @@ function navigate_default(Alpine20) {
restoreScrollPositionOrScrollToTop(); restoreScrollPositionOrScrollToTop();
andAfterAllThis(() => { andAfterAllThis(() => {
autofocus && autofocusElementsWithTheAutofocusAttribute(); autofocus && autofocusElementsWithTheAutofocusAttribute();
nowInitializeAlpineOnTheNewPage(Alpine20); nowInitializeAlpineOnTheNewPage(Alpine23);
fireEventForOtherLibrariesToHookInto("alpine:navigated"); fireEventForOtherLibrariesToHookInto("alpine:navigated");
}); });
}); });
@@ -9378,10 +9425,10 @@ function fetchHtmlOrUsePrefetchedHtml(fromDestination, callback) {
fetchHtml(fromDestination, callback); fetchHtml(fromDestination, callback);
}); });
} }
function preventAlpineFromPickingUpDomChanges(Alpine20, callback) { function preventAlpineFromPickingUpDomChanges(Alpine23, callback) {
Alpine20.stopObservingMutations(); Alpine23.stopObservingMutations();
callback((afterAllThis) => { callback((afterAllThis) => {
Alpine20.startObservingMutations(); Alpine23.startObservingMutations();
queueMicrotask(() => { queueMicrotask(() => {
afterAllThis(); afterAllThis();
}); });
@@ -9396,8 +9443,8 @@ function fireEventForOtherLibrariesToHookInto(name, detail) {
document.dispatchEvent(event); document.dispatchEvent(event);
return event.defaultPrevented; return event.defaultPrevented;
} }
function nowInitializeAlpineOnTheNewPage(Alpine20) { function nowInitializeAlpineOnTheNewPage(Alpine23) {
Alpine20.initTree(document.body, void 0, (el, skip) => { Alpine23.initTree(document.body, void 0, (el, skip) => {
if (el._x_wasPersisted) if (el._x_wasPersisted)
skip(); skip();
}); });
@@ -9420,8 +9467,8 @@ function cleanupAlpineElementsOnThePageThatArentInsideAPersistedElement() {
} }
// js/plugins/history/index.js // js/plugins/history/index.js
function history2(Alpine20) { function history2(Alpine23) {
Alpine20.magic("queryString", (el, { interceptor }) => { Alpine23.magic("queryString", (el, { interceptor }) => {
let alias; let alias;
let alwaysShow = false; let alwaysShow = false;
let usePush = false; let usePush = false;
@@ -9430,9 +9477,9 @@ function history2(Alpine20) {
let { initial, replace: replace2, push: push2, pop } = track(queryKey, initialSeedValue, alwaysShow); let { initial, replace: replace2, push: push2, pop } = track(queryKey, initialSeedValue, alwaysShow);
setter(initial); setter(initial);
if (!usePush) { if (!usePush) {
Alpine20.effect(() => replace2(getter())); Alpine23.effect(() => replace2(getter()));
} else { } else {
Alpine20.effect(() => push2(getter())); Alpine23.effect(() => push2(getter()));
pop(async (newValue) => { pop(async (newValue) => {
setter(newValue); setter(newValue);
let tillTheEndOfTheMicrotaskQueue = () => Promise.resolve(); let tillTheEndOfTheMicrotaskQueue = () => Promise.resolve();
@@ -9455,7 +9502,7 @@ function history2(Alpine20) {
}; };
}); });
}); });
Alpine20.history = { track }; Alpine23.history = { track };
} }
function track(name, initialSeedValue, alwaysShow = false, except = null) { function track(name, initialSeedValue, alwaysShow = false, except = null) {
let { has, get, set, remove } = queryStringUtils(); let { has, get, set, remove } = queryStringUtils();
@@ -9519,14 +9566,22 @@ function replace(url, key, object) {
if (!state.alpine) if (!state.alpine)
state.alpine = {}; state.alpine = {};
state.alpine[key] = unwrap(object); state.alpine[key] = unwrap(object);
window.history.replaceState(state, "", url.toString()); try {
window.history.replaceState(state, "", url.toString());
} catch (e) {
console.error(e);
}
} }
function push(url, key, object) { function push(url, key, object) {
let state = window.history.state || {}; let state = window.history.state || {};
if (!state.alpine) if (!state.alpine)
state.alpine = {}; state.alpine = {};
state = { alpine: { ...state.alpine, ...{ [key]: unwrap(object) } } }; state = { alpine: { ...state.alpine, ...{ [key]: unwrap(object) } } };
window.history.pushState(state, "", url.toString()); try {
window.history.pushState(state, "", url.toString());
} catch (e) {
console.error(e);
}
} }
function unwrap(object) { function unwrap(object) {
if (object === void 0) if (object === void 0)
@@ -9697,7 +9752,7 @@ function ensureLivewireScriptIsntMisplaced() {
} }
// js/index.js // js/index.js
var import_alpinejs18 = __toESM(require_module_cjs()); var import_alpinejs21 = __toESM(require_module_cjs());
// js/features/supportListeners.js // js/features/supportListeners.js
on("effect", ({ component, effects }) => { on("effect", ({ component, effects }) => {
@@ -9754,7 +9809,7 @@ on("effect", ({ component, effects }) => {
onlyIfScriptHasntBeenRunAlreadyForThisComponent(component, key, () => { onlyIfScriptHasntBeenRunAlreadyForThisComponent(component, key, () => {
let scriptContent = extractScriptTagContent(content); let scriptContent = extractScriptTagContent(content);
import_alpinejs6.default.dontAutoEvaluateFunctions(() => { import_alpinejs6.default.dontAutoEvaluateFunctions(() => {
import_alpinejs6.default.evaluate(component.el, scriptContent, { "$wire": component.$wire }); import_alpinejs6.default.evaluate(component.el, scriptContent, { "$wire": component.$wire, "$js": component.$wire.$js });
}); });
}); });
}); });
@@ -9827,6 +9882,10 @@ function cloneScriptTag2(el) {
// js/features/supportJsEvaluation.js // js/features/supportJsEvaluation.js
var import_alpinejs7 = __toESM(require_module_cjs()); var import_alpinejs7 = __toESM(require_module_cjs());
import_alpinejs7.default.magic("js", (el) => {
let component = closestComponent(el);
return component.$wire.js;
});
on("effect", ({ component, effects }) => { on("effect", ({ component, effects }) => {
let js = effects.js; let js = effects.js;
let xjs = effects.xjs; let xjs = effects.xjs;
@@ -9838,8 +9897,9 @@ on("effect", ({ component, effects }) => {
}); });
} }
if (xjs) { if (xjs) {
xjs.forEach((expression) => { xjs.forEach(({ expression, params }) => {
import_alpinejs7.default.evaluate(component.el, expression); params = Object.values(params);
import_alpinejs7.default.evaluate(component.el, expression, { scope: component.jsActions, params });
}); });
} }
}); });
@@ -9860,10 +9920,10 @@ function morph2(component, el, html) {
to.__livewire = component; to.__livewire = component;
trigger("morph", { el, toEl: to, component }); trigger("morph", { el, toEl: to, component });
import_alpinejs8.default.morph(el, to, { import_alpinejs8.default.morph(el, to, {
updating: (el2, toEl, childrenOnly, skip) => { updating: (el2, toEl, childrenOnly, skip, skipChildren) => {
if (isntElement(el2)) if (isntElement(el2))
return; return;
trigger("morph.updating", { el: el2, toEl, component, skip, childrenOnly }); trigger("morph.updating", { el: el2, toEl, component, skip, childrenOnly, skipChildren });
if (el2.__livewire_replace === true) if (el2.__livewire_replace === true)
el2.innerHTML = toEl.innerHTML; el2.innerHTML = toEl.innerHTML;
if (el2.__livewire_replace_self === true) { if (el2.__livewire_replace_self === true) {
@@ -9874,6 +9934,8 @@ function morph2(component, el, html) {
return skip(); return skip();
if (el2.__livewire_ignore_self === true) if (el2.__livewire_ignore_self === true)
childrenOnly(); childrenOnly();
if (el2.__livewire_ignore_children === true)
return skipChildren();
if (isComponentRootEl(el2) && el2.getAttribute("wire:id") !== component.id) if (isComponentRootEl(el2) && el2.getAttribute("wire:id") !== component.id)
return skip(); return skip();
if (isComponentRootEl(el2)) if (isComponentRootEl(el2))
@@ -10309,6 +10371,14 @@ on("morph.added", ({ el }) => {
el.__addedByMorph = true; el.__addedByMorph = true;
}); });
directive("transition", ({ el, directive: directive2, component, cleanup }) => { directive("transition", ({ el, directive: directive2, component, cleanup }) => {
for (let i = 0; i < el.attributes.length; i++) {
if (el.attributes[i].name.startsWith("wire:show")) {
import_alpinejs11.default.bind(el, {
[directive2.rawName.replace("wire:transition", "x-transition")]: directive2.expression
});
return;
}
}
let visibility = import_alpinejs11.default.reactive({ state: el.__addedByMorph ? false : true }); let visibility = import_alpinejs11.default.reactive({ state: el.__addedByMorph ? false : true });
import_alpinejs11.default.bind(el, { import_alpinejs11.default.bind(el, {
[directive2.rawName.replace("wire:", "x-")]: "", [directive2.rawName.replace("wire:", "x-")]: "",
@@ -10446,8 +10516,10 @@ globalDirective("current", ({ el, directive: directive2, cleanup }) => {
let refreshCurrent = (url) => { let refreshCurrent = (url) => {
if (pathMatches(hrefUrl, url, options)) { if (pathMatches(hrefUrl, url, options)) {
el.classList.add(...classes); el.classList.add(...classes);
el.setAttribute("data-current", "");
} else { } else {
el.classList.remove(...classes); el.classList.remove(...classes);
el.removeAttribute("data-current");
} }
}; };
refreshCurrent(new URL(window.location.href)); refreshCurrent(new URL(window.location.href));
@@ -10735,15 +10807,25 @@ directive("replace", ({ el, directive: directive2 }) => {
directive("ignore", ({ el, directive: directive2 }) => { directive("ignore", ({ el, directive: directive2 }) => {
if (directive2.modifiers.includes("self")) { if (directive2.modifiers.includes("self")) {
el.__livewire_ignore_self = true; el.__livewire_ignore_self = true;
} else if (directive2.modifiers.includes("children")) {
el.__livewire_ignore_children = true;
} else { } else {
el.__livewire_ignore = true; el.__livewire_ignore = true;
} }
}); });
// js/directives/wire-cloak.js
var import_alpinejs15 = __toESM(require_module_cjs());
import_alpinejs15.default.interceptInit((el) => {
if (el.hasAttribute("wire:cloak")) {
import_alpinejs15.default.mutateDom(() => el.removeAttribute("wire:cloak"));
}
});
// js/directives/wire-dirty.js // js/directives/wire-dirty.js
var refreshDirtyStatesByComponent = new WeakBag(); var refreshDirtyStatesByComponent = new WeakBag();
on("commit", ({ component, succeed }) => { on("commit", ({ component, respond }) => {
succeed(() => { respond(() => {
setTimeout(() => { setTimeout(() => {
refreshDirtyStatesByComponent.each(component, (i) => i(false)); refreshDirtyStatesByComponent.each(component, (i) => i(false));
}); });
@@ -10751,7 +10833,6 @@ on("commit", ({ component, succeed }) => {
}); });
directive("dirty", ({ el, directive: directive2, component }) => { directive("dirty", ({ el, directive: directive2, component }) => {
let targets = dirtyTargets(el); let targets = dirtyTargets(el);
let dirty = Alpine.reactive({ state: false });
let oldIsDirty = false; let oldIsDirty = false;
let initialDisplay = el.style.display; let initialDisplay = el.style.display;
let refreshDirtyState = (isDirty) => { let refreshDirtyState = (isDirty) => {
@@ -10790,7 +10871,7 @@ function dirtyTargets(el) {
} }
// js/directives/wire-model.js // js/directives/wire-model.js
var import_alpinejs15 = __toESM(require_module_cjs()); var import_alpinejs16 = __toESM(require_module_cjs());
directive("model", ({ el, directive: directive2, component, cleanup }) => { directive("model", ({ el, directive: directive2, component, cleanup }) => {
let { expression, modifiers } = directive2; let { expression, modifiers } = directive2;
if (!expression) { if (!expression) {
@@ -10808,7 +10889,7 @@ directive("model", ({ el, directive: directive2, component, cleanup }) => {
let isDebounced = modifiers.includes("debounce"); let isDebounced = modifiers.includes("debounce");
let update = expression.startsWith("$parent") ? () => component.$wire.$parent.$commit() : () => component.$wire.$commit(); let update = expression.startsWith("$parent") ? () => component.$wire.$parent.$commit() : () => component.$wire.$commit();
let debouncedUpdate = isTextInput(el) && !isDebounced && isLive ? debounce(update, 150) : update; let debouncedUpdate = isTextInput(el) && !isDebounced && isLive ? debounce(update, 150) : update;
import_alpinejs15.default.bind(el, { import_alpinejs16.default.bind(el, {
["@change"]() { ["@change"]() {
isLazy && update(); isLazy && update();
}, },
@@ -10864,14 +10945,14 @@ function debounce(func, wait) {
} }
// js/directives/wire-init.js // js/directives/wire-init.js
var import_alpinejs16 = __toESM(require_module_cjs()); var import_alpinejs17 = __toESM(require_module_cjs());
directive("init", ({ el, directive: directive2 }) => { directive("init", ({ el, directive: directive2 }) => {
let fullMethod = directive2.expression ?? "$refresh"; let fullMethod = directive2.expression ?? "$refresh";
import_alpinejs16.default.evaluate(el, `$wire.${fullMethod}`); import_alpinejs17.default.evaluate(el, `$wire.${fullMethod}`);
}); });
// js/directives/wire-poll.js // js/directives/wire-poll.js
var import_alpinejs17 = __toESM(require_module_cjs()); var import_alpinejs18 = __toESM(require_module_cjs());
directive("poll", ({ el, directive: directive2 }) => { directive("poll", ({ el, directive: directive2 }) => {
let interval = extractDurationFrom(directive2.modifiers, 2e3); let interval = extractDurationFrom(directive2.modifiers, 2e3);
let { start: start2, pauseWhile, throttleWhile, stopWhen } = poll(() => { let { start: start2, pauseWhile, throttleWhile, stopWhen } = poll(() => {
@@ -10885,7 +10966,7 @@ directive("poll", ({ el, directive: directive2 }) => {
stopWhen(() => theElementIsDisconnected(el)); stopWhen(() => theElementIsDisconnected(el));
}); });
function triggerComponentRequest(el, directive2) { function triggerComponentRequest(el, directive2) {
import_alpinejs17.default.evaluate(el, directive2.expression ? "$wire." + directive2.expression : "$wire.$commit()"); import_alpinejs18.default.evaluate(el, directive2.expression ? "$wire." + directive2.expression : "$wire.$commit()");
} }
function poll(callback, interval = 2e3) { function poll(callback, interval = 2e3) {
let pauseConditions = []; let pauseConditions = [];
@@ -10973,6 +11054,40 @@ function extractDurationFrom(modifiers, defaultDuration) {
return durationInMilliSeconds || defaultDuration; return durationInMilliSeconds || defaultDuration;
} }
// js/directives/wire-show.js
var import_alpinejs19 = __toESM(require_module_cjs());
import_alpinejs19.default.interceptInit((el) => {
for (let i = 0; i < el.attributes.length; i++) {
if (el.attributes[i].name.startsWith("wire:show")) {
let { name, value } = el.attributes[i];
let modifierString = name.split("wire:show")[1];
let expression = value.startsWith("!") ? "!$wire." + value.slice(1).trim() : "$wire." + value.trim();
import_alpinejs19.default.bind(el, {
["x-show" + modifierString]() {
return import_alpinejs19.default.evaluate(el, expression);
}
});
}
}
});
// js/directives/wire-text.js
var import_alpinejs20 = __toESM(require_module_cjs());
import_alpinejs20.default.interceptInit((el) => {
for (let i = 0; i < el.attributes.length; i++) {
if (el.attributes[i].name.startsWith("wire:text")) {
let { name, value } = el.attributes[i];
let modifierString = name.split("wire:text")[1];
let expression = value.startsWith("!") ? "!$wire." + value.slice(1).trim() : "$wire." + value.trim();
import_alpinejs20.default.bind(el, {
["x-text" + modifierString]() {
return import_alpinejs20.default.evaluate(el, expression);
}
});
}
}
});
// js/index.js // js/index.js
var Livewire2 = { var Livewire2 = {
directive, directive,
@@ -10988,7 +11103,7 @@ var Livewire2 = {
dispatch: dispatchGlobal, dispatch: dispatchGlobal,
on: on2, on: on2,
get navigate() { get navigate() {
return import_alpinejs18.default.navigate; return import_alpinejs21.default.navigate;
} }
}; };
var warnAboutMultipleInstancesOf = (entity) => console.warn(`Detected multiple instances of ${entity} running`); var warnAboutMultipleInstancesOf = (entity) => console.warn(`Detected multiple instances of ${entity} running`);
@@ -10997,7 +11112,7 @@ if (window.Livewire)
if (window.Alpine) if (window.Alpine)
warnAboutMultipleInstancesOf("Alpine"); warnAboutMultipleInstancesOf("Alpine");
window.Livewire = Livewire2; window.Livewire = Livewire2;
window.Alpine = import_alpinejs18.default; window.Alpine = import_alpinejs21.default;
if (window.livewireScriptConfig === void 0) { if (window.livewireScriptConfig === void 0) {
window.Alpine.__fromLivewire = true; window.Alpine.__fromLivewire = true;
document.addEventListener("DOMContentLoaded", () => { document.addEventListener("DOMContentLoaded", () => {
@@ -11007,7 +11122,7 @@ if (window.livewireScriptConfig === void 0) {
Livewire2.start(); Livewire2.start();
}); });
} }
var export_Alpine = import_alpinejs18.default; var export_Alpine = import_alpinejs21.default;
export { export {
export_Alpine as Alpine, export_Alpine as Alpine,
Livewire2 as Livewire Livewire2 as Livewire

File diff suppressed because one or more lines are too long

View File

@@ -2295,7 +2295,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
get raw() { get raw() {
return raw; return raw;
}, },
version: "3.14.8", version: "3.14.9",
flushAndStopDeferringMutations, flushAndStopDeferringMutations,
dontAutoEvaluateFunctions, dontAutoEvaluateFunctions,
disableEffectScheduling, disableEffectScheduling,
@@ -4363,6 +4363,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
"on": "$on", "on": "$on",
"el": "$el", "el": "$el",
"id": "$id", "id": "$id",
"js": "$js",
"get": "$get", "get": "$get",
"set": "$set", "set": "$set",
"call": "$call", "call": "$call",
@@ -4434,6 +4435,14 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
wireProperty("$id", (component) => { wireProperty("$id", (component) => {
return component.id; return component.id;
}); });
wireProperty("$js", (component) => {
let fn = component.addJsAction.bind(component);
let jsActions = component.getJsActions();
Object.keys(jsActions).forEach((name) => {
fn[name] = component.getJsAction(name);
});
return fn;
});
wireProperty("$set", (component) => async (property, value, live = true) => { wireProperty("$set", (component) => async (property, value, live = true) => {
dataSet(component.reactive, property, value); dataSet(component.reactive, property, value);
if (live) { if (live) {
@@ -4529,6 +4538,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
this.ephemeral = extractData(deepClone(this.snapshot.data)); this.ephemeral = extractData(deepClone(this.snapshot.data));
this.reactive = Alpine.reactive(this.ephemeral); this.reactive = Alpine.reactive(this.ephemeral);
this.queuedUpdates = {}; this.queuedUpdates = {};
this.jsActions = {};
this.$wire = generateWireObject(this, this.reactive); this.$wire = generateWireObject(this, this.reactive);
this.cleanups = []; this.cleanups = [];
this.processEffects(this.effects); this.processEffects(this.effects);
@@ -4604,6 +4614,18 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} }
el.setAttribute("wire:effects", JSON.stringify(effects)); el.setAttribute("wire:effects", JSON.stringify(effects));
} }
addJsAction(name, action) {
this.jsActions[name] = action;
}
hasJsAction(name) {
return this.jsActions[name] !== void 0;
}
getJsAction(name) {
return this.jsActions[name].bind(this.$wire);
}
getJsActions() {
return this.jsActions;
}
addCleanup(cleanup2) { addCleanup(cleanup2) {
this.cleanups.push(cleanup2); this.cleanups.push(cleanup2);
} }
@@ -7715,6 +7737,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
]; ];
function swapCurrentPageWithNewHtml(html, andThen) { function swapCurrentPageWithNewHtml(html, andThen) {
let newDocument = new DOMParser().parseFromString(html, "text/html"); let newDocument = new DOMParser().parseFromString(html, "text/html");
let newHtml = newDocument.documentElement;
let newBody = document.adoptNode(newDocument.body); let newBody = document.adoptNode(newDocument.body);
let newHead = document.adoptNode(newDocument.head); let newHead = document.adoptNode(newDocument.head);
oldBodyScriptTagHashes = oldBodyScriptTagHashes.concat(Array.from(document.body.querySelectorAll("script")).map((i) => { oldBodyScriptTagHashes = oldBodyScriptTagHashes.concat(Array.from(document.body.querySelectorAll("script")).map((i) => {
@@ -7722,6 +7745,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
})); }));
let afterRemoteScriptsHaveLoaded = () => { let afterRemoteScriptsHaveLoaded = () => {
}; };
replaceHtmlAttributes(newHtml);
mergeNewHead(newHead).finally(() => { mergeNewHead(newHead).finally(() => {
afterRemoteScriptsHaveLoaded(); afterRemoteScriptsHaveLoaded();
}); });
@@ -7741,6 +7765,21 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
i.replaceWith(cloneScriptTag(i)); i.replaceWith(cloneScriptTag(i));
}); });
} }
function replaceHtmlAttributes(newHtmlElement) {
let currentHtmlElement = document.documentElement;
Array.from(newHtmlElement.attributes).forEach((attr) => {
const name = attr.name;
const value = attr.value;
if (currentHtmlElement.getAttribute(name) !== value) {
currentHtmlElement.setAttribute(name, value);
}
});
Array.from(currentHtmlElement.attributes).forEach((attr) => {
if (!newHtmlElement.hasAttribute(attr.name)) {
currentHtmlElement.removeAttribute(attr.name);
}
});
}
function mergeNewHead(newHead) { function mergeNewHead(newHead) {
let children = Array.from(document.head.children); let children = Array.from(document.head.children);
let headChildrenHtmlLookup = children.map((i) => i.outerHTML); let headChildrenHtmlLookup = children.map((i) => i.outerHTML);
@@ -8123,14 +8162,22 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
if (!state.alpine) if (!state.alpine)
state.alpine = {}; state.alpine = {};
state.alpine[key] = unwrap(object); state.alpine[key] = unwrap(object);
window.history.replaceState(state, "", url.toString()); try {
window.history.replaceState(state, "", url.toString());
} catch (e) {
console.error(e);
}
} }
function push(url, key, object) { function push(url, key, object) {
let state = window.history.state || {}; let state = window.history.state || {};
if (!state.alpine) if (!state.alpine)
state.alpine = {}; state.alpine = {};
state = { alpine: { ...state.alpine, ...{ [key]: unwrap(object) } } }; state = { alpine: { ...state.alpine, ...{ [key]: unwrap(object) } } };
window.history.pushState(state, "", url.toString()); try {
window.history.pushState(state, "", url.toString());
} catch (e) {
console.error(e);
}
} }
function unwrap(object) { function unwrap(object) {
if (object === void 0) if (object === void 0)
@@ -8251,7 +8298,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
return swapElements(from2, to); return swapElements(from2, to);
} }
let updateChildrenOnly = false; let updateChildrenOnly = false;
if (shouldSkip(updating, from2, to, () => updateChildrenOnly = true)) let skipChildren = false;
if (shouldSkipChildren(updating, () => skipChildren = true, from2, to, () => updateChildrenOnly = true))
return; return;
if (from2.nodeType === 1 && window.Alpine) { if (from2.nodeType === 1 && window.Alpine) {
window.Alpine.cloneNode(from2, to); window.Alpine.cloneNode(from2, to);
@@ -8268,7 +8316,9 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
patchAttributes(from2, to); patchAttributes(from2, to);
} }
updated(from2, to); updated(from2, to);
patchChildren(from2, to); if (!skipChildren) {
patchChildren(from2, to);
}
} }
function differentElementNamesTypesOrKeys(from2, to) { function differentElementNamesTypesOrKeys(from2, to) {
return from2.nodeType != to.nodeType || from2.nodeName != to.nodeName || getKey(from2) != getKey(to); return from2.nodeType != to.nodeType || from2.nodeName != to.nodeName || getKey(from2) != getKey(to);
@@ -8482,6 +8532,11 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
hook(...args, () => skip = true); hook(...args, () => skip = true);
return skip; return skip;
} }
function shouldSkipChildren(hook, skipChildren, ...args) {
let skip = false;
hook(...args, () => skip = true, skipChildren);
return skip;
}
var patched = false; var patched = false;
function createElement(html) { function createElement(html) {
const template = document.createElement("template"); const template = document.createElement("template");
@@ -8861,7 +8916,7 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
onlyIfScriptHasntBeenRunAlreadyForThisComponent(component, key, () => { onlyIfScriptHasntBeenRunAlreadyForThisComponent(component, key, () => {
let scriptContent = extractScriptTagContent(content); let scriptContent = extractScriptTagContent(content);
module_default.dontAutoEvaluateFunctions(() => { module_default.dontAutoEvaluateFunctions(() => {
module_default.evaluate(component.el, scriptContent, { "$wire": component.$wire }); module_default.evaluate(component.el, scriptContent, { "$wire": component.$wire, "$js": component.$wire.$js });
}); });
}); });
}); });
@@ -8933,6 +8988,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
} }
// js/features/supportJsEvaluation.js // js/features/supportJsEvaluation.js
module_default.magic("js", (el) => {
let component = closestComponent(el);
return component.$wire.js;
});
on2("effect", ({ component, effects }) => { on2("effect", ({ component, effects }) => {
let js = effects.js; let js = effects.js;
let xjs = effects.xjs; let xjs = effects.xjs;
@@ -8944,8 +9003,9 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}); });
} }
if (xjs) { if (xjs) {
xjs.forEach((expression) => { xjs.forEach(({ expression, params }) => {
module_default.evaluate(component.el, expression); params = Object.values(params);
module_default.evaluate(component.el, expression, { scope: component.jsActions, params });
}); });
} }
}); });
@@ -8965,10 +9025,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
to.__livewire = component; to.__livewire = component;
trigger2("morph", { el, toEl: to, component }); trigger2("morph", { el, toEl: to, component });
module_default.morph(el, to, { module_default.morph(el, to, {
updating: (el2, toEl, childrenOnly, skip) => { updating: (el2, toEl, childrenOnly, skip, skipChildren) => {
if (isntElement(el2)) if (isntElement(el2))
return; return;
trigger2("morph.updating", { el: el2, toEl, component, skip, childrenOnly }); trigger2("morph.updating", { el: el2, toEl, component, skip, childrenOnly, skipChildren });
if (el2.__livewire_replace === true) if (el2.__livewire_replace === true)
el2.innerHTML = toEl.innerHTML; el2.innerHTML = toEl.innerHTML;
if (el2.__livewire_replace_self === true) { if (el2.__livewire_replace_self === true) {
@@ -8979,6 +9039,8 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
return skip(); return skip();
if (el2.__livewire_ignore_self === true) if (el2.__livewire_ignore_self === true)
childrenOnly(); childrenOnly();
if (el2.__livewire_ignore_children === true)
return skipChildren();
if (isComponentRootEl(el2) && el2.getAttribute("wire:id") !== component.id) if (isComponentRootEl(el2) && el2.getAttribute("wire:id") !== component.id)
return skip(); return skip();
if (isComponentRootEl(el2)) if (isComponentRootEl(el2))
@@ -9411,6 +9473,14 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
el.__addedByMorph = true; el.__addedByMorph = true;
}); });
directive2("transition", ({ el, directive: directive3, component, cleanup: cleanup2 }) => { directive2("transition", ({ el, directive: directive3, component, cleanup: cleanup2 }) => {
for (let i = 0; i < el.attributes.length; i++) {
if (el.attributes[i].name.startsWith("wire:show")) {
module_default.bind(el, {
[directive3.rawName.replace("wire:transition", "x-transition")]: directive3.expression
});
return;
}
}
let visibility = module_default.reactive({ state: el.__addedByMorph ? false : true }); let visibility = module_default.reactive({ state: el.__addedByMorph ? false : true });
module_default.bind(el, { module_default.bind(el, {
[directive3.rawName.replace("wire:", "x-")]: "", [directive3.rawName.replace("wire:", "x-")]: "",
@@ -9545,8 +9615,10 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
let refreshCurrent = (url) => { let refreshCurrent = (url) => {
if (pathMatches(hrefUrl, url, options)) { if (pathMatches(hrefUrl, url, options)) {
el.classList.add(...classes); el.classList.add(...classes);
el.setAttribute("data-current", "");
} else { } else {
el.classList.remove(...classes); el.classList.remove(...classes);
el.removeAttribute("data-current");
} }
}; };
refreshCurrent(new URL(window.location.href)); refreshCurrent(new URL(window.location.href));
@@ -9834,15 +9906,24 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
directive2("ignore", ({ el, directive: directive3 }) => { directive2("ignore", ({ el, directive: directive3 }) => {
if (directive3.modifiers.includes("self")) { if (directive3.modifiers.includes("self")) {
el.__livewire_ignore_self = true; el.__livewire_ignore_self = true;
} else if (directive3.modifiers.includes("children")) {
el.__livewire_ignore_children = true;
} else { } else {
el.__livewire_ignore = true; el.__livewire_ignore = true;
} }
}); });
// js/directives/wire-cloak.js
module_default.interceptInit((el) => {
if (el.hasAttribute("wire:cloak")) {
module_default.mutateDom(() => el.removeAttribute("wire:cloak"));
}
});
// js/directives/wire-dirty.js // js/directives/wire-dirty.js
var refreshDirtyStatesByComponent = new WeakBag(); var refreshDirtyStatesByComponent = new WeakBag();
on2("commit", ({ component, succeed }) => { on2("commit", ({ component, respond }) => {
succeed(() => { respond(() => {
setTimeout(() => { setTimeout(() => {
refreshDirtyStatesByComponent.each(component, (i) => i(false)); refreshDirtyStatesByComponent.each(component, (i) => i(false));
}); });
@@ -9850,7 +9931,6 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
}); });
directive2("dirty", ({ el, directive: directive3, component }) => { directive2("dirty", ({ el, directive: directive3, component }) => {
let targets = dirtyTargets(el); let targets = dirtyTargets(el);
let dirty = Alpine.reactive({ state: false });
let oldIsDirty = false; let oldIsDirty = false;
let initialDisplay = el.style.display; let initialDisplay = el.style.display;
let refreshDirtyState = (isDirty) => { let refreshDirtyState = (isDirty) => {
@@ -10069,6 +10149,38 @@ ${expression ? 'Expression: "' + expression + '"\n\n' : ""}`, el);
return durationInMilliSeconds || defaultDuration; return durationInMilliSeconds || defaultDuration;
} }
// js/directives/wire-show.js
module_default.interceptInit((el) => {
for (let i = 0; i < el.attributes.length; i++) {
if (el.attributes[i].name.startsWith("wire:show")) {
let { name, value } = el.attributes[i];
let modifierString = name.split("wire:show")[1];
let expression = value.startsWith("!") ? "!$wire." + value.slice(1).trim() : "$wire." + value.trim();
module_default.bind(el, {
["x-show" + modifierString]() {
return module_default.evaluate(el, expression);
}
});
}
}
});
// js/directives/wire-text.js
module_default.interceptInit((el) => {
for (let i = 0; i < el.attributes.length; i++) {
if (el.attributes[i].name.startsWith("wire:text")) {
let { name, value } = el.attributes[i];
let modifierString = name.split("wire:text")[1];
let expression = value.startsWith("!") ? "!$wire." + value.slice(1).trim() : "$wire." + value.trim();
module_default.bind(el, {
["x-text" + modifierString]() {
return module_default.evaluate(el, expression);
}
});
}
}
});
// js/index.js // js/index.js
var Livewire2 = { var Livewire2 = {
directive: directive2, directive: directive2,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
{"/livewire.js":"951e6947"} {"/livewire.js":"df3a17f2"}

View File

@@ -973,10 +973,10 @@ label.form-control {
label.form-control--disabled { label.form-control--disabled {
color: #959495; color: #959495;
pointer-events:none;
cursor: not-allowed; cursor: not-allowed;
} }
/** --------------------------------------- **/ /** --------------------------------------- **/
/** Start checkbox styles to replace iCheck **/ /** Start checkbox styles to replace iCheck **/
/** --------------------------------------- **/ /** --------------------------------------- **/
@@ -1165,6 +1165,11 @@ input[type="radio"]:checked::before {
display: table-row !important; display: table-row !important;
} }
.form-control-static {
padding-top: 0px;
}
td.text-right.text-padding-number-cell { td.text-right.text-padding-number-cell {
padding-right: 30px !important; padding-right: 30px !important;
white-space: nowrap; white-space: nowrap;

View File

@@ -5,7 +5,7 @@ return [
'manage' => 'crwdns6501:0crwdne6501:0', 'manage' => 'crwdns6501:0crwdne6501:0',
'field' => 'crwdns1487:0crwdne1487:0', 'field' => 'crwdns1487:0crwdne1487:0',
'about_fieldsets_title' => 'crwdns1488:0crwdne1488:0', 'about_fieldsets_title' => 'crwdns1488:0crwdne1488:0',
'about_fieldsets_text' => 'crwdns13464:0crwdne13464:0', 'about_fieldsets_text' => 'crwdns13482:0crwdne13482:0',
'custom_format' => 'crwdns6505:0crwdne6505:0', 'custom_format' => 'crwdns6505:0crwdne6505:0',
'encrypt_field' => 'crwdns1792:0crwdne1792:0', 'encrypt_field' => 'crwdns1792:0crwdne1792:0',
'encrypt_field_help' => 'crwdns1683:0crwdne1683:0', 'encrypt_field_help' => 'crwdns1683:0crwdne1683:0',

View File

@@ -55,7 +55,7 @@ return [
'default_eula_text_placeholder' => 'crwdns13174:0crwdne13174:0', 'default_eula_text_placeholder' => 'crwdns13174:0crwdne13174:0',
'default_language' => 'crwdns1581:0crwdne1581:0', 'default_language' => 'crwdns1581:0crwdne1581:0',
'default_eula_help_text' => 'crwdns1260:0crwdne1260:0', 'default_eula_help_text' => 'crwdns1260:0crwdne1260:0',
'acceptance_note' => 'crwdns12186:0crwdne12186:0', 'acceptance_note' => 'crwdns13488:0crwdne13488:0',
'display_asset_name' => 'crwdns828:0crwdne828:0', 'display_asset_name' => 'crwdns828:0crwdne828:0',
'display_checkout_date' => 'crwdns829:0crwdne829:0', 'display_checkout_date' => 'crwdns829:0crwdne829:0',
'display_eol' => 'crwdns1118:0crwdne1118:0', 'display_eol' => 'crwdns1118:0crwdne1118:0',

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'crwdns1635:0crwdne1635:0', 'forgot_password' => 'crwdns1635:0crwdne1635:0',
'ldap_reset_password' => 'crwdns6066:0crwdne6066:0', 'ldap_reset_password' => 'crwdns6066:0crwdne6066:0',
'remember_me' => 'crwdns1636:0crwdne1636:0', 'remember_me' => 'crwdns1636:0crwdne1636:0',
'username_help_top' => 'crwdns6044:0crwdne6044:0', 'username_help_top' => 'crwdns6044:0crwdne6044:0',
'username_help_bottom' => 'crwdns6046:0crwdne6046:0', 'username_help_bottom' => 'crwdns6046:0crwdne6046:0',
'google_login' => 'crwdns12026:0crwdne12026:0', 'google_login' => 'crwdns12026:0crwdne12026:0',
'google_login_failed' => 'crwdns11603:0crwdne11603:0', 'google_login_failed' => 'crwdns11603:0crwdne11603:0',
'invite_password_expires' => 'crwdns13496:0crwdne13496:0',
]; ];

View File

@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'crwdns5988:0crwdne5988:0', 'audit_overdue' => 'crwdns5988:0crwdne5988:0',
'accept' => 'crwdns6016:0crwdne6016:0', 'accept' => 'crwdns6016:0crwdne6016:0',
'i_accept' => 'crwdns6018:0crwdne6018:0', 'i_accept' => 'crwdns6018:0crwdne6018:0',
'i_decline_item' => 'crwdns13490:0crwdne13490:0',
'i_accept_item' => 'crwdns13492:0crwdne13492:0',
'i_decline' => 'crwdns6020:0crwdne6020:0', 'i_decline' => 'crwdns6020:0crwdne6020:0',
'accept_decline' => 'crwdns6163:0crwdne6163:0', 'accept_decline' => 'crwdns6163:0crwdne6163:0',
'sign_tos' => 'crwdns6022:0crwdne6022:0', 'sign_tos' => 'crwdns6022:0crwdne6022:0',
@@ -593,6 +595,7 @@ return [
'version' => 'crwdns13278:0crwdne13278:0', 'version' => 'crwdns13278:0crwdne13278:0',
'build' => 'crwdns13280:0crwdne13280:0', 'build' => 'crwdns13280:0crwdne13280:0',
'footer_credit' => 'crwdns13282:0crwdne13282:0', 'footer_credit' => 'crwdns13282:0crwdne13282:0',
'set_password' => 'crwdns13494:0crwdne13494:0',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [

View File

@@ -8,11 +8,15 @@ return [
'Asset_Checkout_Notification' => 'crwdns11625:0crwdne11625:0', 'Asset_Checkout_Notification' => 'crwdns11625:0crwdne11625:0',
'Confirm_Accessory_Checkin' => 'crwdns5992:0crwdne5992:0', 'Confirm_Accessory_Checkin' => 'crwdns5992:0crwdne5992:0',
'Confirm_Asset_Checkin' => 'crwdns5990:0crwdne5990:0', 'Confirm_Asset_Checkin' => 'crwdns5990:0crwdne5990:0',
'Confirm_component_checkin' => 'crwdns13500:0crwdne13500:0',
'Confirm_accessory_delivery' => 'crwdns5994:0crwdne5994:0', 'Confirm_accessory_delivery' => 'crwdns5994:0crwdne5994:0',
'Confirm_asset_delivery' => 'crwdns5998:0crwdne5998:0', 'Confirm_asset_delivery' => 'crwdns5998:0crwdne5998:0',
'Confirm_consumable_delivery' => 'crwdns6000:0crwdne6000:0', 'Confirm_consumable_delivery' => 'crwdns6000:0crwdne6000:0',
'Confirm_component_delivery' => 'crwdns13502:0crwdne13502:0',
'Confirm_license_delivery' => 'crwdns5996:0crwdne5996:0', 'Confirm_license_delivery' => 'crwdns5996:0crwdne5996:0',
'Consumable_checkout_notification' => 'crwdns12062:0crwdne12062:0', 'Consumable_checkout_notification' => 'crwdns12062:0crwdne12062:0',
'Component_checkout_notification' => 'crwdns13504:0crwdne13504:0',
'Component_checkin_notification' => 'crwdns13506:0crwdne13506:0',
'Days' => 'crwdns1728:0crwdne1728:0', 'Days' => 'crwdns1728:0crwdne1728:0',
'Expected_Checkin_Date' => 'crwdns6012:0crwdne6012:0', 'Expected_Checkin_Date' => 'crwdns6012:0crwdne6012:0',
'Expected_Checkin_Notification' => 'crwdns6030:0crwdne6030:0', 'Expected_Checkin_Notification' => 'crwdns6030:0crwdne6030:0',
@@ -33,7 +37,7 @@ return [
'send_pdf_copy' => 'crwdns13480:0crwdne13480:0', 'send_pdf_copy' => 'crwdns13480:0crwdne13480:0',
'accessory_name' => 'crwdns12732:0crwdne12732:0', 'accessory_name' => 'crwdns12732:0crwdne12732:0',
'additional_notes' => 'crwdns12734:0crwdne12734:0', 'additional_notes' => 'crwdns12734:0crwdne12734:0',
'admin_has_created' => 'crwdns1708:0crwdne1708:0', 'admin_has_created' => 'crwdns13498:0crwdne13498:0',
'asset' => 'crwdns12750:0crwdne12750:0', 'asset' => 'crwdns12750:0crwdne12750:0',
'asset_name' => 'crwdns12716:0crwdne12716:0', 'asset_name' => 'crwdns12716:0crwdne12716:0',
'asset_requested' => 'crwdns1711:0crwdne1711:0', 'asset_requested' => 'crwdns1711:0crwdne1711:0',

View File

@@ -5,7 +5,7 @@ return [
'manage' => 'Manage', 'manage' => 'Manage',
'field' => 'veld', 'field' => 'veld',
'about_fieldsets_title' => 'Oor Fieldsets', 'about_fieldsets_title' => 'Oor Fieldsets',
'about_fieldsets_text' => 'Veldstelle stel jou in staat om groepe van persoonlike velde te skep wat gereeld hergebruik word vir spesifieke tipe bates.', 'about_fieldsets_text' => 'Fieldsets allow you to create groups of custom fields that are frequently re-used for specific asset model types.',
'custom_format' => 'Custom Regex format...', 'custom_format' => 'Custom Regex format...',
'encrypt_field' => 'Enkripteer die waarde van hierdie veld in die databasis', 'encrypt_field' => 'Enkripteer die waarde van hierdie veld in die databasis',
'encrypt_field_help' => 'WAARSKUWING: Om \'n veld te enkripteer, maak dit onondersoekbaar.', 'encrypt_field_help' => 'WAARSKUWING: Om \'n veld te enkripteer, maak dit onondersoekbaar.',

View File

@@ -55,7 +55,7 @@ return [
'default_eula_text_placeholder' => 'Add your default EULA text', 'default_eula_text_placeholder' => 'Add your default EULA text',
'default_language' => 'Verstek taal', 'default_language' => 'Verstek taal',
'default_eula_help_text' => 'U kan ook aangepaste EULA\'s aan spesifieke batekategorieë assosieer.', 'default_eula_help_text' => 'U kan ook aangepaste EULA\'s aan spesifieke batekategorieë assosieer.',
'acceptance_note' => 'Add a note for your decision (Optional)', 'acceptance_note' => 'Add a note for your decision (required if declining)',
'display_asset_name' => 'Wys bate naam', 'display_asset_name' => 'Wys bate naam',
'display_checkout_date' => 'Vertoon Checkout Date', 'display_checkout_date' => 'Vertoon Checkout Date',
'display_eol' => 'Wys EOL in tabelweergawe', 'display_eol' => 'Wys EOL in tabelweergawe',

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'ek het my wagwoord vergeet', 'forgot_password' => 'ek het my wagwoord vergeet',
'ldap_reset_password' => 'Please click here to reset your LDAP password', 'ldap_reset_password' => 'Please click here to reset your LDAP password',
'remember_me' => 'Onthou my', 'remember_me' => 'Onthou my',
'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.', 'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.',
'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ', 'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ',
'google_login' => 'Login with Google Workspace', 'google_login' => 'Login with Google Workspace',
'google_login_failed' => 'Google Login failed, please try again.', 'google_login_failed' => 'Google Login failed, please try again.',
'invite_password_expires' => 'This password reset link will expire on :expire_date. You can use the manual password reset link to receive a new reset token by clicking here',
]; ];

View File

@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'Overdue for Audit', 'audit_overdue' => 'Overdue for Audit',
'accept' => 'Accept :asset', 'accept' => 'Accept :asset',
'i_accept' => 'I accept', 'i_accept' => 'I accept',
'i_decline_item' => 'Decline this item',
'i_accept_item' => 'Accept this item',
'i_decline' => 'I decline', 'i_decline' => 'I decline',
'accept_decline' => 'Accept/Decline', 'accept_decline' => 'Accept/Decline',
'sign_tos' => 'Sign below to indicate that you agree to the terms of service:', 'sign_tos' => 'Sign below to indicate that you agree to the terms of service:',
@@ -594,6 +596,7 @@ return [
'version' => 'Version', 'version' => 'Version',
'build' => 'build', 'build' => 'build',
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.', 'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
'set_password' => 'Set a Password',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [

View File

@@ -8,11 +8,15 @@ return [
'Asset_Checkout_Notification' => 'Asset checked out', 'Asset_Checkout_Notification' => 'Asset checked out',
'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation', 'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation',
'Confirm_Asset_Checkin' => 'Asset checkin confirmation', 'Confirm_Asset_Checkin' => 'Asset checkin confirmation',
'Confirm_component_checkin' => 'Component checkin confirmation',
'Confirm_accessory_delivery' => 'Accessory delivery confirmation', 'Confirm_accessory_delivery' => 'Accessory delivery confirmation',
'Confirm_asset_delivery' => 'Asset delivery confirmation', 'Confirm_asset_delivery' => 'Asset delivery confirmation',
'Confirm_consumable_delivery' => 'Consumable delivery confirmation', 'Confirm_consumable_delivery' => 'Consumable delivery confirmation',
'Confirm_component_delivery' => 'Component delivery confirmation',
'Confirm_license_delivery' => 'License delivery confirmation', 'Confirm_license_delivery' => 'License delivery confirmation',
'Consumable_checkout_notification' => 'Consumable checked out', 'Consumable_checkout_notification' => 'Consumable checked out',
'Component_checkout_notification' => 'Component checked out',
'Component_checkin_notification' => 'Component checked in',
'Days' => 'dae', 'Days' => 'dae',
'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date', 'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date',
'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching', 'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching',
@@ -33,7 +37,7 @@ return [
'send_pdf_copy' => 'Send a copy of this acceptance to my email address', 'send_pdf_copy' => 'Send a copy of this acceptance to my email address',
'accessory_name' => 'Toebehore Naam', 'accessory_name' => 'Toebehore Naam',
'additional_notes' => 'Bykomende aantekeninge', 'additional_notes' => 'Bykomende aantekeninge',
'admin_has_created' => '\'N Administrateur het \'n rekening vir jou op die webtuiste gemaak.', 'admin_has_created' => 'An administrator has created an account for you on the :web website. Please find your username below, and click on the link to set a password.',
'asset' => 'bate', 'asset' => 'bate',
'asset_name' => 'Bate Naam', 'asset_name' => 'Bate Naam',
'asset_requested' => 'Bate aangevra', 'asset_requested' => 'Bate aangevra',

View File

@@ -5,7 +5,7 @@ return [
'manage' => 'Manage', 'manage' => 'Manage',
'field' => 'Field', 'field' => 'Field',
'about_fieldsets_title' => 'About Fieldsets', 'about_fieldsets_title' => 'About Fieldsets',
'about_fieldsets_text' => 'Fieldsets allow you to create groups of custom fields that are frequently re-used used for specific asset model types.', 'about_fieldsets_text' => 'Fieldsets allow you to create groups of custom fields that are frequently re-used for specific asset model types.',
'custom_format' => 'Custom Regex format...', 'custom_format' => 'Custom Regex format...',
'encrypt_field' => 'Encrypt the value of this field in the database', 'encrypt_field' => 'Encrypt the value of this field in the database',
'encrypt_field_help' => 'WARNING: Encrypting a field makes it unsearchable.', 'encrypt_field_help' => 'WARNING: Encrypting a field makes it unsearchable.',

View File

@@ -55,7 +55,7 @@ return [
'default_eula_text_placeholder' => 'Add your default EULA text', 'default_eula_text_placeholder' => 'Add your default EULA text',
'default_language' => 'Default Language', 'default_language' => 'Default Language',
'default_eula_help_text' => 'You can also associate custom EULAs to specific asset categories.', 'default_eula_help_text' => 'You can also associate custom EULAs to specific asset categories.',
'acceptance_note' => 'Add a note for your decision (Optional)', 'acceptance_note' => 'Add a note for your decision (required if declining)',
'display_asset_name' => 'Display Asset Name', 'display_asset_name' => 'Display Asset Name',
'display_checkout_date' => 'Display Checkout Date', 'display_checkout_date' => 'Display Checkout Date',
'display_eol' => 'Display EOL in table view', 'display_eol' => 'Display EOL in table view',

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'I forgot my password', 'forgot_password' => 'I forgot my password',
'ldap_reset_password' => 'Please click here to reset your LDAP password', 'ldap_reset_password' => 'Please click here to reset your LDAP password',
'remember_me' => 'Remember Me', 'remember_me' => 'Remember Me',
'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.', 'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.',
'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ', 'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ',
'google_login' => 'Login with Google Workspace', 'google_login' => 'Login with Google Workspace',
'google_login_failed' => 'Google Login failed, please try again.', 'google_login_failed' => 'Google Login failed, please try again.',
'invite_password_expires' => 'This password reset link will expire on :expire_date. You can use the manual password reset link to receive a new reset token by clicking here',
]; ];

View File

@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'Overdue for Audit', 'audit_overdue' => 'Overdue for Audit',
'accept' => 'Accept :asset', 'accept' => 'Accept :asset',
'i_accept' => 'I accept', 'i_accept' => 'I accept',
'i_decline_item' => 'Decline this item',
'i_accept_item' => 'Accept this item',
'i_decline' => 'I decline', 'i_decline' => 'I decline',
'accept_decline' => 'Accept/Decline', 'accept_decline' => 'Accept/Decline',
'sign_tos' => 'Sign below to indicate that you agree to the terms of service:', 'sign_tos' => 'Sign below to indicate that you agree to the terms of service:',
@@ -594,6 +596,7 @@ return [
'version' => 'Version', 'version' => 'Version',
'build' => 'build', 'build' => 'build',
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.', 'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
'set_password' => 'Set a Password',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [

View File

@@ -8,11 +8,15 @@ return [
'Asset_Checkout_Notification' => 'Asset checked out', 'Asset_Checkout_Notification' => 'Asset checked out',
'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation', 'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation',
'Confirm_Asset_Checkin' => 'Asset checkin confirmation', 'Confirm_Asset_Checkin' => 'Asset checkin confirmation',
'Confirm_component_checkin' => 'Component checkin confirmation',
'Confirm_accessory_delivery' => 'Accessory delivery confirmation', 'Confirm_accessory_delivery' => 'Accessory delivery confirmation',
'Confirm_asset_delivery' => 'Asset delivery confirmation', 'Confirm_asset_delivery' => 'Asset delivery confirmation',
'Confirm_consumable_delivery' => 'Consumable delivery confirmation', 'Confirm_consumable_delivery' => 'Consumable delivery confirmation',
'Confirm_component_delivery' => 'Component delivery confirmation',
'Confirm_license_delivery' => 'License delivery confirmation', 'Confirm_license_delivery' => 'License delivery confirmation',
'Consumable_checkout_notification' => 'Consumable checked out', 'Consumable_checkout_notification' => 'Consumable checked out',
'Component_checkout_notification' => 'Component checked out',
'Component_checkin_notification' => 'Component checked in',
'Days' => 'Days', 'Days' => 'Days',
'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date', 'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date',
'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching', 'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching',
@@ -33,7 +37,7 @@ return [
'send_pdf_copy' => 'Send a copy of this acceptance to my email address', 'send_pdf_copy' => 'Send a copy of this acceptance to my email address',
'accessory_name' => 'Accessory Name', 'accessory_name' => 'Accessory Name',
'additional_notes' => 'Additional Notes', 'additional_notes' => 'Additional Notes',
'admin_has_created' => 'An administrator has created an account for you on the :web website.', 'admin_has_created' => 'An administrator has created an account for you on the :web website. Please find your username below, and click on the link to set a password.',
'asset' => 'ንብረት', 'asset' => 'ንብረት',
'asset_name' => 'Asset Name', 'asset_name' => 'Asset Name',
'asset_requested' => 'Asset requested', 'asset_requested' => 'Asset requested',

View File

@@ -5,7 +5,7 @@ return [
'manage' => 'إدارة', 'manage' => 'إدارة',
'field' => 'حقل', 'field' => 'حقل',
'about_fieldsets_title' => 'حول مجموعة الحقول', 'about_fieldsets_title' => 'حول مجموعة الحقول',
'about_fieldsets_text' => '(مجموعات الحقول) تسمح لك بإنشاء مجموعات من الحقول اللتي يمكن إعادة إستخدامها مع موديل محدد.', 'about_fieldsets_text' => 'مجموعات الحقول تسمح لك بإنشاء مجموعات من الحقول المخصصة التي يعاد استخدامها في كثير من الأحيان لأنواع معينة من نماذج الأصول.',
'custom_format' => 'تنسيق Regex المخصص...', 'custom_format' => 'تنسيق Regex المخصص...',
'encrypt_field' => 'تشفير قيمة هذا الحقل في قاعدة البيانات', 'encrypt_field' => 'تشفير قيمة هذا الحقل في قاعدة البيانات',
'encrypt_field_help' => 'تحذير: تشفير الحقل يجعله غير قابل للبحث.', 'encrypt_field_help' => 'تحذير: تشفير الحقل يجعله غير قابل للبحث.',

View File

@@ -55,7 +55,7 @@ return [
'default_eula_text_placeholder' => 'Add your default EULA text', 'default_eula_text_placeholder' => 'Add your default EULA text',
'default_language' => 'اللغة الافتراضية', 'default_language' => 'اللغة الافتراضية',
'default_eula_help_text' => 'يمكنك أيضا ربط (اتفاقية ترخيص المستخدم) لاصناف محددة من الاصول.', 'default_eula_help_text' => 'يمكنك أيضا ربط (اتفاقية ترخيص المستخدم) لاصناف محددة من الاصول.',
'acceptance_note' => 'Add a note for your decision (Optional)', 'acceptance_note' => 'Add a note for your decision (required if declining)',
'display_asset_name' => 'عرض اسم مادة العرض', 'display_asset_name' => 'عرض اسم مادة العرض',
'display_checkout_date' => 'عرض تاريخ الخروج', 'display_checkout_date' => 'عرض تاريخ الخروج',
'display_eol' => 'عرض نهاية العمر على شكل جدول', 'display_eol' => 'عرض نهاية العمر على شكل جدول',

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'نسيت كلمة المرور', 'forgot_password' => 'نسيت كلمة المرور',
'ldap_reset_password' => 'الرجاء النقر هنا لإعادة تعيين كلمة مرور LDAP', 'ldap_reset_password' => 'الرجاء النقر هنا لإعادة تعيين كلمة مرور LDAP',
'remember_me' => 'تذكرني', 'remember_me' => 'تذكرني',
'username_help_top' => 'أدخل اسم المستخدم الخاص بك <strong></strong> ليتم إرسال رابط إعادة تعيين كلمة المرور إلى البريد الإلكتروني.', 'username_help_top' => 'أدخل اسم المستخدم الخاص بك <strong></strong> ليتم إرسال رابط إعادة تعيين كلمة المرور إلى البريد الإلكتروني.',
'username_help_bottom' => 'قد يكون اسم المستخدم وعنوان البريد الإلكتروني الخاصين بك متماثلين، ولكن قد لا يكونا كذلك، بناءً على الإعدادات الخاصة بك. إذا كنت لا تستطيع تذكر اسم المستخدم الخاص بك، اتصل بالمسؤول. لن يتم إرسال رابط إعادة تعيين كلمة المرور عبر البريد الإلكتروني إلى أسماء المستخدمين التي لا تحتوي على عنوان بريد إلكتروني مرتبط بها ', 'username_help_bottom' => 'قد يكون اسم المستخدم وعنوان البريد الإلكتروني الخاصين بك متماثلين، ولكن قد لا يكونا كذلك، بناءً على الإعدادات الخاصة بك. إذا كنت لا تستطيع تذكر اسم المستخدم الخاص بك، اتصل بالمسؤول. لن يتم إرسال رابط إعادة تعيين كلمة المرور عبر البريد الإلكتروني إلى أسماء المستخدمين التي لا تحتوي على عنوان بريد إلكتروني مرتبط بها ',
'google_login' => 'تسجيل الدخول باستخدام مساحة عمل جوجل', 'google_login' => 'تسجيل الدخول باستخدام مساحة عمل جوجل',
'google_login_failed' => 'فشل تسجيل دخول جوجل، الرجاء المحاولة مرة أخرى.', 'google_login_failed' => 'فشل تسجيل دخول جوجل، الرجاء المحاولة مرة أخرى.',
'invite_password_expires' => 'This password reset link will expire on :expire_date. You can use the manual password reset link to receive a new reset token by clicking here',
]; ];

View File

@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'مراجعة الحسابات المتأخرة', 'audit_overdue' => 'مراجعة الحسابات المتأخرة',
'accept' => 'قبول :asset', 'accept' => 'قبول :asset',
'i_accept' => 'قبول', 'i_accept' => 'قبول',
'i_decline_item' => 'Decline this item',
'i_accept_item' => 'Accept this item',
'i_decline' => 'أنا أرفض', 'i_decline' => 'أنا أرفض',
'accept_decline' => 'قبول/رفض', 'accept_decline' => 'قبول/رفض',
'sign_tos' => 'قم بتسجيل الدخول أدناه للإشارة إلى أنك توافق على شروط الخدمة:', 'sign_tos' => 'قم بتسجيل الدخول أدناه للإشارة إلى أنك توافق على شروط الخدمة:',
@@ -594,6 +596,7 @@ return [
'version' => 'Version', 'version' => 'Version',
'build' => 'build', 'build' => 'build',
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.', 'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
'set_password' => 'Set a Password',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [

View File

@@ -8,11 +8,15 @@ return [
'Asset_Checkout_Notification' => 'تم إخراج الأصل', 'Asset_Checkout_Notification' => 'تم إخراج الأصل',
'Confirm_Accessory_Checkin' => 'تأكيد تسجيل الأصول', 'Confirm_Accessory_Checkin' => 'تأكيد تسجيل الأصول',
'Confirm_Asset_Checkin' => 'تأكيد تسجيل الأصول', 'Confirm_Asset_Checkin' => 'تأكيد تسجيل الأصول',
'Confirm_component_checkin' => 'Component checkin confirmation',
'Confirm_accessory_delivery' => 'تأكيد توصيل الأصول', 'Confirm_accessory_delivery' => 'تأكيد توصيل الأصول',
'Confirm_asset_delivery' => 'تأكيد تسليم الأصول', 'Confirm_asset_delivery' => 'تأكيد تسليم الأصول',
'Confirm_consumable_delivery' => 'تأكيد التسليم المستهلكة', 'Confirm_consumable_delivery' => 'تأكيد التسليم المستهلكة',
'Confirm_component_delivery' => 'Component delivery confirmation',
'Confirm_license_delivery' => 'تأكيد توصيل الرخصة', 'Confirm_license_delivery' => 'تأكيد توصيل الرخصة',
'Consumable_checkout_notification' => 'تم فحص المواد المستهلكة', 'Consumable_checkout_notification' => 'تم فحص المواد المستهلكة',
'Component_checkout_notification' => 'Component checked out',
'Component_checkin_notification' => 'Component checked in',
'Days' => 'أيام', 'Days' => 'أيام',
'Expected_Checkin_Date' => 'من المقرر أن يتم التحقق من الأصول التي تم إخراجها إليك في :date', 'Expected_Checkin_Date' => 'من المقرر أن يتم التحقق من الأصول التي تم إخراجها إليك في :date',
'Expected_Checkin_Notification' => 'تذكير: تاريخ تحقق :name يقترب من الموعد النهائي', 'Expected_Checkin_Notification' => 'تذكير: تاريخ تحقق :name يقترب من الموعد النهائي',
@@ -33,7 +37,7 @@ return [
'send_pdf_copy' => 'Send a copy of this acceptance to my email address', 'send_pdf_copy' => 'Send a copy of this acceptance to my email address',
'accessory_name' => 'اسم الملحق', 'accessory_name' => 'اسم الملحق',
'additional_notes' => 'ملاحظات إضافية', 'additional_notes' => 'ملاحظات إضافية',
'admin_has_created' => 'قام مسؤول بإنشاء حساب لك على الموقع :web.', 'admin_has_created' => 'An administrator has created an account for you on the :web website. Please find your username below, and click on the link to set a password.',
'asset' => 'أصل', 'asset' => 'أصل',
'asset_name' => 'اسم الأصل', 'asset_name' => 'اسم الأصل',
'asset_requested' => 'تم طلب مادة العرض', 'asset_requested' => 'تم طلب مادة العرض',

View File

@@ -5,7 +5,7 @@ return [
'manage' => 'Управление', 'manage' => 'Управление',
'field' => 'Поле', 'field' => 'Поле',
'about_fieldsets_title' => 'Относно Fieldsets', 'about_fieldsets_title' => 'Относно Fieldsets',
'about_fieldsets_text' => 'Fieldsets позволяват създаването на групи от персонализирани полета, които се използват и преизползват често за специфични типове модели на активи.', 'about_fieldsets_text' => '"Група от полета" позволяват създаването на групи от персонализирани полета, които се използват и преизползват често за специфични типове модели на активи.',
'custom_format' => 'Персонализиран формат...', 'custom_format' => 'Персонализиран формат...',
'encrypt_field' => 'Шифроване на стойността на това поле в базата данни', 'encrypt_field' => 'Шифроване на стойността на това поле в базата данни',
'encrypt_field_help' => 'ВНИМАНИЕ: Шифроване на поле го прави невалидно за търсене.', 'encrypt_field_help' => 'ВНИМАНИЕ: Шифроване на поле го прави невалидно за търсене.',

View File

@@ -55,7 +55,7 @@ return [
'default_eula_text_placeholder' => 'Добавете ваш EULA', 'default_eula_text_placeholder' => 'Добавете ваш EULA',
'default_language' => 'Език по подразбиране', 'default_language' => 'Език по подразбиране',
'default_eula_help_text' => 'Можете да асоциирате специфична EULA към всяка избрана категория.', 'default_eula_help_text' => 'Можете да асоциирате специфична EULA към всяка избрана категория.',
'acceptance_note' => 'Добавете бележка за вашето решение (По желание)', 'acceptance_note' => 'Add a note for your decision (required if declining)',
'display_asset_name' => 'Визуализиране на актив', 'display_asset_name' => 'Визуализиране на актив',
'display_checkout_date' => 'Визуализиране на дата на изписване', 'display_checkout_date' => 'Визуализиране на дата на изписване',
'display_eol' => 'Визуализиране на EOL в таблиците', 'display_eol' => 'Визуализиране на EOL в таблиците',

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'Забравих си паролата', 'forgot_password' => 'Забравих си паролата',
'ldap_reset_password' => 'Щракнете тук, за да нулирате вашата LDAP парола', 'ldap_reset_password' => 'Щракнете тук, за да нулирате вашата LDAP парола',
'remember_me' => 'Запомни ме', 'remember_me' => 'Запомни ме',
'username_help_top' => 'Въведете вашето <strong>потребителско име</strong> за да получите линк за смяна на парола.', 'username_help_top' => 'Въведете вашето <strong>потребителско име</strong> за да получите линк за смяна на парола.',
'username_help_bottom' => 'Вашето потребителско име и е-майл адрес <em>може да</em> са еднакви или да не са, зависимост от вашата конфигурация. Ако не помните вашето потребителско име се свържете с Администратора. <br><br><strong>Потребители които нямат въведен е-майл адрес няма да получат линк за смяна на парола.</strong> ', 'username_help_bottom' => 'Вашето потребителско име и е-майл адрес <em>може да</em> са еднакви или да не са, зависимост от вашата конфигурация. Ако не помните вашето потребителско име се свържете с Администратора. <br><br><strong>Потребители които нямат въведен е-майл адрес няма да получат линк за смяна на парола.</strong> ',
'google_login' => 'Вход с Google Workspace', 'google_login' => 'Вход с Google Workspace',
'google_login_failed' => 'Неуспешен вход с Google Login, пробвайте отново.', 'google_login_failed' => 'Неуспешен вход с Google Login, пробвайте отново.',
'invite_password_expires' => 'This password reset link will expire on :expire_date. You can use the manual password reset link to receive a new reset token by clicking here',
]; ];

View File

@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'Просрочен Одит', 'audit_overdue' => 'Просрочен Одит',
'accept' => 'Приеми :asset', 'accept' => 'Приеми :asset',
'i_accept' => 'Съгласен съм', 'i_accept' => 'Съгласен съм',
'i_decline_item' => 'Decline this item',
'i_accept_item' => 'Accept this item',
'i_decline' => 'Отказ', 'i_decline' => 'Отказ',
'accept_decline' => 'Премане/отказване', 'accept_decline' => 'Премане/отказване',
'sign_tos' => 'Подпишете се за да се съгласите с условията за ползване:', 'sign_tos' => 'Подпишете се за да се съгласите с условията за ползване:',
@@ -594,6 +596,7 @@ return [
'version' => 'Version', 'version' => 'Version',
'build' => 'build', 'build' => 'build',
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.', 'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
'set_password' => 'Set a Password',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [

View File

@@ -8,11 +8,15 @@ return [
'Asset_Checkout_Notification' => 'Актива е изписан', 'Asset_Checkout_Notification' => 'Актива е изписан',
'Confirm_Accessory_Checkin' => 'Потвърждение при връщане на аксесоар', 'Confirm_Accessory_Checkin' => 'Потвърждение при връщане на аксесоар',
'Confirm_Asset_Checkin' => 'Потвърждение при връщане на актив', 'Confirm_Asset_Checkin' => 'Потвърждение при връщане на актив',
'Confirm_component_checkin' => 'Component checkin confirmation',
'Confirm_accessory_delivery' => 'Потвърждение при доставка на аксесоар', 'Confirm_accessory_delivery' => 'Потвърждение при доставка на аксесоар',
'Confirm_asset_delivery' => 'Потвърждение при доставка на актив', 'Confirm_asset_delivery' => 'Потвърждение при доставка на актив',
'Confirm_consumable_delivery' => 'Потвърждение при доставка на консуматив', 'Confirm_consumable_delivery' => 'Потвърждение при доставка на консуматив',
'Confirm_component_delivery' => 'Component delivery confirmation',
'Confirm_license_delivery' => 'Потвърждение при доставка на лиценз', 'Confirm_license_delivery' => 'Потвърждение при доставка на лиценз',
'Consumable_checkout_notification' => 'Изписани консумативи', 'Consumable_checkout_notification' => 'Изписани консумативи',
'Component_checkout_notification' => 'Component checked out',
'Component_checkin_notification' => 'Component checked in',
'Days' => 'Дни', 'Days' => 'Дни',
'Expected_Checkin_Date' => 'Наближава срока за връщане на актив който е заведен на Вас, трябва да се върна на :date', 'Expected_Checkin_Date' => 'Наближава срока за връщане на актив който е заведен на Вас, трябва да се върна на :date',
'Expected_Checkin_Notification' => 'Напомняне: :name крайната дата за вписване наближава', 'Expected_Checkin_Notification' => 'Напомняне: :name крайната дата за вписване наближава',
@@ -33,7 +37,7 @@ return [
'send_pdf_copy' => 'Send a copy of this acceptance to my email address', 'send_pdf_copy' => 'Send a copy of this acceptance to my email address',
'accessory_name' => 'Аксесоар', 'accessory_name' => 'Аксесоар',
'additional_notes' => 'Допълнителни бележки', 'additional_notes' => 'Допълнителни бележки',
'admin_has_created' => 'Администратор е създал акаунт за вас на :web website.', 'admin_has_created' => 'An administrator has created an account for you on the :web website. Please find your username below, and click on the link to set a password.',
'asset' => 'Актив', 'asset' => 'Актив',
'asset_name' => 'Име на актив', 'asset_name' => 'Име на актив',
'asset_requested' => 'Заявка за актив', 'asset_requested' => 'Заявка за актив',

View File

@@ -5,7 +5,7 @@ return [
'manage' => 'Manage', 'manage' => 'Manage',
'field' => 'Field', 'field' => 'Field',
'about_fieldsets_title' => 'About Fieldsets', 'about_fieldsets_title' => 'About Fieldsets',
'about_fieldsets_text' => 'Fieldsets allow you to create groups of custom fields that are frequently re-used used for specific asset model types.', 'about_fieldsets_text' => 'Fieldsets allow you to create groups of custom fields that are frequently re-used for specific asset model types.',
'custom_format' => 'Custom Regex format...', 'custom_format' => 'Custom Regex format...',
'encrypt_field' => 'Encrypt the value of this field in the database', 'encrypt_field' => 'Encrypt the value of this field in the database',
'encrypt_field_help' => 'WARNING: Encrypting a field makes it unsearchable.', 'encrypt_field_help' => 'WARNING: Encrypting a field makes it unsearchable.',

View File

@@ -55,7 +55,7 @@ return [
'default_eula_text_placeholder' => 'Add your default EULA text', 'default_eula_text_placeholder' => 'Add your default EULA text',
'default_language' => 'Default Language', 'default_language' => 'Default Language',
'default_eula_help_text' => 'You can also associate custom EULAs to specific asset categories.', 'default_eula_help_text' => 'You can also associate custom EULAs to specific asset categories.',
'acceptance_note' => 'Add a note for your decision (Optional)', 'acceptance_note' => 'Add a note for your decision (required if declining)',
'display_asset_name' => 'Display Asset Name', 'display_asset_name' => 'Display Asset Name',
'display_checkout_date' => 'Display Checkout Date', 'display_checkout_date' => 'Display Checkout Date',
'display_eol' => 'Display EOL in table view', 'display_eol' => 'Display EOL in table view',

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'I forgot my password', 'forgot_password' => 'I forgot my password',
'ldap_reset_password' => 'Please click here to reset your LDAP password', 'ldap_reset_password' => 'Please click here to reset your LDAP password',
'remember_me' => 'Remember Me', 'remember_me' => 'Remember Me',
'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.', 'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.',
'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ', 'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ',
'google_login' => 'Login with Google Workspace', 'google_login' => 'Login with Google Workspace',
'google_login_failed' => 'Google Login failed, please try again.', 'google_login_failed' => 'Google Login failed, please try again.',
'invite_password_expires' => 'This password reset link will expire on :expire_date. You can use the manual password reset link to receive a new reset token by clicking here',
]; ];

View File

@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'Overdue for Audit', 'audit_overdue' => 'Overdue for Audit',
'accept' => 'Acceptar :recurs', 'accept' => 'Acceptar :recurs',
'i_accept' => 'I accept', 'i_accept' => 'I accept',
'i_decline_item' => 'Decline this item',
'i_accept_item' => 'Accept this item',
'i_decline' => 'I decline', 'i_decline' => 'I decline',
'accept_decline' => 'Accept/Decline', 'accept_decline' => 'Accept/Decline',
'sign_tos' => 'Sign below to indicate that you agree to the terms of service:', 'sign_tos' => 'Sign below to indicate that you agree to the terms of service:',
@@ -594,6 +596,7 @@ return [
'version' => 'Version', 'version' => 'Version',
'build' => 'build', 'build' => 'build',
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.', 'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
'set_password' => 'Set a Password',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [

View File

@@ -8,11 +8,15 @@ return [
'Asset_Checkout_Notification' => 'Asset checked out', 'Asset_Checkout_Notification' => 'Asset checked out',
'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation', 'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation',
'Confirm_Asset_Checkin' => 'Asset checkin confirmation', 'Confirm_Asset_Checkin' => 'Asset checkin confirmation',
'Confirm_component_checkin' => 'Component checkin confirmation',
'Confirm_accessory_delivery' => 'Accessory delivery confirmation', 'Confirm_accessory_delivery' => 'Accessory delivery confirmation',
'Confirm_asset_delivery' => 'Asset delivery confirmation', 'Confirm_asset_delivery' => 'Asset delivery confirmation',
'Confirm_consumable_delivery' => 'Consumable delivery confirmation', 'Confirm_consumable_delivery' => 'Consumable delivery confirmation',
'Confirm_component_delivery' => 'Component delivery confirmation',
'Confirm_license_delivery' => 'License delivery confirmation', 'Confirm_license_delivery' => 'License delivery confirmation',
'Consumable_checkout_notification' => 'Consumable checked out', 'Consumable_checkout_notification' => 'Consumable checked out',
'Component_checkout_notification' => 'Component checked out',
'Component_checkin_notification' => 'Component checked in',
'Days' => 'Days', 'Days' => 'Days',
'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date', 'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date',
'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching', 'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching',
@@ -33,7 +37,7 @@ return [
'send_pdf_copy' => 'Send a copy of this acceptance to my email address', 'send_pdf_copy' => 'Send a copy of this acceptance to my email address',
'accessory_name' => 'Accessory Name', 'accessory_name' => 'Accessory Name',
'additional_notes' => 'Additional Notes', 'additional_notes' => 'Additional Notes',
'admin_has_created' => 'An administrator has created an account for you on the :web website.', 'admin_has_created' => 'An administrator has created an account for you on the :web website. Please find your username below, and click on the link to set a password.',
'asset' => 'Recurs', 'asset' => 'Recurs',
'asset_name' => 'Asset Name', 'asset_name' => 'Asset Name',
'asset_requested' => 'Asset requested', 'asset_requested' => 'Asset requested',

View File

@@ -5,7 +5,7 @@ return [
'manage' => 'Manage', 'manage' => 'Manage',
'field' => 'Field', 'field' => 'Field',
'about_fieldsets_title' => 'About Fieldsets', 'about_fieldsets_title' => 'About Fieldsets',
'about_fieldsets_text' => 'Fieldsets allow you to create groups of custom fields that are frequently re-used used for specific asset model types.', 'about_fieldsets_text' => 'Fieldsets allow you to create groups of custom fields that are frequently re-used for specific asset model types.',
'custom_format' => 'Custom Regex format...', 'custom_format' => 'Custom Regex format...',
'encrypt_field' => 'Encrypt the value of this field in the database', 'encrypt_field' => 'Encrypt the value of this field in the database',
'encrypt_field_help' => 'WARNING: Encrypting a field makes it unsearchable.', 'encrypt_field_help' => 'WARNING: Encrypting a field makes it unsearchable.',

View File

@@ -55,7 +55,7 @@ return [
'default_eula_text_placeholder' => 'Add your default EULA text', 'default_eula_text_placeholder' => 'Add your default EULA text',
'default_language' => 'Default Language', 'default_language' => 'Default Language',
'default_eula_help_text' => 'You can also associate custom EULAs to specific asset categories.', 'default_eula_help_text' => 'You can also associate custom EULAs to specific asset categories.',
'acceptance_note' => 'Add a note for your decision (Optional)', 'acceptance_note' => 'Add a note for your decision (required if declining)',
'display_asset_name' => 'Display Asset Name', 'display_asset_name' => 'Display Asset Name',
'display_checkout_date' => 'Display Checkout Date', 'display_checkout_date' => 'Display Checkout Date',
'display_eol' => 'Display EOL in table view', 'display_eol' => 'Display EOL in table view',

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'I forgot my password', 'forgot_password' => 'I forgot my password',
'ldap_reset_password' => 'Please click here to reset your LDAP password', 'ldap_reset_password' => 'Please click here to reset your LDAP password',
'remember_me' => 'Remember Me', 'remember_me' => 'Remember Me',
'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.', 'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.',
'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ', 'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ',
'google_login' => 'Login with Google Workspace', 'google_login' => 'Login with Google Workspace',
'google_login_failed' => 'Google Login failed, please try again.', 'google_login_failed' => 'Google Login failed, please try again.',
'invite_password_expires' => 'This password reset link will expire on :expire_date. You can use the manual password reset link to receive a new reset token by clicking here',
]; ];

View File

@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'Overdue for Audit', 'audit_overdue' => 'Overdue for Audit',
'accept' => 'Accept :asset', 'accept' => 'Accept :asset',
'i_accept' => 'I accept', 'i_accept' => 'I accept',
'i_decline_item' => 'Decline this item',
'i_accept_item' => 'Accept this item',
'i_decline' => 'I decline', 'i_decline' => 'I decline',
'accept_decline' => 'Accept/Decline', 'accept_decline' => 'Accept/Decline',
'sign_tos' => 'Sign below to indicate that you agree to the terms of service:', 'sign_tos' => 'Sign below to indicate that you agree to the terms of service:',
@@ -594,6 +596,7 @@ return [
'version' => 'Version', 'version' => 'Version',
'build' => 'build', 'build' => 'build',
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.', 'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
'set_password' => 'Set a Password',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [

View File

@@ -8,11 +8,15 @@ return [
'Asset_Checkout_Notification' => 'Asset checked out', 'Asset_Checkout_Notification' => 'Asset checked out',
'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation', 'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation',
'Confirm_Asset_Checkin' => 'Asset checkin confirmation', 'Confirm_Asset_Checkin' => 'Asset checkin confirmation',
'Confirm_component_checkin' => 'Component checkin confirmation',
'Confirm_accessory_delivery' => 'Accessory delivery confirmation', 'Confirm_accessory_delivery' => 'Accessory delivery confirmation',
'Confirm_asset_delivery' => 'Asset delivery confirmation', 'Confirm_asset_delivery' => 'Asset delivery confirmation',
'Confirm_consumable_delivery' => 'Consumable delivery confirmation', 'Confirm_consumable_delivery' => 'Consumable delivery confirmation',
'Confirm_component_delivery' => 'Component delivery confirmation',
'Confirm_license_delivery' => 'License delivery confirmation', 'Confirm_license_delivery' => 'License delivery confirmation',
'Consumable_checkout_notification' => 'Consumable checked out', 'Consumable_checkout_notification' => 'Consumable checked out',
'Component_checkout_notification' => 'Component checked out',
'Component_checkin_notification' => 'Component checked in',
'Days' => 'Days', 'Days' => 'Days',
'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date', 'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date',
'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching', 'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching',
@@ -33,7 +37,7 @@ return [
'send_pdf_copy' => 'Send a copy of this acceptance to my email address', 'send_pdf_copy' => 'Send a copy of this acceptance to my email address',
'accessory_name' => 'Accessory Name', 'accessory_name' => 'Accessory Name',
'additional_notes' => 'Additional Notes', 'additional_notes' => 'Additional Notes',
'admin_has_created' => 'An administrator has created an account for you on the :web website.', 'admin_has_created' => 'An administrator has created an account for you on the :web website. Please find your username below, and click on the link to set a password.',
'asset' => 'Asset', 'asset' => 'Asset',
'asset_name' => 'Asset Name', 'asset_name' => 'Asset Name',
'asset_requested' => 'Asset requested', 'asset_requested' => 'Asset requested',

View File

@@ -57,7 +57,7 @@ return [
'default_eula_text_placeholder' => 'Přidat výchozí text EULA', 'default_eula_text_placeholder' => 'Přidat výchozí text EULA',
'default_language' => 'Výchozí jazyk', 'default_language' => 'Výchozí jazyk',
'default_eula_help_text' => 'Můžete také spojit vlastní EULA se specifickými kategoriemi majetku.', 'default_eula_help_text' => 'Můžete také spojit vlastní EULA se specifickými kategoriemi majetku.',
'acceptance_note' => 'Přidat poznámku k vašemu rozhodnutí (nepovinné)', 'acceptance_note' => 'Add a note for your decision (required if declining)',
'display_asset_name' => 'Zobrazit název majetku', 'display_asset_name' => 'Zobrazit název majetku',
'display_checkout_date' => 'Zobrazit den převzetí', 'display_checkout_date' => 'Zobrazit den převzetí',
'display_eol' => 'Zobrazit EOL v tabulkovém zobrazení', 'display_eol' => 'Zobrazit EOL v tabulkovém zobrazení',

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'Zapomněl jsem heslo', 'forgot_password' => 'Zapomněl jsem heslo',
'ldap_reset_password' => 'Prosím klikněte zde pro obnovu vašeho LDAP hesla', 'ldap_reset_password' => 'Prosím klikněte zde pro obnovu vašeho LDAP hesla',
'remember_me' => 'Pamatovat si mě', 'remember_me' => 'Pamatovat si mě',
'username_help_top' => 'Zadejte své <strong>uživatelské jméno</strong> pro zaslání e-mailu s odkazem pro obnovení hesla.', 'username_help_top' => 'Zadejte své <strong>uživatelské jméno</strong> pro zaslání e-mailu s odkazem pro obnovení hesla.',
'username_help_bottom' => 'Vaše uživatelské jméno a e-mailová adresa <em>mohou</em> být stejná, ale nemusí být, záleží na Vašem nastavení. Pokud si nepamatujete Vaše uživatelské jméno, kontaktujte Vašeho správce. <br><br><strong>Uživatelským jménům bez přidružené e-mailové adresy nebude zaslán odkaz pro obnovu hesla.</strong> ', 'username_help_bottom' => 'Vaše uživatelské jméno a e-mailová adresa <em>mohou</em> být stejná, ale nemusí být, záleží na Vašem nastavení. Pokud si nepamatujete Vaše uživatelské jméno, kontaktujte Vašeho správce. <br><br><strong>Uživatelským jménům bez přidružené e-mailové adresy nebude zaslán odkaz pro obnovu hesla.</strong> ',
'google_login' => 'Přihlásit se pomocí Google Workspace', 'google_login' => 'Přihlásit se pomocí Google Workspace',
'google_login_failed' => 'Přihlášení Google se nezdařilo, zkuste to prosím znovu.', 'google_login_failed' => 'Přihlášení Google se nezdařilo, zkuste to prosím znovu.',
'invite_password_expires' => 'This password reset link will expire on :expire_date. You can use the manual password reset link to receive a new reset token by clicking here',
]; ];

View File

@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'Po termínu inventury', 'audit_overdue' => 'Po termínu inventury',
'accept' => 'Přijmout :asset', 'accept' => 'Přijmout :asset',
'i_accept' => 'Přijímám', 'i_accept' => 'Přijímám',
'i_decline_item' => 'Decline this item',
'i_accept_item' => 'Accept this item',
'i_decline' => 'Odmítám', 'i_decline' => 'Odmítám',
'accept_decline' => 'Přijímat/zamítnout', 'accept_decline' => 'Přijímat/zamítnout',
'sign_tos' => 'Podepsáním níže souhlasíte s podmínkami služby:', 'sign_tos' => 'Podepsáním níže souhlasíte s podmínkami služby:',
@@ -596,6 +598,7 @@ return [
'version' => 'Verze', 'version' => 'Verze',
'build' => 'sestavení', 'build' => 'sestavení',
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> Je open-source software, vytvořený s <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">láskou</span> od <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.', 'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> Je open-source software, vytvořený s <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">láskou</span> od <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
'set_password' => 'Set a Password',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [

View File

@@ -8,11 +8,15 @@ return [
'Asset_Checkout_Notification' => 'Majetek zkontrolován', 'Asset_Checkout_Notification' => 'Majetek zkontrolován',
'Confirm_Accessory_Checkin' => 'Potvrzení odevzdání příslušenství', 'Confirm_Accessory_Checkin' => 'Potvrzení odevzdání příslušenství',
'Confirm_Asset_Checkin' => 'Potvrzení odevzdání předmětu', 'Confirm_Asset_Checkin' => 'Potvrzení odevzdání předmětu',
'Confirm_component_checkin' => 'Component checkin confirmation',
'Confirm_accessory_delivery' => 'Potvrďte dodání příslušenství', 'Confirm_accessory_delivery' => 'Potvrďte dodání příslušenství',
'Confirm_asset_delivery' => 'Potvrďte dodání majetku', 'Confirm_asset_delivery' => 'Potvrďte dodání majetku',
'Confirm_consumable_delivery' => 'Potvrďte dodání spotřebního zboží', 'Confirm_consumable_delivery' => 'Potvrďte dodání spotřebního zboží',
'Confirm_component_delivery' => 'Component delivery confirmation',
'Confirm_license_delivery' => 'Potvrdit dodání licence', 'Confirm_license_delivery' => 'Potvrdit dodání licence',
'Consumable_checkout_notification' => 'Spotřební materiál byl zkontrolován', 'Consumable_checkout_notification' => 'Spotřební materiál byl zkontrolován',
'Component_checkout_notification' => 'Component checked out',
'Component_checkin_notification' => 'Component checked in',
'Days' => 'Dní', 'Days' => 'Dní',
'Expected_Checkin_Date' => 'Majetek, který vám byl předán, musí být vrácen zpět do :date', 'Expected_Checkin_Date' => 'Majetek, který vám byl předán, musí být vrácen zpět do :date',
'Expected_Checkin_Notification' => 'Připomenutí: blížící se lhůta pro :name', 'Expected_Checkin_Notification' => 'Připomenutí: blížící se lhůta pro :name',
@@ -33,7 +37,7 @@ return [
'send_pdf_copy' => 'Send a copy of this acceptance to my email address', 'send_pdf_copy' => 'Send a copy of this acceptance to my email address',
'accessory_name' => 'Název příslušenství', 'accessory_name' => 'Název příslušenství',
'additional_notes' => 'Další Poznámky', 'additional_notes' => 'Další Poznámky',
'admin_has_created' => 'Administrátor pro vás vytvořil účet na stránce :web.', 'admin_has_created' => 'An administrator has created an account for you on the :web website. Please find your username below, and click on the link to set a password.',
'asset' => 'Majetek', 'asset' => 'Majetek',
'asset_name' => 'Název majetku', 'asset_name' => 'Název majetku',
'asset_requested' => 'Požadovaný majetek', 'asset_requested' => 'Požadovaný majetek',

View File

@@ -5,7 +5,7 @@ return [
'manage' => 'Manage', 'manage' => 'Manage',
'field' => 'Meysydd', 'field' => 'Meysydd',
'about_fieldsets_title' => 'Amdan grwpiau meysydd', 'about_fieldsets_title' => 'Amdan grwpiau meysydd',
'about_fieldsets_text' => 'Mae grwpiau meysydd yn caniatau i chi creu grwpiau o meysydd addasedig sydd yn cael ei defnyddio yn amal ar gyfer mathau penodol o asedau.', 'about_fieldsets_text' => 'Fieldsets allow you to create groups of custom fields that are frequently re-used for specific asset model types.',
'custom_format' => 'Custom Regex format...', 'custom_format' => 'Custom Regex format...',
'encrypt_field' => 'Hamcryptio gwerth y maes yma yn y basdata', 'encrypt_field' => 'Hamcryptio gwerth y maes yma yn y basdata',
'encrypt_field_help' => 'RHYBUDD: Mae hamcryptio maes yn feddwl nid oes modd chwilio amdano.', 'encrypt_field_help' => 'RHYBUDD: Mae hamcryptio maes yn feddwl nid oes modd chwilio amdano.',

View File

@@ -55,7 +55,7 @@ return [
'default_eula_text_placeholder' => 'Add your default EULA text', 'default_eula_text_placeholder' => 'Add your default EULA text',
'default_language' => 'Iaith Diofyn', 'default_language' => 'Iaith Diofyn',
'default_eula_help_text' => 'Yn ogystal, fedrwch perthnasu CTDT yn erbyn asedau penodol.', 'default_eula_help_text' => 'Yn ogystal, fedrwch perthnasu CTDT yn erbyn asedau penodol.',
'acceptance_note' => 'Add a note for your decision (Optional)', 'acceptance_note' => 'Add a note for your decision (required if declining)',
'display_asset_name' => 'Dangos Enw Ased', 'display_asset_name' => 'Dangos Enw Ased',
'display_checkout_date' => 'Dangos Dyddiad Allan', 'display_checkout_date' => 'Dangos Dyddiad Allan',
'display_eol' => 'Dangos DB yn y tabl', 'display_eol' => 'Dangos DB yn y tabl',

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'Wedi anghofio\'r cyfrinair', 'forgot_password' => 'Wedi anghofio\'r cyfrinair',
'ldap_reset_password' => 'Cliciwch yma i ailosod eich cyfrinair LDAP', 'ldap_reset_password' => 'Cliciwch yma i ailosod eich cyfrinair LDAP',
'remember_me' => 'Cofiwch fi', 'remember_me' => 'Cofiwch fi',
'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.', 'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.',
'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ', 'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ',
'google_login' => 'Login with Google Workspace', 'google_login' => 'Login with Google Workspace',
'google_login_failed' => 'Google Login failed, please try again.', 'google_login_failed' => 'Google Login failed, please try again.',
'invite_password_expires' => 'This password reset link will expire on :expire_date. You can use the manual password reset link to receive a new reset token by clicking here',
]; ];

View File

@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'Overdue for Audit', 'audit_overdue' => 'Overdue for Audit',
'accept' => 'Accept :asset', 'accept' => 'Accept :asset',
'i_accept' => 'I accept', 'i_accept' => 'I accept',
'i_decline_item' => 'Decline this item',
'i_accept_item' => 'Accept this item',
'i_decline' => 'I decline', 'i_decline' => 'I decline',
'accept_decline' => 'Accept/Decline', 'accept_decline' => 'Accept/Decline',
'sign_tos' => 'Sign below to indicate that you agree to the terms of service:', 'sign_tos' => 'Sign below to indicate that you agree to the terms of service:',
@@ -594,6 +596,7 @@ return [
'version' => 'Version', 'version' => 'Version',
'build' => 'build', 'build' => 'build',
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.', 'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
'set_password' => 'Set a Password',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [

View File

@@ -8,11 +8,15 @@ return [
'Asset_Checkout_Notification' => 'Asset checked out', 'Asset_Checkout_Notification' => 'Asset checked out',
'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation', 'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation',
'Confirm_Asset_Checkin' => 'Asset checkin confirmation', 'Confirm_Asset_Checkin' => 'Asset checkin confirmation',
'Confirm_component_checkin' => 'Component checkin confirmation',
'Confirm_accessory_delivery' => 'Accessory delivery confirmation', 'Confirm_accessory_delivery' => 'Accessory delivery confirmation',
'Confirm_asset_delivery' => 'Asset delivery confirmation', 'Confirm_asset_delivery' => 'Asset delivery confirmation',
'Confirm_consumable_delivery' => 'Consumable delivery confirmation', 'Confirm_consumable_delivery' => 'Consumable delivery confirmation',
'Confirm_component_delivery' => 'Component delivery confirmation',
'Confirm_license_delivery' => 'License delivery confirmation', 'Confirm_license_delivery' => 'License delivery confirmation',
'Consumable_checkout_notification' => 'Consumable checked out', 'Consumable_checkout_notification' => 'Consumable checked out',
'Component_checkout_notification' => 'Component checked out',
'Component_checkin_notification' => 'Component checked in',
'Days' => 'Dyddiau', 'Days' => 'Dyddiau',
'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date', 'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date',
'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching', 'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching',
@@ -33,7 +37,7 @@ return [
'send_pdf_copy' => 'Send a copy of this acceptance to my email address', 'send_pdf_copy' => 'Send a copy of this acceptance to my email address',
'accessory_name' => 'Enw Ategolyn', 'accessory_name' => 'Enw Ategolyn',
'additional_notes' => 'Nodiadau ychwanegol', 'additional_notes' => 'Nodiadau ychwanegol',
'admin_has_created' => 'Mae gweinyddwr wedi creu cyfrif i chi a yr :web wefan.', 'admin_has_created' => 'An administrator has created an account for you on the :web website. Please find your username below, and click on the link to set a password.',
'asset' => 'Ased', 'asset' => 'Ased',
'asset_name' => 'Enw Ased', 'asset_name' => 'Enw Ased',
'asset_requested' => 'Gofynnwyd am ased', 'asset_requested' => 'Gofynnwyd am ased',

View File

@@ -5,7 +5,7 @@ return [
'manage' => 'Administrer', 'manage' => 'Administrer',
'field' => 'Felt', 'field' => 'Felt',
'about_fieldsets_title' => 'Om Feltsæt', 'about_fieldsets_title' => 'Om Feltsæt',
'about_fieldsets_text' => 'Fieldsets giver dig mulighed for at oprette grupper af brugerdefinerede felter, der ofte bruges igen til specifikke aktivmodeltyper.', 'about_fieldsets_text' => 'Feltsæt giver dig mulighed for at oprette grupper af brugerdefinerede felter, der ofte genbruges til specifikke asset-modeltyper.',
'custom_format' => 'Tilpasset Regex format...', 'custom_format' => 'Tilpasset Regex format...',
'encrypt_field' => 'Kryptere værdien af dette felt i databasen', 'encrypt_field' => 'Kryptere værdien af dette felt i databasen',
'encrypt_field_help' => 'Advarsel: Kryptere et felt gør det uransagelige.', 'encrypt_field_help' => 'Advarsel: Kryptere et felt gør det uransagelige.',

View File

@@ -55,7 +55,7 @@ return [
'default_eula_text_placeholder' => 'Add your default EULA text', 'default_eula_text_placeholder' => 'Add your default EULA text',
'default_language' => 'Standard sprog', 'default_language' => 'Standard sprog',
'default_eula_help_text' => 'Du kan også knytte brugerdefinerede EULA til specifikke aktivkategorier.', 'default_eula_help_text' => 'Du kan også knytte brugerdefinerede EULA til specifikke aktivkategorier.',
'acceptance_note' => 'Add a note for your decision (Optional)', 'acceptance_note' => 'Add a note for your decision (required if declining)',
'display_asset_name' => 'Vis aktivnavn', 'display_asset_name' => 'Vis aktivnavn',
'display_checkout_date' => 'Vis checkout dato', 'display_checkout_date' => 'Vis checkout dato',
'display_eol' => 'Vis EOL i tabelvisning', 'display_eol' => 'Vis EOL i tabelvisning',

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'Jeg har glemt min adgangskode', 'forgot_password' => 'Jeg har glemt min adgangskode',
'ldap_reset_password' => 'Klik her for at nulstille din LDAP adgangskode', 'ldap_reset_password' => 'Klik her for at nulstille din LDAP adgangskode',
'remember_me' => 'Husk mig', 'remember_me' => 'Husk mig',
'username_help_top' => 'Indtast dit <strong>brugernavn</strong> for at få tilsendt et link til nulstilling af adgangskoden.', 'username_help_top' => 'Indtast dit <strong>brugernavn</strong> for at få tilsendt et link til nulstilling af adgangskoden.',
'username_help_bottom' => 'Dit brugernavn og din emailadresse <em>kan</em> være den samme; men din konfiguration kan kæve at de er forskellige. Hvis du ikke kan huske dit brugernavn, så kontakt administratoren. <br><br><strong>Brugernavne uden tilhørende emailadresse vil ikke få tilsendt mail med link til reset af kodeord.</strong> ', 'username_help_bottom' => 'Dit brugernavn og din emailadresse <em>kan</em> være den samme; men din konfiguration kan kæve at de er forskellige. Hvis du ikke kan huske dit brugernavn, så kontakt administratoren. <br><br><strong>Brugernavne uden tilhørende emailadresse vil ikke få tilsendt mail med link til reset af kodeord.</strong> ',
'google_login' => 'Log ind med Google Workspace', 'google_login' => 'Log ind med Google Workspace',
'google_login_failed' => 'Google Log ind mislykkedes, prøv igen.', 'google_login_failed' => 'Google Log ind mislykkedes, prøv igen.',
'invite_password_expires' => 'This password reset link will expire on :expire_date. You can use the manual password reset link to receive a new reset token by clicking here',
]; ];

View File

@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'Forfalden til tilsyn', 'audit_overdue' => 'Forfalden til tilsyn',
'accept' => 'Accepter :asset', 'accept' => 'Accepter :asset',
'i_accept' => 'Jeg accepterer', 'i_accept' => 'Jeg accepterer',
'i_decline_item' => 'Decline this item',
'i_accept_item' => 'Accept this item',
'i_decline' => 'Jeg afviser', 'i_decline' => 'Jeg afviser',
'accept_decline' => 'Accepter/afvis', 'accept_decline' => 'Accepter/afvis',
'sign_tos' => 'Bekræft nedenfor for at angive, at du accepterer vilkårene for tjenesten:', 'sign_tos' => 'Bekræft nedenfor for at angive, at du accepterer vilkårene for tjenesten:',
@@ -594,6 +596,7 @@ return [
'version' => 'Version', 'version' => 'Version',
'build' => 'build', 'build' => 'build',
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.', 'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
'set_password' => 'Set a Password',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [

View File

@@ -8,11 +8,15 @@ return [
'Asset_Checkout_Notification' => 'Aktiv tjekket ud', 'Asset_Checkout_Notification' => 'Aktiv tjekket ud',
'Confirm_Accessory_Checkin' => 'Tilbehør checkin bekræftelse', 'Confirm_Accessory_Checkin' => 'Tilbehør checkin bekræftelse',
'Confirm_Asset_Checkin' => 'Asset checkin bekræftelse', 'Confirm_Asset_Checkin' => 'Asset checkin bekræftelse',
'Confirm_component_checkin' => 'Component checkin confirmation',
'Confirm_accessory_delivery' => 'Tilbehør leveringsbekræftelse', 'Confirm_accessory_delivery' => 'Tilbehør leveringsbekræftelse',
'Confirm_asset_delivery' => 'Asset leveringsbekræftelse', 'Confirm_asset_delivery' => 'Asset leveringsbekræftelse',
'Confirm_consumable_delivery' => 'Forbrugsvare leveringsbekræftelse', 'Confirm_consumable_delivery' => 'Forbrugsvare leveringsbekræftelse',
'Confirm_component_delivery' => 'Component delivery confirmation',
'Confirm_license_delivery' => 'Licens leveringsbekræftelse', 'Confirm_license_delivery' => 'Licens leveringsbekræftelse',
'Consumable_checkout_notification' => 'Forbrugsstoffer tjekket ud', 'Consumable_checkout_notification' => 'Forbrugsstoffer tjekket ud',
'Component_checkout_notification' => 'Component checked out',
'Component_checkin_notification' => 'Component checked in',
'Days' => 'Dage', 'Days' => 'Dage',
'Expected_Checkin_Date' => 'Et asset tjekket ud til dig skal tjekkes tilbage den :date', 'Expected_Checkin_Date' => 'Et asset tjekket ud til dig skal tjekkes tilbage den :date',
'Expected_Checkin_Notification' => 'Påmindelse: :name checkin deadline nærmer sig', 'Expected_Checkin_Notification' => 'Påmindelse: :name checkin deadline nærmer sig',
@@ -33,7 +37,7 @@ return [
'send_pdf_copy' => 'Send a copy of this acceptance to my email address', 'send_pdf_copy' => 'Send a copy of this acceptance to my email address',
'accessory_name' => 'Tilbehør Navn', 'accessory_name' => 'Tilbehør Navn',
'additional_notes' => 'Yderligere bemærkninger', 'additional_notes' => 'Yderligere bemærkninger',
'admin_has_created' => 'En administrator har oprettet en konto til dig på webstedet:.', 'admin_has_created' => 'An administrator has created an account for you on the :web website. Please find your username below, and click on the link to set a password.',
'asset' => 'Asset', 'asset' => 'Asset',
'asset_name' => 'Aktivnavn', 'asset_name' => 'Aktivnavn',
'asset_requested' => 'Aktiver bedt om', 'asset_requested' => 'Aktiver bedt om',

View File

@@ -4,7 +4,7 @@ return array(
'asset_categories' => 'Asset-Kategorien', 'asset_categories' => 'Asset-Kategorien',
'category_name' => 'Kategorie Name', 'category_name' => 'Kategorie Name',
'checkin_email' => 'Beim Checkin/Checkout eine E-Mail an den Benutzer senden.', 'checkin_email' => 'Beim Checkin/Checkout eine E-Mail an den Benutzer senden.',
'email_to_initiator' => 'Send email to you when user accepts or declines checkout.', 'email_to_initiator' => 'Sende eine E-Mail an Sie, wenn der Benutzer die Herausgabe akzeptiert oder ablehnt.',
'checkin_email_notification' => 'Dieser Benutzer erhält beim Checkin / Checkout eine E-Mail.', 'checkin_email_notification' => 'Dieser Benutzer erhält beim Checkin / Checkout eine E-Mail.',
'clone' => 'Kategorie duplizieren', 'clone' => 'Kategorie duplizieren',
'create' => 'Kategorie erstellen', 'create' => 'Kategorie erstellen',

View File

@@ -5,7 +5,7 @@ return [
'manage' => 'Verwalten', 'manage' => 'Verwalten',
'field' => 'Feld', 'field' => 'Feld',
'about_fieldsets_title' => 'Über Feldsätze', 'about_fieldsets_title' => 'Über Feldsätze',
'about_fieldsets_text' => 'Feldsätze erlauben es, Gruppen aus benutzerdefinierten Feldern zu erstellen, die regelmäßig für spezifische Modelltypen benutzt werden.', 'about_fieldsets_text' => 'Feldsätze sind Gruppen von benutzerdefinierten Feldern, die häufig für bestimmte Asset-Modelltypen wiederverwendet werden.',
'custom_format' => 'Benutzerdefiniertes Regex-Format...', 'custom_format' => 'Benutzerdefiniertes Regex-Format...',
'encrypt_field' => 'Den Wert dieses Feldes in der Datenbank verschlüsseln', 'encrypt_field' => 'Den Wert dieses Feldes in der Datenbank verschlüsseln',
'encrypt_field_help' => 'WARNUNG: Ein verschlüsseltes Feld kann nicht durchsucht werden.', 'encrypt_field_help' => 'WARNUNG: Ein verschlüsseltes Feld kann nicht durchsucht werden.',

View File

@@ -55,7 +55,7 @@ return [
'default_eula_text_placeholder' => 'Fügen Sie Ihren Standard-EULA Text hinzu', 'default_eula_text_placeholder' => 'Fügen Sie Ihren Standard-EULA Text hinzu',
'default_language' => 'Standardsprache', 'default_language' => 'Standardsprache',
'default_eula_help_text' => 'Sie können ebenfalls eigene EULA\'s mit spezifischen Asset Kategorien verknüpfen.', 'default_eula_help_text' => 'Sie können ebenfalls eigene EULA\'s mit spezifischen Asset Kategorien verknüpfen.',
'acceptance_note' => 'Notiz für Ihre Entscheidung hinzufügen (Optional)', 'acceptance_note' => 'Add a note for your decision (required if declining)',
'display_asset_name' => 'Zeige Assetname an', 'display_asset_name' => 'Zeige Assetname an',
'display_checkout_date' => 'Zeige Herausgabedatum', 'display_checkout_date' => 'Zeige Herausgabedatum',
'display_eol' => 'Zeige EOL in der Tabellenansicht', 'display_eol' => 'Zeige EOL in der Tabellenansicht',
@@ -157,7 +157,7 @@ return [
'scope_locations_fmcs_support_text' => 'Bereicherte Standorte mit vollständiger Unterstützung für mehrere Unternehmen', 'scope_locations_fmcs_support_text' => 'Bereicherte Standorte mit vollständiger Unterstützung für mehrere Unternehmen',
'scope_locations_fmcs_support_help_text' => 'Standorte auf das ausgewählte Unternehmen beschränken.', 'scope_locations_fmcs_support_help_text' => 'Standorte auf das ausgewählte Unternehmen beschränken.',
'scope_locations_fmcs_check_button' => 'Kompatibilität prüfen', 'scope_locations_fmcs_check_button' => 'Kompatibilität prüfen',
'scope_locations_fmcs_test_needed' => 'Please Check Compatibility to enable this', 'scope_locations_fmcs_test_needed' => 'Bitte überprüfen Sie die Kompatibilität, um dies zu aktivieren',
'scope_locations_fmcs_support_disabled_text' => 'Diese Option ist deaktiviert, da für :count oder mehr Elemente widersprüchliche Standorte gesetzt sind.', 'scope_locations_fmcs_support_disabled_text' => 'Diese Option ist deaktiviert, da für :count oder mehr Elemente widersprüchliche Standorte gesetzt sind.',
'show_in_model_list' => 'In Modell-Dropdown-Liste anzeigen', 'show_in_model_list' => 'In Modell-Dropdown-Liste anzeigen',
'optional' => 'optional', 'optional' => 'optional',
@@ -404,9 +404,9 @@ return [
'due_checkin_days_help' => 'Wie viele Tage vor dem voraussichtlichen Check-in eines Vermögenswerts soll dieser auf der Seite „Zur Eincheckzeit fällig“ aufgeführt werden?', 'due_checkin_days_help' => 'Wie viele Tage vor dem voraussichtlichen Check-in eines Vermögenswerts soll dieser auf der Seite „Zur Eincheckzeit fällig“ aufgeführt werden?',
'no_groups' => 'Es wurden noch keine Gruppen erstellt. Navigieren Sie zu <code>Admin-Einstellungen > Berechtigungsgruppen</code>, um eine hinzuzufügen.', 'no_groups' => 'Es wurden noch keine Gruppen erstellt. Navigieren Sie zu <code>Admin-Einstellungen > Berechtigungsgruppen</code>, um eine hinzuzufügen.',
'text' => 'Text', 'text' => 'Text',
'manager_view' => 'Manager View', 'manager_view' => 'Leitungsansicht',
'manager_view_enabled_text' => 'Enable Manager View', 'manager_view_enabled_text' => 'Leitungsansicht aktivieren',
'manager_view_enabled_help' => 'Allow managers to view assigned items to their direct and indirect reports in their account view.', 'manager_view_enabled_help' => 'Erlaube Leitungen die ihren Mitarbeitern zugewiesenen Gegenstände in direkten und indirekten Berichten in der Account-Ansicht anzuzeigen.',
'username_formats' => [ 'username_formats' => [
'username_format' => 'Format der Benutzernamen', 'username_format' => 'Format der Benutzernamen',

View File

@@ -53,5 +53,5 @@ return [
'next_save_user' => 'Weiter: Benutzer speichern', 'next_save_user' => 'Weiter: Benutzer speichern',
'all_assigned_list_generation' => 'Generiert am:', 'all_assigned_list_generation' => 'Generiert am:',
'email_user_creds_on_create' => 'Diesem Benutzer seine Zugangsdaten per E-Mail senden?', 'email_user_creds_on_create' => 'Diesem Benutzer seine Zugangsdaten per E-Mail senden?',
'department_manager' => 'Department Manager', 'department_manager' => 'Abteilungsleiter',
]; ];

View File

@@ -10,9 +10,11 @@ return [
'forgot_password' => 'Ich habe mein Passwort vergessen', 'forgot_password' => 'Ich habe mein Passwort vergessen',
'ldap_reset_password' => 'Klicken Sie hier, um Ihr LDAP-Kennwort zurückzusetzen.', 'ldap_reset_password' => 'Klicken Sie hier, um Ihr LDAP-Kennwort zurückzusetzen.',
'remember_me' => 'Angemeldet bleiben', 'remember_me' => 'Angemeldet bleiben',
'username_help_top' => '<strong>Benutzernamen</strong> eingeben, um einen Link zum Zurücksetzen des Passwortes per E-Mail zu erhalten.', 'username_help_top' => '<strong>Benutzernamen</strong> eingeben, um einen Link zum Zurücksetzen des Passwortes per E-Mail zu erhalten.',
'username_help_bottom' => 'Abhängig von der Konfiguration, <em>kann</em> der Benutzername identisch mit ihrer E-Mailadresse sein. Falls Sie ihren Benutzernamen vergessen haben, kontaktieren Sie ihren Administrator.<br><br><strong>Benutzernamen ohne zugeordnete E-Mailadresse erhalten keine E-Mail zum Zurücksetzen des Passwortes.</strong> ', 'username_help_bottom' => 'Abhängig von der Konfiguration, <em>kann</em> der Benutzername identisch mit ihrer E-Mailadresse sein. Falls Sie ihren Benutzernamen vergessen haben, kontaktieren Sie ihren Administrator.<br><br><strong>Benutzernamen ohne zugeordnete E-Mailadresse erhalten keine E-Mail zum Zurücksetzen des Passwortes.</strong> ',
'google_login' => 'Mit Google Workspace anmelden', 'google_login' => 'Mit Google Workspace anmelden',
'google_login_failed' => 'Google-Anmeldung fehlgeschlagen, bitte versuchen Sie es erneut.', 'google_login_failed' => 'Google-Anmeldung fehlgeschlagen, bitte versuchen Sie es erneut.',
'invite_password_expires' => 'This password reset link will expire on :expire_date. You can use the manual password reset link to receive a new reset token by clicking here',
]; ];

View File

@@ -225,13 +225,13 @@ return [
'order_number' => 'Bestellnummer', 'order_number' => 'Bestellnummer',
'only_deleted' => 'Nur gelöschte Gegenstände', 'only_deleted' => 'Nur gelöschte Gegenstände',
'page_menu' => 'Zeige _MENU_ Einträge', 'page_menu' => 'Zeige _MENU_ Einträge',
'page_error' => 'Could not determine previous page. Redirected to homepage.', 'page_error' => 'Vorherige Seite konnte nicht ermittelt werden. Sie wurden auf die Startseite weitergeleitet.',
'pagination_info' => 'Zeige _START_ bis _END_ von _TOTAL_ Einträgen', 'pagination_info' => 'Zeige _START_ bis _END_ von _TOTAL_ Einträgen',
'pending' => 'Ausstehende', 'pending' => 'Ausstehende',
'people' => 'Benutzer', 'people' => 'Benutzer',
'per_page' => 'Ergebnisse pro Seite', 'per_page' => 'Ergebnisse pro Seite',
'previous' => 'Vorherige', 'previous' => 'Vorherige',
'previous_page' => 'Previous Page', 'previous_page' => 'Vorherige Seite',
'processing' => 'Wird verarbeitet', 'processing' => 'Wird verarbeitet',
'profile' => 'Ihr Profil', 'profile' => 'Ihr Profil',
'purchase_cost' => 'Einkaufspreis', 'purchase_cost' => 'Einkaufspreis',
@@ -253,7 +253,7 @@ return [
'requested' => 'Angefordert', 'requested' => 'Angefordert',
'requested_date' => 'Angefordertes Datum', 'requested_date' => 'Angefordertes Datum',
'requested_assets' => 'Angeforderte Assets', 'requested_assets' => 'Angeforderte Assets',
'requested_assets_menu' => 'Requested Items', 'requested_assets_menu' => 'Angeforderte Gegenstände',
'request_canceled' => 'Anfrage abgebrochen', 'request_canceled' => 'Anfrage abgebrochen',
'request_item' => 'Diesen Artikel anfordern', 'request_item' => 'Diesen Artikel anfordern',
'external_link_tooltip' => 'Externer Link zu', 'external_link_tooltip' => 'Externer Link zu',
@@ -309,11 +309,11 @@ return [
'type' => 'Typ', 'type' => 'Typ',
'undeployable' => 'Nicht herausgebbar', 'undeployable' => 'Nicht herausgebbar',
'unknown_admin' => 'Unbekannter Administrator', 'unknown_admin' => 'Unbekannter Administrator',
'unknown_user' => 'Unknown User', 'unknown_user' => 'Unbekannter Benutzer',
'username' => 'Benutzername', 'username' => 'Benutzername',
'update' => 'Aktualisieren', 'update' => 'Aktualisieren',
'updating_item' => ':item wird aktualisiert', 'updating_item' => ':item wird aktualisiert',
'upload_filetypes_help' => 'Allowed filetypes are: :allowed_filetypes. Max upload size allowed is :size.', 'upload_filetypes_help' => 'Erlaubte Dateitypen sind: :allowed_filetypes. Maximale Upload-Größe ist :size.',
'uploaded' => 'Hochgeladen', 'uploaded' => 'Hochgeladen',
'user' => 'Benutzer', 'user' => 'Benutzer',
'accepted' => 'angenommen', 'accepted' => 'angenommen',
@@ -323,9 +323,9 @@ return [
'unaccepted_asset_report' => 'Nicht akzeptierte Assets', 'unaccepted_asset_report' => 'Nicht akzeptierte Assets',
'users' => 'Benutzer', 'users' => 'Benutzer',
'viewall' => 'Alle anzeigen', 'viewall' => 'Alle anzeigen',
'viewassets' => 'View Assigned Items', 'viewassets' => 'Zugewiesene Gegenstände anzeigen',
'viewassetsfor' => 'View Items for :name', 'viewassetsfor' => 'Gegenstände von :name anzeigen',
'view_user_assets' => 'View Items Assigned to User', 'view_user_assets' => 'Dem Benutzer zugewiesene Gegenstände anzeigen',
'me' => 'Ich', 'me' => 'Ich',
'website' => 'Webseite', 'website' => 'Webseite',
'welcome' => 'Willkommen, :name', 'welcome' => 'Willkommen, :name',
@@ -346,6 +346,8 @@ return [
'audit_overdue' => 'Prüfung überfällig', 'audit_overdue' => 'Prüfung überfällig',
'accept' => ':asset akzeptieren', 'accept' => ':asset akzeptieren',
'i_accept' => 'Ich akzeptiere', 'i_accept' => 'Ich akzeptiere',
'i_decline_item' => 'Decline this item',
'i_accept_item' => 'Accept this item',
'i_decline' => 'Ich lehne ab', 'i_decline' => 'Ich lehne ab',
'accept_decline' => 'Akzeptieren/Ablehnen', 'accept_decline' => 'Akzeptieren/Ablehnen',
'sign_tos' => 'Unterschreiben Sie unten, um den Nutzungsbedingungen zuzustimmen:', 'sign_tos' => 'Unterschreiben Sie unten, um den Nutzungsbedingungen zuzustimmen:',
@@ -516,7 +518,7 @@ return [
'manager_last_name' => 'Vorgesetzter Nachname', 'manager_last_name' => 'Vorgesetzter Nachname',
'manager_full_name' => 'Vorgesetzter Voller Name', 'manager_full_name' => 'Vorgesetzter Voller Name',
'manager_username' => 'Vorgesetzter Benutzername', 'manager_username' => 'Vorgesetzter Benutzername',
'manager_employee_num' => 'Manager Employee Number', 'manager_employee_num' => 'Leitungsmitarbeiternummer',
'checkout_type' => 'Herausgabetyp', 'checkout_type' => 'Herausgabetyp',
'checkout_location' => 'Herausgeben an Ort', 'checkout_location' => 'Herausgeben an Ort',
'image_filename' => 'Bild Dateiname', 'image_filename' => 'Bild Dateiname',
@@ -594,6 +596,7 @@ return [
'version' => 'Version', 'version' => 'Version',
'build' => 'Build', 'build' => 'Build',
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> ist Open-Source-Software, entwickelt mit <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">Liebe</span> von <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.', 'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> ist Open-Source-Software, entwickelt mit <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">Liebe</span> von <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
'set_password' => 'Set a Password',
// Add form placeholders here // Add form placeholders here
'placeholders' => [ 'placeholders' => [
@@ -645,28 +648,28 @@ return [
'file_upload_status' => [ 'file_upload_status' => [
'upload' => [ 'upload' => [
'success' => 'File successfully uploaded |:count files successfully uploaded', 'success' => 'Datei wurde erfolgreich hochgeladen|:count Dateien wurden erfolgreich hochgeladen',
'error' => 'File upload failed |:count file uploads failed', 'error' => 'Datei-Upload fehlgeschlagen |:count Datei-Uploads fehlgeschlagen',
], ],
'delete' => [ 'delete' => [
'success' => 'File successfully deleted |:count files successfully deleted', 'success' => 'Datei wurde erfolgreich gelöscht|:count Dateien wurden erfolgreich gelöscht',
'error' => 'File deletion failed |:count file deletions failed', 'error' => 'Datei-Löschung fehlgeschlagen|:count Datei-Löschungen fehlgeschlagen',
], ],
'file_not_found' => 'The selected file was not found on server', 'file_not_found' => 'Die ausgewählte Datei wurde nicht auf dem Server gefunden',
'invalid_id' => 'That file ID is invalid', 'invalid_id' => 'Diese Datei-ID ist ungültig',
'invalid_object' => 'That object ID is invalid', 'invalid_object' => 'Diese Objekt-ID ist ungültig',
'nofiles' => 'No files were included for upload', 'nofiles' => 'Keine Dateien zum Hochladen vorhanden',
'confirm_delete' => 'Are you sure you want to delete this file?', 'confirm_delete' => 'Sind sie sicher das diese Datei gelöscht werden soll?',
], ],
'depreciation_options' => [ 'depreciation_options' => [
'amount' => 'Amount', 'amount' => 'Anzahl',
'percent' => 'Percentage', 'percent' => 'Prozentsatz',
], ],
'months_plural' => '1 month|:count months', 'months_plural' => '1 Monat|:count Monate',
]; ];

Some files were not shown because too many files have changed in this diff Show More