View Issue Details

This bug affects 1 person(s).
 6
IDProjectCategoryView StatusLast Update
18204Feature requestsPluginspublic2022-09-15 11:21
Reporterollehar Assigned Toollehar  
PrioritynoneSeverityfeature 
Status closedResolutionfixed 
Summary18204: New event: ExtendForm
Description
  • New event in development branch (not the epic branch) No event is needed
  • Event is called extendForm
  • Plugin adds objects to the extendForm event FormExtensionService module
  • Object contains information about which type of input field it is
  • Object does NOT contain any HTML, that’s decided by the application using the event
  • Object also contains a function to save the POST data into database, for its input
  • Save function takes request object, and should not access any super-globals like $_GET or $_POST
  • Object implements an interface, e.g. ExtendFormInputInterface, so that other objects can be added later (for dropdown, date picker, select2 etc etc)
  • Each form has an id string, so that objects are attached to the correct form
  • Manual must be updated, so that other developers can use it
TagsNo tags attached.
Bug heat6
Story point estimate
Users affected %

Users monitoring this issue

There are no users monitoring this issue.

Activities

ollehar

ollehar

2022-06-21 13:11

administrator   ~70423

Last edited: 2022-06-21 13:12

Ping @DenisChenu and @gabrieljenik if you're interested. We will work on this internally and initially only support global settings form and input checkbox.

Added to LS5 LTS, I guess (dev branch).

DenisChenu

DenisChenu

2022-06-21 14:20

developer   ~70424

You mean : for GroupSettings ? UserSettings ? near SurveySettings

Something related to an object with an id ?

https://manual.limesurvey.org/BeforeSurveySettings
https://manual.limesurvey.org/NewSurveySettings

ollehar

ollehar

2022-06-21 14:30

administrator   ~70425

This would be a general event for any form that supports it. So, one form event to rule them all. :)

DenisChenu

DenisChenu

2022-06-21 14:36

developer   ~70426

But : you need to review all existing form then ?

Before : need to review core form …

Each form has an id used by the event, so that objects are attached to the correct form

https://github.com/LimeSurvey/LimeSurvey/blob/baf7a27369fab4bb10bacb467790e046385da591/application/models/PluginSetting.php#L21-L22

ollehar

ollehar

2022-06-21 14:37

administrator   ~70427

Yeah, but we're just gonna support global settings for now. Rest are added when needed by a plugin author.

ollehar

ollehar

2022-06-21 14:39

administrator   ~70428

Last edited: 2022-06-21 14:39

$event->append('globalsettings', new ExtendFormCheckbox('input_id', function($post, $connection) { ... save logic here }));
DenisChenu

DenisChenu

2022-06-21 14:44

developer   ~70429

:(

To add 3elements

$event->append('globalsettings', new ExtendFormCheckbox('input_id', function($post) { ... save logic here }));
$event->append('globalsettings', new ExtendFormCheckbox('input_id2', function($post) { ... save logic here /* Same than previous*/ }));
$event->append('globalsettings', new ExtendFormCheckbox('input_id3', function($post) { ... save logic here /* copy/paste from previous*/  }));

I never have to update global settings ,

See how i do to create forum since some years now (and it work without update plugin …) : https://gitlab.com/SondagesPro/mailing/sendMailCron/-/blob/master/sendMailCron.php#L1403

We already hae 2 form constructor : one for Survey and one for QuestionAttribute.
You add another one …

ollehar

ollehar

2022-06-21 14:52

administrator   ~70430

No no.

$saveMethod = function($post, $db) { ... };
$event->append('globalsettings', new ExtendFormCheckbox('input_id', $saveMethod));
etc
ollehar

ollehar

2022-06-21 14:52

administrator   ~70431

We already have 2 form constructor : one for Survey and one for QuestionAttribute.

Let me read those again, then. But I doubt they are really flexible, nor object oriented...

DenisChenu

DenisChenu

2022-06-21 14:54

developer   ~70432

Let me read those again, then. But I doubt they are really flexible, nor object oriented...

Not really flexible … right.

ollehar

ollehar

2022-06-21 15:07

administrator   ~70433

OK, so how would you add a new select2 or datepicker as a survey setting...?

ollehar

ollehar

2022-06-21 15:10

administrator   ~70434

Ah, it's using the SettingsWidget. Also used by plugin settings, right? I thought about that one...

DenisChenu

DenisChenu

2022-06-21 15:12

developer   ~70435

Like always … «je me débrouille comme je peux»

example : https://gitlab.com/SondagesPro/OrcidAuthenticate/-/blob/master/views/admin/IntroductionSetting.php

ollehar

ollehar

2022-06-21 15:12

administrator   ~70436

Last edited: 2022-06-21 15:13

So you'd prefer $event->append('globalsettings.tab', ...settings widget data)?

DenisChenu

DenisChenu

2022-06-21 15:15

developer   ~70437

I prefer something easy and stable ;)

