6161 <input class =" block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
6262 id =" details" :placeholder =" t('logs.placeholder_details')" v-model =" filters.details" >
6363 </div >
64- <!-- Before -->
65- <div class =" w-1/6 px-3 pr-1 mobile:w-full mobile:mb-3" >
66- <label class =" block mb-3 mt-3" for =" before-date" >
67- {{ t('logs.before-date') }} <sup class =" text-muted dark:text-dark-muted" >*</sup >
68- </label >
69- <input class =" block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
70- id =" before-date" type =" date" placeholder =" " >
71- </div >
72- <!-- Before -->
73- <div class =" w-1/6 px-3 pl-1 mobile:w-full mobile:mb-3" >
74- <label class =" block mb-3 mt-3" for =" before-time" >
75- {{ t('logs.before-time') }} <sup class =" text-muted dark:text-dark-muted" >*</sup >
76- </label >
77- <input class =" block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
78- id =" before-time" type =" time" placeholder =" " >
79- </div >
80- <!-- After -->
64+ <!-- After Date -->
8165 <div class =" w-1/6 px-3 pr-1 mobile:w-full mobile:mb-3" >
8266 <label class =" block mb-3 mt-3" for =" after-date" >
8367 {{ t('logs.after-date') }} <sup class =" text-muted dark:text-dark-muted" >*</sup >
8468 </label >
8569 <input class =" block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600" id =" after-date"
8670 type =" date" placeholder =" " >
8771 </div >
88- <!-- Before -->
72+ <!-- After Time -->
8973 <div class =" w-1/6 px-3 pl-1 mobile:w-full mobile:mb-3" >
9074 <label class =" block mb-3 mt-3" for =" after-time" >
9175 {{ t('logs.after-time') }} <sup class =" text-muted dark:text-dark-muted" >*</sup >
9276 </label >
9377 <input class =" block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
9478 id =" after-time" type =" time" placeholder =" " >
9579 </div >
80+ <!-- Before Date -->
81+ <div class =" w-1/6 px-3 pr-1 mobile:w-full mobile:mb-3" >
82+ <label class =" block mb-3 mt-3" for =" before-date" >
83+ {{ t('logs.before-date') }} <sup class =" text-muted dark:text-dark-muted" >*</sup >
84+ </label >
85+ <input class =" block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
86+ id =" before-date" type =" date" placeholder =" " >
87+ </div >
88+ <!-- Before Time -->
89+ <div class =" w-1/6 px-3 pl-1 mobile:w-full mobile:mb-3" >
90+ <label class =" block mb-3 mt-3" for =" before-time" >
91+ {{ t('logs.before-time') }} <sup class =" text-muted dark:text-dark-muted" >*</sup >
92+ </label >
93+ <input class =" block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
94+ id =" before-time" type =" time" placeholder =" " >
95+ </div >
9696 </div >
9797 <!-- Description -->
9898 <div class =" w-full px-3 mt-3" >
204204 </template >
205205 </v-section >
206206
207+ <modal :show.sync =" showLogDetail" >
208+ <template #header >
209+ <h1 class =" dark:text-white" >
210+ {{ t('logs.detail.title') }}
211+ </h1 >
212+ <p class =" dark:text-dark-muted !-mt-3 italic" >
213+ {{ t('logs.detail.description', log_detail.user) }}
214+ </p >
215+ </template >
216+
217+ <template #default >
218+ <pre class =" text-lg block mb-2" >{{ log_detail.reason }}</pre >
219+ {{ log_detail.description }}
220+ </template >
221+
222+ <template #actions >
223+ <button type =" button" class =" px-5 py-2 rounded hover:bg-gray-200 dark:bg-gray-600 dark:hover:bg-gray-400" @click =" showLogDetail = false" >
224+ {{ t('global.close') }}
225+ </button >
226+ </template >
227+ </modal >
228+
207229 </div >
208230</template >
209231
210232<script >
211233import Layout from ' ./../../Layouts/App' ;
212234import VSection from ' ./../../Components/Section' ;
213235import Pagination from ' ./../../Components/Pagination' ;
236+ import Modal from ' ./../../Components/Modal' ;
214237
215238export default {
216239 layout: Layout,
217240 components: {
218241 Pagination,
242+ Modal,
219243 VSection,
220244 },
221245 props: {
@@ -250,7 +274,13 @@ export default {
250274 },
251275 data () {
252276 return {
253- isLoading: false
277+ isLoading: false ,
278+ showLogDetail: false ,
279+ log_detail: {
280+ user: ' ' ,
281+ reason: ' ' ,
282+ description: ' '
283+ }
254284 };
255285 },
256286 methods: {
@@ -293,6 +323,57 @@ export default {
293323
294324 this .isLoading = false ;
295325 },
326+ parseDisconnectLog (details ) {
327+ const regex = / (?<=\) has disconnected from the server . +? with reason: `)(. +? )(?=`\. )/ gm ;
328+ const matches = details .match (regex);
329+ const match = matches && matches .length === 1 && matches[0 ].trim () ? matches[0 ].trim () : null ;
330+
331+ if (match) {
332+ const descriptions = [
333+ [/ ^ Exiting/ gmi , this .t (' logs.detail.reasons.exited' )],
334+ [/ ^ Disconnected| ^ You have disconnected from the server/ gmi , this .t (' logs.detail.reasons.disconnected' )],
335+ [/ Game crashed: / gmi , this .t (' logs.detail.reasons.crash' )],
336+ [/ (?<=connection| You) timed out[!. ] | ^ Timed out after/ gmi , this .t (' logs.detail.reasons.timeout' )],
337+ [/ ^ You have been banned/ gmi , this .t (' logs.detail.reasons.banned' )],
338+ [/ ^ The server is restarting/ gmi , this .t (' logs.detail.reasons.restart' )],
339+ [/ ^ You have been kicked/ gmi , this .t (' logs.detail.reasons.kicked' )],
340+ [/ ^ Your Job Priority expired/ gmi , this .t (' logs.detail.reasons.job' )],
341+ [/ ^ Failed to sync doors/ gmi , this .t (' logs.detail.reasons.doors' )],
342+ [/ ^ You have been globally banned from all OP-FW servers/ gmi , this .t (' logs.detail.reasons.global' )],
343+ [/ ^ Entering Rockstar Editor/ gmi , this .t (' logs.detail.reasons.editor' )],
344+ [/ ^ Reliable network event overflow/ gmi , this .t (' logs.detail.reasons.overflow' )],
345+ [/ ^ Connecting to another server/ gmi , this .t (' logs.detail.reasons.another' )],
346+ [/ ^ Obtaining configuration from server failed/ gmi , this .t (' logs.detail.reasons.config' )],
347+ ];
348+
349+ let description = ' ' ;
350+ for (let x in descriptions) {
351+ const entry = descriptions[x];
352+
353+ if (entry[0 ].test (match)) {
354+ description = entry[1 ];
355+ break ;
356+ }
357+ }
358+
359+ if (! description) {
360+ description = this .t (' logs.detail.reasons.unknown' );
361+ }
362+
363+ const html = $ (' <div />' ).append (
364+ $ (' <a></a>' , {
365+ " data-reason" : match,
366+ " data-description" : description,
367+ " class" : " text-yellow-800 dark:text-yellow-200 exit-log" ,
368+ " href" : " #"
369+ }).text (match)
370+ ).html ();
371+
372+ return details .replace (match, html);
373+ }
374+
375+ return details;
376+ },
296377 parseLog (details ) {
297378 const regex = / (to| from) (inventory )? ((trunk| glovebox| character| property)-(\d + -)? \d + :\d + )/ gmi ;
298379
@@ -313,13 +394,24 @@ export default {
313394 details = details .replaceAll (inventories[x], ' <a title="' + this .t (' inventories.view' ) + ' " class="text-indigo-600 dark:text-indigo-400" href="/inventory/' + inventories[x] + ' ">' + inventories[x] + ' </a>' );
314395 }
315396
316- return details;
397+ return this . parseDisconnectLog ( details) ;
317398 },
318399 playerName (steamIdentifier ) {
319400 return steamIdentifier in this .playerMap ? this .playerMap [steamIdentifier] : steamIdentifier;
320401 }
321402 },
322403 mounted () {
404+ const _this = this ;
405+ $ (' body' ).on (' click' , ' a.exit-log' , function (e ) {
406+ e .preventDefault ();
407+ const parent = $ (this ).closest (' tr' );
408+
409+ _this .showLogDetail = true ;
410+ _this .log_detail .user = $ (' td:first-child a' , parent).text ().trim ();
411+ _this .log_detail .reason = $ (this ).data (' reason' );
412+ _this .log_detail .description = $ (this ).data (' description' );
413+ });
414+
323415 if (this .filters .before ) {
324416 const d = new Date (this .filters .before * 1000 );
325417
0 commit comments