Execute Expression OnShow in MDriven Turnkey - mdriven

I want to initialize some variables and do a search in a viewModel so in "Execute Expression On Show" I put :
vSeekParam := 'Check';
selfVM.Search
In the action that brings the Seeker ViewModel.
When prototyping in WECPOF, it changes the vSeekParam variable, but not when I run the model in Turnkey.
What am I doing wrong?
Thanks

Bringing up views is an asynchronous process - possibly the call to search is to early in OnShow - but if it is - it is undocumented.
Workaround: Add a ViewModel Column IsAction=true and make it periodic by setting the periodicity. In this action you can perform the selfVM.Search.
This is described in this wiki article: https://wiki.mdriven.net/index.php/QR-Code_to_drive_a_workflow_in_any_MDriven_turnkey_app

Related

Passing values to onExit template in an argo workflow

I've stumbled upon a problem when using some more complex argo workflows with initialization and clean-up logic. We are running some initialization in one of the initial steps of the workflow (e.g. creation of some resources) and we'd like to perform a clean-up regardless of the status of the workflow. onExit template seems to be an ideal solution (I think that clean-up is even mentioned in argo documentation as predestined for tasks of the onExit template).
However, I haven't found a way yet to pass some values to it. For example - let's say that in the initialization phase we created some resource with id some-random-unique-id and we'd like to let the onExit container know what resources it needs to clean up.
We tried the outputs of some steps, but it seems that steps are unknown in the onExit template.
Is there a built-in argo mechanism to pass this kind of data? We'd like to avoid some external services (like key-value storage service that would hold the context).
You can mark output parameters as global using the globalName field. A global output parameter, assuming it has been set, can be accessed from anywhere in the Workflow, including in an exit handler.
The example file for writing and consuming global output parameters should contain all the information you need to use global output parameters in an exit handler.
https://github.com/argoproj/argo-workflows/blob/master/examples/global-outputs.yaml
Please share if you found a cleaner solution.
I see this workflow example for exit handler with parameters, which may resolve your issue: Exit Handler with Parameters
One method I found was to add steps to the template I want to call the exit template on, and call the exit template as the last step so I can access steps variables. I changed the original template to an inline template so the structure does not change too much, just involves adding the last step call to the exit template. Unfortunately, this does not utilize the actual onExit method.
Inline steps template example
1.https://sourcegraph.com/github.com/argoproj/argo-workflows/-/blob/examples/exit-handler-with-param.yaml?L21
2.https://raw.githubusercontent.com/argoproj/argo-workflows/master/examples/steps-inline-workflow.yaml

Specify an intent on the ask function

I would like to know, how to specify the function of redirection in the ask function.
Like :
Launch main function to choice the actions.
Start the function chosen by the user.
Loop in this function as long as the user does not say "stop" for example.
Maybe with a specific intent in the ask function, I don't know ...
Does anyone have the solution ?
Your request is what contexts are used for in Dialogflow. You can set it up so that certain intents are only available to be triggered if a certain input context exists. These contexts originate from an output context of an intent.
Using the dialog state is not recommended. If you want to store generic data, you should use app.data in v1 or conv.data in v2 of the AoG client library. This data object persists throughout a session, which is more powerful than dialog state.
You can't. The ask() method is "completed" in the text intent. It is a shame that you can't - the code would be so much less cluttered if you could.
IAC, you can pass "dialog state" to ask() and then getDialogState() in the text intent and use that to restore your application's context and continue from there.

In protractor , when to use protractor.promise.controlFlow() >

I'm confused when to use
var flow = protractor.promise.controlFlow()
in protractor scripts and also I can see a method called execute method flow.execute().
Can Any one give me some example and elaborate above statement
You shouldn't normally need to use the controlFlow yourself unless you are trying to add some asynchronous code into the middle of other webdriver operations. You would basically have to wrap that asynchronous code inside of a promise and the pass that promise/function into the flow.execute(). Here is a good link with more information about Control Flow in WebdriverJS
https://github.com/SeleniumHQ/selenium/wiki/WebDriverJs#control-flows

Delphi Form Creation and Showing