I think i already create a mantis issue about moving QuestoionAttributes + CoreForms + PluginSettings to same extension .

Else : i thionk have a definition array without need to create new object each time still instresting

ollehar

ollehar

2022-06-21 15:18

administrator   ~70438

Arrays require more writing than objects, tho. And they have no validation, or defaults. But a middle-ground is to have objects with $input->toSettingsWidget() function that converts them. Idk.

DenisChenu

DenisChenu

2022-06-21 15:24

developer   ~70439

Arrays require more writing than objects, tho.

?
You mean by core team ?

And they have no validation, or defaults.

core can offer some … PluginSettings have htmlOptions and current

$saveMethod = function($post, $db) { ... };
$event->append('globalsettings', new ExtendFormCheckbox('input_id', $saveMethod));

default saveMethod by core can be great
(for example : i think i creat an issue about save Plugin settings password encrypted by default …)

ollehar

ollehar

2022-06-21 15:25

administrator   ~70440

Idk, the settings widget is doing a lot of shit... Starting form tags, registering css and js files, ... It should have been an object hierarchy rather, SettingsWidgetButton, SettingsWidgetBoolean, etc, instead of a function for every setting type. Then it could have been reused in different contexts.

DenisChenu

DenisChenu

2022-06-21 15:28

developer   ~70441

Yes …
but : if you create another way, do you deprecated and removed old ways ?
And then : we have to redo whole plugins in 7 or 8 ?

ollehar

ollehar

2022-06-21 15:30

administrator   ~70442

default saveMethod by core can be great

Ya, but not sure how... xD Needs info about database table and column and validation. Basically model data.

$saveMethod = new DefaultSaveMethod('table', 'column', $validationRules);

??

ollehar

ollehar

2022-06-21 15:32

administrator   ~70443

but : if you create another way, do you deprecated and removed old ways ?
And then : we have to redo whole plugins in 7 or 8 ?

Urgh. No.

DenisChenu

DenisChenu

2022-06-21 15:34

developer   ~70444

Why not use PluginSettings table by default ?

When i mean default : a default table + way to save.
Plugin dev can replace by it's own function.

I already use PluginSettings table to save User related data.

DenisChenu

DenisChenu

2022-06-21 15:34

developer   ~70445

Urgh. No.

Then seem:s best to move (after) PluginSettings to the new ExtendForm system, no ?

ollehar

ollehar

2022-06-21 15:35

administrator   ~70446

We also have AdvancedSettingWidget and GeneralOptionWidget for question editor.

Already based on DTOs.

https://github.com/LimeSurvey/LimeSurvey/tree/master/application/extensions/GeneralOptionWidget/settings

DenisChenu

DenisChenu

2022-06-21 15:37

developer   ~70447

Yes,
And we have 2 separate system with a lot of same code …

PS : AdvancedSettingWidget are for QuestionAttribute

ollehar

ollehar

2022-06-21 15:37

administrator   ~70448

Why not use PluginSettings table by default ?

Hmmm, yes, this works, true.

DenisChenu

DenisChenu

2022-06-21 15:38

developer   ~70450

We also have AdvancedSettingWidget and GeneralOptionWidget for question editor.

Lack of optionnal htmlOptions (html5) and way to extend

ollehar

ollehar

2022-06-21 15:41

administrator   ~70451

What's HTML5 html options?

Extend how? Something else than new attributes?

DenisChenu

DenisChenu

2022-06-21 15:49

developer   ~70452

Oups …
I mean any attributes : min/max for number, pattern, disabled, placeholder etc … :)

ollehar

ollehar

2022-06-22 10:17

administrator   ~70477

Last edited: 2022-06-22 10:25

Actually, does this even need to be an event? We can have a service provider or module instead, where you can add input elements during system init. So.

// Plugin init
public function init()
{
  App()->extendedForm->append('globalsettings', new Input());
}

