/ app / Http / Livewire / Jsons / BaseJsonView.php
BaseJsonView.php
  1  <?php
  2  
  3  namespace App\Http\Livewire\Jsons;
  4  
  5  use App\Http\Services\JsonImporterService;
  6  use App\Models\Dossier;
  7  use App\Models\Json;
  8  use App\Models\JsonDraft;
  9  use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
 10  use Illuminate\Pagination\LengthAwarePaginator;
 11  use Illuminate\Support\Collection;
 12  use Jfcherng\Diff\DiffHelper;
 13  use Jfcherng\Diff\Renderer\RendererConstant;
 14  use Livewire\Component;
 15  use Livewire\Redirector;
 16  use Livewire\WithPagination;
 17  use WireUi\Traits\Actions;
 18  
 19  abstract class BaseJsonView extends Component
 20  {
 21      use WithPagination, Actions, AuthorizesRequests;
 22  
 23      /**
 24       * @var $json JsonDraft|Json
 25       */
 26      public $json;
 27  
 28      public ?Json $oldJson;
 29  
 30      public int $entityId;
 31  
 32      public array $data;
 33  
 34      public bool $isDiffing = false;
 35  
 36      protected $listeners = ['refresh' => '$refresh'];
 37  
 38      public function mount()
 39      {
 40          $this->authorize('viewAnyAdmin', Dossier::class);
 41          $this->data = $this->json->json;
 42  
 43          if (get_class($this->json) === JsonDraft::class)
 44              $this->oldJson = JsonImporterService::findJsonFromDraft($this->json);
 45      }
 46  
 47      public function updating(): void
 48      {
 49          $this->resetPage();
 50      }
 51  
 52      public function getChangelogsProperty()
 53      {
 54          $changelogs = collect($this->json->json['changelog']);
 55          return $this->getPaginate($changelogs, 'changelogs');
 56      }
 57  
 58      public function getAcronymsProperty()
 59      {
 60          $acronyms = collect($this->json->json['acronyms']);
 61          return $this->getPaginate($acronyms, 'acronyms');
 62      }
 63  
 64      public function getDocumentReferencesProperty()
 65      {
 66          $documentReferences = collect($this->json->json['documentReferences']);
 67          return $this->getPaginate($documentReferences, 'documentReferences');
 68      }
 69  
 70      public function getNonConformitiesProperty()
 71      {
 72          $nonConformities = collect($this->json->json['nonconformities']);
 73          return $this->getPaginate($nonConformities, 'nonConformities');
 74      }
 75  
 76      public function getCommentsProperty()
 77      {
 78          $comments = collect($this->json->json['comments']);
 79          return $this->getPaginate($comments, 'comments');
 80      }
 81  
 82      public abstract function render();
 83  
 84  
 85      public function getDossierCode(Json|JsonDraft $json)
 86      {
 87          return $json->json['information']['dossierCode'];
 88      }
 89  
 90  
 91      public function getProjectCode(Json|JsonDraft $json)
 92      {
 93          return $json->json['information']['projectCode'];
 94      }
 95  
 96      public function getApprovedBy(Json|JsonDraft $json)
 97      {
 98          return $json->json['information']['approvedBy'];
 99      }
100  
101      public function getReviewedBy(Json|JsonDraft $json)
102      {
103          return $json->json['information']['reviewedBy'];
104      }
105  
106      public function getAuthors(Json|JsonDraft $json)
107      {
108          $olds = collect($this->oldJson->json['information']['authors']);
109          $news = collect($this->json->json['information']['authors']);
110          $result = [];
111          $used = [];
112  
113          foreach ($news as $new) {
114              $used[] = $new;
115              $aux = $olds->contains($new);
116              $result[] = $this->applyDiff($new ?? '', $aux ?? '');
117          }
118  
119          foreach ($olds as $old) {
120              if (!collect($used)->contains($old)) {
121                  $result[] = $this->applyDiff('', $old);
122              }
123          }
124  
125          return implode('-',$result);
126      }
127  
128      public function getAssuranceLevel(Json|JsonDraft $json)
129      {
130          return $json->json['information']['assuranceLevel'];
131      }
132  
133  
134      const rendererName = 'Combined';
135  
136      const differOptions = [
137          // show how many neighbor lines
138          // Differ::CONTEXT_ALL can be used to show the whole file
139          'context' => 3,
140          // ignore case difference
141          'ignoreCase' => false,
142          // ignore line ending difference
143          'ignoreLineEnding' => false,
144          // ignore whitespace difference
145          'ignoreWhitespace' => false,
146          // if the input sequence is too long, it will just gives up (especially for char-level diff)
147          'lengthLimit' => 4000,
148      ];
149  
150      const rendererOptions = [
151          // how detailed the rendered HTML in-line diff is? (none, line, word, char)
152          'detailLevel' => 'line',
153          // renderer language: eng, cht, chs, jpn, ...
154          // or an array which has the same keys with a language file
155          // check the "Custom Language" section in the readme for more advanced usage
156          'language' => 'eng',
157          // show line numbers in HTML renderers
158          'lineNumbers' => false,
159          // show a separator between different diff hunks in HTML renderers
160          'separateBlock' => true,
161          // show the (table) header
162          'showHeader' => false,
163          // the frontend HTML could use CSS "white-space: pre;" to visualize consecutive whitespaces
164          // but if you want to visualize them in the backend with "&nbsp;", you can set this to true
165          'spacesToNbsp' => false,
166          // HTML renderer tab width (negative = do not convert into spaces)
167          'tabSize' => 4,
168          // this option is currently only for the Combined renderer.
169          // it determines whether a replace-type block should be merged or not
170          // depending on the content changed ratio, which values between 0 and 1.
171          'mergeThreshold' => 0.8,
172          // this option is currently only for the Unified and the Context renderers.
173          // RendererConstant::CLI_COLOR_AUTO = colorize the output if possible (default)
174          // RendererConstant::CLI_COLOR_ENABLE = force to colorize the output
175          // RendererConstant::CLI_COLOR_DISABLE = force not to colorize the output
176          'cliColorization' => RendererConstant::CLI_COLOR_AUTO,
177          // this option is currently only for the Json renderer.
178          // internally, ops (tags) are all int type but this is not good for human reading.
179          // set this to "true" to convert them into string form before outputting.
180          'outputTagAsString' => false,
181          // this option is currently only for the Json renderer.
182          // it controls how the output JSON is formatted.
183          // see available options on https://www.php.net/manual/en/function.json-encode.php
184          'jsonEncodeFlags' => \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE,
185          // this option is currently effective when the "detailLevel" is "word"
186          // characters listed in this array can be used to make diff segments into a whole
187          // for example, making "<del>good</del>-<del>looking</del>" into "<del>good-looking</del>"
188          // this should bring better readability but set this to empty array if you do not want it
189          'wordGlues' => [' ', '-'],
190          // change this value to a string as the returned diff if the two input strings are identical
191          'resultForIdenticals' => null,
192          // extra HTML classes added to the DOM of the diff container
193          'wrapperClasses' => ['diff-wrapper'],
194      ];
195  
196      public function diff(string $function)
197      {
198          $function = 'get' . ucfirst($function);
199  
200          if (!$this->isDiffing)
201              return $this->{$function}($this->json);
202  
203          return $this->applyDiff($this->{$function}($this->json), $this->{$function}($this->oldJson));
204      }
205  
206      protected function applyDiff(string $draft, string $saved): string
207      {
208          $result = DiffHelper::calculate($saved, $draft, self::rendererName, self::differOptions, self::rendererOptions);
209  
210          if (!$result)
211              return $draft;
212  
213          return $result;
214      }
215  
216      public function enabledDiff()
217      {
218          $this->isDiffing = !$this->isDiffing;
219      }
220  
221      public function canDiff(): bool
222      {
223          if (isset($this->oldJson) && !$this->json->completed)
224              return true;
225  
226          return false;
227      }
228  
229      public function canSave()
230      {
231          if (get_class($this->json) !== JsonDraft::class)
232              return false;
233  
234          if ($this->json->completed)
235              return false;
236  
237          return true;
238      }
239  
240      public function canValidate()
241      {
242          return $this->canSave();
243      }
244  
245      public function gotoValidation()
246      {
247          if ($this->canValidate()) {
248              return redirect()->to(route('validations.jsons.view', ['jsonDraft' => $this->json]));
249          }
250      }
251  
252      public function showDialog()
253      {
254          $this->dialog()->confirm([
255              'title' => __('jsons.dialogs.title'),
256              'description' => __('jsons.dialogs.description'),
257              'acceptLabel' => __('jsons.dialogs.yes'),
258              'rejectLabel' => __('jsons.dialogs.cancel'),
259              'method' => 'save',
260          ]);
261      }
262  
263      public function diffedChangelogs()
264      {
265          $olds = collect($this->oldJson->json['changelog']);
266          $news = collect($this->json->json['changelog']);
267          $result = [];
268          $used = [];
269  
270          foreach ($news as $new) {
271  
272              $used[] = $new['version'];
273              $aux = $olds->where('version', $new['version'])->first();
274  
275              $result[] = [
276                  'version' => $this->applyDiff($new['version'] ?? '', $aux['version'] ?? ''),
277                  'date' => $this->applyDiff($new['date'] ?? '', $aux['date'] ?? ''),
278                  'authors' => $this->applyDiff(implode(', ', $new['authors'] ?? []), implode(', ', $aux['authors'] ?? [])),
279                  'reason' => $this->applyDiff($new['reason'] ?? '', $aux['reason'] ?? ''),
280                  'changes' => $this->applyDiff(implode(', ', (array)$new['changes'] ?? []), implode(', ', is_null($aux) ? [] : (array)$aux['changes'])),
281              ];
282          }
283  
284          foreach ($olds->whereNotIn('version', $used) as $old) {
285              $result[] = [
286                  'version' => $this->applyDiff('', $old['version']),
287                  'date' => $this->applyDiff('', $old['date']),
288                  'authors' => $this->applyDiff('', implode(', ', $old['authors'])),
289                  'reason' => $this->applyDiff('', $old['reason']),
290                  'changes' => $this->applyDiff('', implode(', ', (array)$old['changes'])),
291              ];
292          }
293  
294          return $this->getPaginate(collect($result), 'changelogs');
295      }
296  
297      public function diffedAcronyms()
298      {
299          $olds = collect($this->oldJson->json['acronyms']);
300          $news = collect($this->json->json['acronyms']);
301          $result = [];
302          $used = [];
303  
304          foreach ($news as $new) {
305  
306              $used[] = $new['acronym'];
307              $aux = $olds->where('acronym', $new['acronym'])->first();
308  
309              $result[] = [
310                  'acronym' => $this->applyDiff($new['acronym'] ?? '', $aux['acronym'] ?? ''),
311                  'meaning' => $this->applyDiff($new['meaning'] ?? '', $aux['meaning'] ?? ''),
312              ];
313          }
314  
315          foreach ($olds->whereNotIn('acronym', $used) as $old) {
316              $result[] = [
317                  'acronym' => $this->applyDiff('', $old['acronym']),
318                  'meaning' => $this->applyDiff('', $old['meaning']),
319              ];
320          }
321  
322          return $this->getPaginate(collect($result), 'acronyms');
323      }
324  
325      public function diffedDocumentReferences()
326      {
327          $olds = collect($this->oldJson->json['documentReferences']);
328          $news = collect($this->json->json['documentReferences']);
329          $result = [];
330          $used = [];
331  
332          foreach ($news as $new) {
333  
334              $used[] = $new['reference'];
335              $aux = $olds->where('reference', $new['reference'])->first();
336  
337              $result[] = [
338                  'reference' => $this->applyDiff($new['reference'] ?? '', $aux['reference'] ?? ''),
339                  'document' => $this->applyDiff($new['document'] ?? '', $aux['document'] ?? ''),
340              ];
341          }
342  
343          foreach ($olds->whereNotIn('reference', $used) as $old) {
344              $result[] = [
345                  'reference' => $this->applyDiff('', $old['reference']),
346                  'document' => $this->applyDiff('', $old['document']),
347              ];
348          }
349  
350          return $this->getPaginate(collect($result), 'documentReferences');
351      }
352  
353      public function diffedNonConformities()
354      {
355          $olds = collect($this->oldJson->json['nonconformities']);
356          $news = collect($this->json->json['nonconformities']);
357          $result = [];
358          $used = [];
359  
360          foreach ($news as $new) {
361  
362              $used[] = $new['id'];
363              $aux = $olds->where('id', $new['id'])->first();
364  
365              $result[] = [
366                  'id' => $this->applyDiff($new['id'] ?? '', $aux['id'] ?? ''),
367                  'workunit' => $this->applyDiff($new['workunit'] ?? '', $aux['workunit'] ?? ''),
368                  'observation' => $this->applyDiff($new['observation'] ?? '', $aux['observation'] ?? ''),
369                  'state' => $this->applyDiff($new['state'] ?? '', $aux['state'] ?? ''),
370              ];
371          }
372  
373          foreach ($olds->whereNotIn('id', $used) as $old) {
374              $result[] = [
375                  'id' => $this->applyDiff('', $old['id']),
376                  'workunit' => $this->applyDiff('', $old['workunit']),
377                  'observation' => $this->applyDiff('', $old['observation']),
378                  'state' => $this->applyDiff('', $old['state']),
379              ];
380          }
381  
382          return $this->getPaginate(collect($result), 'nonConformities');
383      }
384  
385      public function diffedComments()
386      {
387          $olds = collect($this->oldJson->json['comments']);
388          $news = collect($this->json->json['comments']);
389          $result = [];
390          $used = [];
391  
392          foreach ($news as $new) {
393  
394              $used[] = $new['id'];
395              $aux = $olds->where('id', $new['id'])->first();
396  
397              $result[] = [
398                  'id' => $this->applyDiff($new['id'] ?? '', $aux['id'] ?? ''),
399                  'workunit' => $this->applyDiff($new['workunit'] ?? '', $aux['workunit'] ?? ''),
400                  'observation' => $this->applyDiff($new['observation'] ?? '', $aux['observation'] ?? ''),
401                  'state' => $this->applyDiff($new['state'] ?? '', $aux['state'] ?? ''),
402              ];
403          }
404  
405          foreach ($olds->whereNotIn('id', $used) as $old) {
406              $result[] = [
407                  'id' => $this->applyDiff('', $old['id']),
408                  'workunit' => $this->applyDiff('', $old['workunit']),
409                  'observation' => $this->applyDiff('', $old['observation']),
410                  'state' => $this->applyDiff('', $old['state']),
411              ];
412          }
413  
414          return $this->getPaginate(collect($result), 'comments');
415      }
416  
417  
418      public function getPaginate(Collection $items, string $pageName, ?bool $isDiffing = false, ?int $perPage = 3): LengthAwarePaginator
419      {
420          $pageName = $pageName . 'Page';
421          $itemsReverse = $isDiffing ? $items->reverse() : $items;
422          return $itemsReverse->paginate($perPage, $itemsReverse->count(), null, $pageName);
423      }
424  
425      public function save(): Redirector
426      {
427          $this->authorize('viewAnyAdmin', Dossier::class);
428  
429          JsonImporterService::acceptDraft($this->json);
430          $this->notification()->success(
431              __('jsons.dialogs.notification.title'),
432              __('jsons.dialogs.notification.description'),
433          );
434  
435          $this->emitSelf('refresh');
436  
437          return redirect()->to(route('jsons.index'));
438      }
439  }