I am trying to create an application with 2 forms in Delphi XE6. Depending on a ParamStr setting Form2 may or may not be shown before Form1.
In a quick test app both forms are created before Form1.Show is invoked - during which Form2 is shown or not
procedure TForm1.FormShow(Sender: TObject);
begin
if ParamStr(1) = 'foo' then
Form2.FooShow;
end;
procedure TForm2.FooShow;
begin
ShowModal;
end;
However in the "real" application I am seeing a different behaviour.
In this case Form1.Show is being called as soon as Application.CreateForm(TForm1, Form1) is called. This is before Form2 is being created, which is causing problems as Form2 doesn't exist when it is needed.
Any explanation why the behaviour would differ? Am I missing a setting buried somewhere in Project>Options
If your form is persisted with Visible set to True, then it will be shown as soon as it's created.
Setting the property to False should resolve your problem.
EDIT
PS: Just in case someone with a similar problem has their main form unexpectedly show even though Visible is set to False. This happens because by default the application will show the main form regardless of its Visible property in the call to Application.Run.
If so, the following question should help: How can I start Delphi application with the hidden main form?
EDIT2
For the sake of completeness, there are a couple other things that could cause a form to be shown as soon as it's created. However, these probably aren't applicable to this specific question.
Any code that explicitly shows the form when it's created (such as the OnCreate event) would obviously cause the form to be shown. However, one would hope that such actions don't lead to these kinds of questions.
An MDI child form can never be hidden. At best it can be minimised.
TIP
The quickest way to finding the answer to such questions is usually just a little bit of debugging.
Set a break-point in your FormShow method.
Go to Compiler Settings, and enable the option to build with debug DCU's. (You'll want to see the VCL code.)
Rebuild and run your application.
When you get to your break-point, open the Call Stack debug window.
Navigate the call-stack looking for the trigger.
In this case you should have found the following code in Forms.pas.
procedure TCustomForm.DoCreate;
begin
//...
if fsVisible in FFormState then Visible := True; //<-- The trigger
end;
And a little more investagation on fsVisible would reveal the root cause as: The Visible property is set to True.
That said, you don't want to be coding this way because you're creating dependencies via globals. This is error-prone; and your little experiment shows shows just one of many subtle things that can cause problems.
Rather avoid the globals with something like the following changes in your DPR:
begin
Application.Initialize;
ShowForms;
end;
Where ShowForms is implemented as:
procedure ShowForms;
var
LForm1: TForm1;
LForm2: TForm2;
begin
Application.CreateForm(TFrom1, LForm1);
Application.CreateForm(TFrom2, LForm2);
if (ParamStr(1) = 'foo') then
LForm2.Show
else
LForm1.Show;
end;
If you don't have any dependencies between the forms, the above will suffice.
If you do have a dependency, e.g. Form2 uses Form1: then you can explicitly pass a reference after creating the forms, bu before you start doing anything with them.
//Define a property on TForm2 E.g.
property MainForm: TForm1 read FMainForm write SetMainForm;
//Immediately after creating both forms tell form2 which to use as its main form.
LForm2.MainForm := LForm1;

Delphi: App initialization - best practices / approach

I run into this regularly, and am just looking for best practice/approach. I have a database / datamodule-containing app, and want to fire up the database/datasets on startup w/o having "active at runtime" set to true at design time (database location varies). Also run a web "check for updates" routine when the app starts up.
Given TForm event sequences, and results from various trial and error, I'm currently using this approach:
I use a "Globals" record set up in the main form to store all global vars, have one element of that called Globals.AppInitialized (boolean), and set it to False in the Initialization section of the main form.
At the main form's OnShow event (all forms are created by then), I test Globals.AppInitialized; if it's false, I run my "Initialization" stuff, and then finish by setting Globals.AppInitialized := True.
This seems to work pretty well, but is it the best approach? Looking for insight from others' experience, ideas and opinions. TIA..
I generally always turn off auto creation of all forms EXCEPT for the main form and possibly the primary datamodule.
One trick that I learned you can do, is add your datamodule to your project, allow it to auto-create and create BEFORE your main form. Then, when your main form is created, the onCreate for the datamodule will have already been run.
If your application has some code to say, set the focus of a control (something you can't do on creation, since its "not visible yet") then create a user message and post it to the form in your oncreate. The message SHOULD (no guarantee) be processed as soon as the forms message loop is processed. For example:
const
wm_AppStarted = wm_User + 101;
type
Form1 = class(tForm)
:
procedure wmAppStarted(var Msg:tMessage); message wm_AppStarted;
end;
// in your oncreate event add the following, which should result in your wmAppStarted event firing.
PostMessage(handle,wm_AppStarted,0,0);
I can't think of a single time that this message was never processed, but the nature of the call is that it is added to the message queue, and if the queue is full then it is "dropped". Just be aware that edge case exists.
You may want to directly interfere with the project source (.dpr file) after the form creation calls and before the Application.Run. (Or even earlier in case.)
This is how I usually handle such initialization stuff:
...
Application.CreateForm(TMainForm, MainForm);
...
MainForm.ApplicationLoaded; // loads options, etc..
Application.Run;
...
I don't know if this is helpful, but some of my applications don't have any form auto created, i.e. they have no mainform in the IDE.
The first form created with the Application object as its owner will automatically become the mainform. Thus I only autocreate one datamodule as a loader and let this one decide which datamodules to create when and which forms to create in what order. This datamodule has a StartUp and ShutDown method, which are called as "brackets" around Application.Run in the dpr. The ShutDown method gives a little more control over the shutdown process.
This can be useful when you have designed different "mainforms" for different use cases of your application or you can use some configuration files to select different mainforms.
There actually isn't such a concept as a "global variable" in Delphi. All variables are scoped to the unit they are in and other units that use that unit.
Just make the AppInitialized and Initialization stuff as part of your data module. Basically have one class (or datamodule) to rule all your non-UI stuff (kind of like the One-Ring, except not all evil and such.)
Alternatively you can:
Call it from your splash screen.
Do it during log in
Run the "check for update" in a background thread - don't force them to update right now. Do it kind of like Firefox does.
I'm not sure I understand why you need the global variables? Nowadays I write ALL my Delphi apps without a single global variable. Even when I did use them, I never had more than a couple per application.
So maybe you need to first think why you actually need them.
I use a primary Data Module to check if the DB connection is OK and if it doesn't, show a custom component form to setup the db connection and then loads the main form:
Application.CreateForm(TDmMain, DmMain);
if DmMain.isDBConnected then
begin
Application.CreateForm(TDmVisualUtils, DmVisualUtils);
Application.CreateForm(TfrmMain, frmMain);
end;
Application.Run;
One trick I use is to place a TTimer on the main form, set the time to something like 300ms, and perform any initialization (db login, network file copies, etc). Starting the application brings up the main form immediately and allows any initialization 'stuff' to happen. Users don't startup multiple instances thinking "Oh..I didn't dbl-click...I'll do it again.."