And then application code just fetch inputs from that service locator when needed.

DenisChenu

DenisChenu

2022-06-22 10:35

developer   ~70478

Need to be in API then , not in App only.

https://github.com/LimeSurvey/LimeSurvey/blob/master/application/libraries/PluginManager/LimesurveyApi.php

Then it's clearly set it can be used without issue since API version are not updated.

ollehar

ollehar

2022-06-22 10:37

administrator   ~70479

Hm, yes, correct.

ollehar

ollehar

2022-09-01 11:14

administrator   ~71571

Would you prefer to have two new events instead, Denis?

BeforeGlobalSettings - to add new global setting
NewGlobalSettings - to save new global setting

DenisChenu

DenisChenu

2022-09-01 11:16

developer   ~71572

Unsure …
I don't really like 2 events, but like to be allowed to replace the way to save …

See wiith @gabrieljenik

ollehar

ollehar

2022-09-01 11:16

administrator   ~71573

Yes, I've pinged Gabriel on Cliq too.

gabrieljenik

gabrieljenik

2022-09-01 15:25

manager   ~71592

Last edited: 2022-09-01 15:33

I think I caught the main ideas.
Still, a summary or a document where the blueprint can be consolidated would be great.

Some issues/discussions I believe I noticed:

Event for each control

I think this will be too complex, either for implementing from the plugin side, as well as for the plgin invocation side.
I would rather go with something like BeforeGlobalSettings, the parameters received there can have all necesarry to add the extra controls.

Also, the saving event needs to be one. We can't have each control with its own saving rutine. (If I understood correctly).

Validation Event

I believe a validation event is missing and an error message flow could be missing.
Validation not only on the custom controls, but also on the standard controls.

Other events

I would also allow a place to add JS and CSS when the form is shown.

Control Setup

I would reuse what we have in the plugin settings.
Actually try to share it as to have it evolved hand in hand.

It could be important to be able to set the position of the extra controls.

AfterCloseForm

Would be great to be able to have an event like that to inject extra HTML

Comments

Can we reuse something from WP hooks maybe?

Also, on the plugin setup, maybe we can have something for enabling and disabling for specific forms?
Would be easier to deactivate in case of mal-functioning.

We could have the plugin to setup the events by providing an object of a specific class?

ollehar

ollehar

2022-09-01 16:50

administrator   ~71594

Last edited: 2022-09-01 17:40

Hm, yeah, maybe I can try to write a short spec in the manual, including some example code.

Good point about validation. I guess the input objects could throw an exception, like InvalidInputException, and then the application code could catch it and show a warning.

Scripts could also be added as objects, but classes like class ScriptInput that output <script> at rendering. Same for CSS.

I wanted to avoid injecting raw HTML. But I guess we can do a RawHtml class too, for those cases. :d

I was thinking of trying to re-use the plugin settings widget, if possible. Would have to look more closely.

Some more conceptual example code:

class MyPlugin ...
public function init() {
  App()->extendForm->add('globalsettings', new RawHtmlInput('<h1>Moo</h1>'));
  App()->extendForm->add('globalsettings', new ScriptInput($fileLocation));
  App()->extendForm->add('globalsettings', new CheckboxInput('checkbox_id', function ($request) { throw new InvalidInputException("Wrong!")); }));
}

Then in the global settings view file, you'd have something like

<?= PluginInputWidget->render(App()>->extendForm->get('globalsettings'); ?>

And in the controller save action:

// Loops all input objects associated to "globalsettings" and apply their save() methods.
// Also catches the InvalidInputException and adds warning/error messages
App()->extendForm->applySave('globalsettings', $request, $database);  

Hm, maybe formInputService is a better module name than extendForm.

And also, maybe applySave() must return bool rather then echoing warning HTML, so that each controller can decide what to do with the information. Might be different.

gabrieljenik

gabrieljenik

2022-09-01 19:46

manager   ~71596

Good point about validation. I guess the input objects could throw an exception, like InvalidInputException, and then the application code could catch it and show a warning.

I was thinking something a but more similar to how Yii validations work.
That exception mechanism you mention seems a bit more complicated and not sure if will allow to handle multiple error messages.

Some more conceptual example code:

By how you wrote it there, seems like you are adding individual fields, as opposed to adding an extension, which has fields, validations, ....
I am more inclined towards the later, as some settings or behaviour will be attached to the extension.

Also, how to handle multuple extensions to the same form?
Just multiple plugins?

ollehar

ollehar

2022-09-02 10:53

administrator   ~71597

Last edited: 2022-09-02 11:03

I was thinking something a but more similar to how Yii validations work.

Hm, you're thinking of active record rules? Or the form functionality?

That exception mechanism you mention seems a bit more complicated and not sure if will allow to handle multiple error messages.

No problem, the formExtensionService module will just loop the inputs and insert a message for each exception it catches. :)

By how you wrote it there, seems like you are adding individual fields, as opposed to adding an extension, which has fields, validations, ....

Yeah, the formExtensionService module would be core code, that accepts individual fields from the plugin init() function.
Maybe you can show some pseudocode or concept on how you'd like to add an extension from the plugin itself?

Also, how to handle multiple extensions to the same form?

The formExtensionService maps form names to input arrays, like

class FormExtensionService {
  private $extensions = []
  public function add(string $formName, FormExtensionInterface $input) {
    $this->extensions[$formName][] = $input;
  }
}

But we would probably also have to consider tabs. So $formName might be "globalsettings", or like "globalsettings.email_settings", where the word after the dot is the name of the tab.

ollehar

ollehar

2022-09-06 18:12

administrator   ~71611

Some issues:

  • Localization and label
  • Permission
ollehar

ollehar

2022-09-06 18:12

administrator   ~71612

Work started on branch feature/18204-extend-form, trying to use the plugin SettingsWidget at first

ollehar

ollehar

2022-09-06 18:16

administrator   ~71613

As you can see, the SettingsWidget HTML is not adapted to global settings form HTML.

pic.png (128,401 bytes)
ollehar

ollehar

2022-09-06 18:29

administrator   ~71614

Missing:

  • Populate from database (need a load() function?)
  • Conditions for viewing (might include permission, so maybe a function for condition() or such...?)
ollehar

ollehar

2022-09-06 18:38

administrator   ~71615

And of course each stupid form has some extra CSS classes that must be obeyed... Hm, maybe factor out render-classes? That can be populated from the form name? So form "globalsettings" has render classes for each input type?

ollehar

ollehar

2022-09-06 19:36

administrator   ~71617

Got something basic running now. Used the exampleSettings plugin, with this code in init():

        Yii::app()->formExtensionService->add(
            'globalsettings.general',
            new TextInput(
                'myinput',
                'Label',
                // Save function
                function($request, $connection) {
                    SettingGlobal::setSetting('myinput', $request->getPost('myinput'));
                },
                // Load function
                function () {
                    return getGlobalSetting('myinput');
                }
            )
        );
ollehar

ollehar

2022-09-06 19:38

administrator   ~71618

Here's the renderer class for global settings: https://github.com/LimeSurvey/LimeSurvey/blob/feature/18204-extend-form/application/libraries/FormExtension/Inputs/GlobalSettingsRenderer.php

DenisChenu

DenisChenu

2022-09-06 19:52

developer   ~71619

Last edited: 2022-09-06 19:55

Here's the renderer class for global settings:

Seems great !
Lot of work , but after : just some file to update to BS6 (for example)

And of course each stupid form has some extra CSS classes that must be obeyed

Ye s: but here : maybe all form need to have same presentation, same css class etc …

ollehar

ollehar

2022-09-06 19:57

administrator   ~71620

Last edited: 2022-09-06 19:59

Lot of work , but after : just some file to update to BS6 (for example)

Yes, the plugin authors would not have to touch the plugins to make sure the HTML is up to date, then. :)

Hm, if save() is taken care of in the plugins, beforeControllerAction(), then it could be enough with this widget snippet to make a form extensible (assuming there's a renderer for that form):

<?= FormExtensionWidget::render(
    App()->formExtensionService->getAll('globalsettings.general'),
    new GlobalSettingsRenderer()
); ?>

Else you need the save code in the controller too:

Yii::app()->formExtensionService->applySave('globalsettings', $request);

ollehar

ollehar

2022-09-06 19:58

administrator   ~71621

 Ye s: but here : maybe all form need to have same presentation, same css class etc …

There should be a DefaultRenderer class that should work in most places...

ollehar

ollehar

2022-09-07 12:35

administrator   ~71625

Last edited: 2022-09-07 12:45

The downside of letting the FormExtensionService class add flash messages - in the pic, the example input threw an exception, and now we have two messages - one success and on failing. :/

But this is necessary to make the change as small as possible to add support to customize one of the forms.

Hm, I also made applySave() return a bool for success, so that the controller can adapt, if it wants to.

image.png (144,321 bytes)
gabrieljenik

gabrieljenik

2022-09-07 13:31

manager   ~71626

Last edited: 2022-09-07 13:32

Nice work!!!

Please find some comments:

https://bugs.limesurvey.org/view.php?id=18204#c71617
Got something basic running now. Used the exampleSettings plugin, with this code in init():

You would need to do a save and a run for every new field?
I believe the load() and save() should be at form-extension level.

https://bugs.limesurvey.org/view.php?id=18204#c71614
Missing

What about setting default values?

https://bugs.limesurvey.org/view.php?id=18204#c71618
Renderer

Is there a place where plugin authors can set which renderer to use per field?

https://bugs.limesurvey.org/view.php?id=18204#c71625
The downside of letting the FormExtensionService class add flash messages

Maybe we can show a summary instead of 2 separated flash messages.
I believe that could be possible. I remember working on something close to that couple of months ago.

ollehar

ollehar

2022-09-07 15:07

administrator   ~71627

You would need to do a save and a run for every new field?

Ya, it's not performant. It's designed to have minimal code impact on the core code-base, so that's easy to add support for more forms, with a very small PR.

What about setting default values?

Default value can be part of the load() function. :) Just return a default value if non is found in database.

Is there a place where plugin authors can set which renderer to use per field?

That would defeat the purpose. :D The purpose is to make plugin author oblivious to the html, since it might be different in different LS versions, and for different forms.

Maybe we can show a summary instead of 2 separated flash messages.

Maybe, not sure if that would require more changes to the controllers tho. Or standardize it somehow.

ollehar

ollehar

2022-09-07 15:17

administrator   ~71628

Do we really need classes for JS and CSS scripts? That can also be done in beforeControllerAction, right?

gabrieljenik

gabrieljenik

2022-09-07 16:21

manager   ~71629

You would need to do a save and a run for every new field?

Ya, it's not performant. It's designed to have minimal code impact on the core code-base, so that's easy to add support for more forms, with a very small PR.

Where is that hook called from?
Can you point me out? As to get some context

Is there a place where plugin authors can set which renderer to use per field?

That would defeat the purpose. :D The purpose is to make plugin author oblivious to the html, since it might be different in different LS versions, and for different forms.

Yes, but it will allow to do easier customizations per field if needed and wanted

Maybe we can show a summary instead of 2 separated flash messages.

Maybe, not sure if that would require more changes to the controllers tho. Or standardize it somehow.

We can think of something for that I believe. Standarized. Don't think of that as the reatest challenge
Still, of course can be left for later.

gabrieljenik

gabrieljenik

2022-09-07 16:21

manager   ~71630

What about validations?
How can we stop everything from being saved (std + custom)?

ollehar

ollehar

2022-09-07 16:24

administrator   ~71631

How can we stop everything from being saved (std + custom)?

You can't. That's also a thing that causes too much code impact to core code. You can only prevent save + validate in your save() method, per input field.
You have a use-case for preventing the entire save from happening?
I mean, you can always throw an Exception exception, to stop the entire process. :)

ollehar

ollehar

2022-09-07 16:26

administrator   ~71632

Yes, but it will allow to do easier customizations per field if needed and wanted

You have the RawHtml thing for that, I guess. Currently it doesn't try to save, but I can change that, if you want. Or you use beforeActionController to save it.

ollehar

ollehar

2022-09-07 16:31

administrator   ~71633

Where is that hook called from?

Here's the hook for saving: https://github.com/LimeSurvey/LimeSurvey/blob/feature/18204-extend-form/application/controllers/admin/globalsettings.php#L408

Here's the hook for rendering: https://github.com/LimeSurvey/LimeSurvey/blob/feature/18204-extend-form/application/views/admin/globalsettings/_general.php#L377

So you only need two small changes to support a new form (but, sadly, also in this case a new GlobalSettingsRenderer class).

ollehar

ollehar

2022-09-07 17:44

administrator   ~71634

@DenisChenu You have any other comments here, regarding different use-cases? As mentioned, it's adapted for small changes, not to add entire new pages or tabs.

ollehar

ollehar

2022-09-07 18:07

administrator   ~71635

Manual entry here: https://manual.limesurvey.org/Plugins_-_advanced#Form_extension_.28New_in_6_.29

gabrieljenik

gabrieljenik

2022-09-08 12:55

manager   ~71644

Quick thought: If this approach will be for individual fields being added to specific places... Why not already providing the means for saving it? I mean KeyValue table, saving routine, Loading as well, ...

ollehar

ollehar

2022-09-08 13:06

administrator   ~71645

Quick thought: If this approach will be for individual fields being added to specific places... Why not already providing the means for saving it? I mean KeyValue table, saving routine, Loading as well, ...

Flexibility, mostly. The obvious place to store is in plugin settings storage, but maybe some plugin would like to do some logic or who knows? So passing a save-function gives the dev access to custom logic. But yes, we could include default save-functions, sure. :) new DefaultSaveFunction("input_name"), and make the class implement __invoke.

gabrieljenik

gabrieljenik

2022-09-08 13:17

manager   ~71646

Another thing to take into account then would be:
The form type: Per User, Global, Per Survey, ...

We could provide the related object on the context.
Also, that would impact the automatic saving routines.

ollehar

ollehar

2022-09-08 13:20

administrator   ~71647

Hmmm, what do you mean with form type? The specific form?

The related form object? If there is such?

ollehar

ollehar

2022-09-08 13:22

administrator   ~71648

Merged into develop, because I need to backport it to our cloud, but we can still make changes. Dev branch won't be released for 2 months at least.

gabrieljenik

gabrieljenik

2022-09-08 13:26

manager   ~71649

Hmmm, what do you mean with form type? The specific form?
The related form object? If there is such?

Yes. Is this a user level form? A survey level form, ... ?

ollehar

ollehar

2022-09-08 14:23

administrator   ~71652

Yes. Is this a user level form? A survey level form, ... ?

Aha. What's the related use-case? I see your point, but the usefulness is not obvious to me, sorry. :)

ollehar

ollehar

2022-09-15 11:21

administrator   ~71758

This has been merged into develop. Branch deleted.

Issue History

Date Modified Username Field Change
2022-06-21 13:10 ollehar New Issue
2022-06-21 13:10 ollehar Status new => assigned
2022-06-21 13:10 ollehar Assigned To => ollehar
2022-06-21 13:11 ollehar Note Added: 70423
2022-06-21 13:11 ollehar Bug heat 0 => 2
2022-06-21 13:12 ollehar Note Edited: 70423
2022-06-21 14:20 DenisChenu Note Added: 70424
2022-06-21 14:20 DenisChenu Bug heat 2 => 4
2022-06-21 14:30 ollehar Note Added: 70425
2022-06-21 14:36 DenisChenu Note Added: 70426
2022-06-21 14:37 ollehar Note Added: 70427
2022-06-21 14:39 ollehar Note Added: 70428
2022-06-21 14:39 ollehar Note Edited: 70428
2022-06-21 14:39 ollehar Note Edited: 70428
2022-06-21 14:44 DenisChenu Note Added: 70429
2022-06-21 14:52 ollehar Note Added: 70430
2022-06-21 14:52 ollehar Note Added: 70431
2022-06-21 14:54 DenisChenu Note Added: 70432
2022-06-21 15:07 ollehar Note Added: 70433
2022-06-21 15:10 ollehar Note Added: 70434
2022-06-21 15:12 DenisChenu Note Added: 70435
2022-06-21 15:12 ollehar Note Added: 70436
2022-06-21 15:12 ollehar Note Edited: 70436
2022-06-21 15:13 ollehar Note Edited: 70436
2022-06-21 15:15 DenisChenu Note Added: 70437
2022-06-21 15:18 ollehar Note Added: 70438
2022-06-21 15:24 DenisChenu Note Added: 70439
2022-06-21 15:25 ollehar Note Added: 70440
2022-06-21 15:28 DenisChenu Note Added: 70441
2022-06-21 15:30 ollehar Note Added: 70442
2022-06-21 15:32 ollehar Note Added: 70443
2022-06-21 15:34 DenisChenu Note Added: 70444
2022-06-21 15:34 DenisChenu Note Added: 70445
2022-06-21 15:35 ollehar Note Added: 70446
2022-06-21 15:37 DenisChenu Note Added: 70447
2022-06-21 15:37 ollehar Note Added: 70448
2022-06-21 15:38 DenisChenu Note Added: 70450
2022-06-21 15:41 ollehar Note Added: 70451
2022-06-21 15:49 DenisChenu Note Added: 70452
2022-06-22 10:17 ollehar Note Added: 70477
2022-06-22 10:25 ollehar Note Edited: 70477
2022-06-22 10:25 ollehar Note Edited: 70477
2022-06-22 10:35 DenisChenu Note Added: 70478
2022-06-22 10:37 ollehar Note Added: 70479
2022-08-31 12:38 ollehar Description Updated
2022-08-31 12:38 ollehar Steps to Reproduce Updated
2022-09-01 11:14 ollehar Note Added: 71571
2022-09-01 11:16 DenisChenu Note Added: 71572
2022-09-01 11:16 ollehar Note Added: 71573
2022-09-01 15:25 gabrieljenik Note Added: 71592
2022-09-01 15:25 gabrieljenik Bug heat 4 => 6
2022-09-01 15:31 gabrieljenik Note Edited: 71592
2022-09-01 15:33 gabrieljenik Note Edited: 71592
2022-09-01 16:50 ollehar Note Added: 71594
2022-09-01 16:59 ollehar Note Edited: 71594
2022-09-01 17:00 ollehar Note Edited: 71594
2022-09-01 17:40 ollehar Note Edited: 71594
2022-09-01 17:40 ollehar Note Edited: 71594
2022-09-01 19:46 gabrieljenik Note Added: 71596
2022-09-02 10:53 ollehar Note Added: 71597
2022-09-02 10:54 ollehar Note Edited: 71597
2022-09-02 11:02 ollehar Note Edited: 71597
2022-09-02 11:03 ollehar Note Edited: 71597
2022-09-06 18:12 ollehar Note Added: 71611
2022-09-06 18:12 ollehar Note Added: 71612
2022-09-06 18:16 ollehar Note Added: 71613
2022-09-06 18:16 ollehar File Added: pic.png
2022-09-06 18:29 ollehar Note Added: 71614
2022-09-06 18:38 ollehar Note Added: 71615
2022-09-06 19:36 ollehar Note Added: 71617
2022-09-06 19:38 ollehar Note Added: 71618
2022-09-06 19:52 DenisChenu Note Added: 71619
2022-09-06 19:55 DenisChenu Note Edited: 71619
2022-09-06 19:57 ollehar Note Added: 71620
2022-09-06 19:58 ollehar Note Added: 71621
2022-09-06 19:59 ollehar Note Edited: 71620
2022-09-06 19:59 ollehar Note Edited: 71620
2022-09-06 19:59 ollehar Note Edited: 71620
2022-09-07 12:35 ollehar Note Added: 71625
2022-09-07 12:35 ollehar File Added: image.png
2022-09-07 12:36 ollehar Note Edited: 71625
2022-09-07 12:45 ollehar Note Edited: 71625
2022-09-07 13:31 gabrieljenik Note Added: 71626
2022-09-07 13:32 gabrieljenik Note Edited: 71626
2022-09-07 15:07 ollehar Note Added: 71627
2022-09-07 15:07 ollehar Description Updated
2022-09-07 15:07 ollehar Description Updated
2022-09-07 15:08 ollehar Description Updated
2022-09-07 15:17 ollehar Note Added: 71628
2022-09-07 16:21 gabrieljenik Note Added: 71629
2022-09-07 16:21 gabrieljenik Note Added: 71630
2022-09-07 16:24 ollehar Note Added: 71631
2022-09-07 16:26 ollehar Note Added: 71632
2022-09-07 16:31 ollehar Note Added: 71633
2022-09-07 17:44 ollehar Note Added: 71634
2022-09-07 18:07 ollehar Note Added: 71635
2022-09-08 12:55 gabrieljenik Note Added: 71644
2022-09-08 13:06 ollehar Note Added: 71645
2022-09-08 13:17 gabrieljenik Note Added: 71646
2022-09-08 13:20 ollehar Note Added: 71647
2022-09-08 13:22 ollehar Note Added: 71648
2022-09-08 13:26 gabrieljenik Note Added: 71649
2022-09-08 14:23 ollehar Note Added: 71652
2022-09-15 11:21 ollehar Status assigned => closed
2022-09-15 11:21 ollehar Resolution open => fixed
2022-09-15 11:21 ollehar Note Added: 71758