2024年2月16日金曜日

オラクルの公式ブログMulti Level Expense Approval using APEX Workflowのワークフローを理解する

Oracle CorporationでAPEXワークフローを開発しているAnanya Chatterjeeさんが、オラクルの公式ブログに以下の記事を寄稿しています。

Multi Level Expense Approval using APEX Workflow

Ananya ChatterjeeさんはOracle APEXの承認タスクの開発も行なっています。APEXワークフローがリリースされる前のAPEXで、承認タスクによる多段階承認の実装を紹介する記事も書かれています。

Implementing Multi-Approvals in Oracle APEX 22.1
https://blogs.oracle.com/apex/post/implementing-multi-approvals-in-oracle-apex-221

承認タスクを使った多段階認証の実装については、本ブログでも以下の記事で紹介しています。

APEX 22.1の承認コンポーネント(4) - 多段階承認の実装

Oracle APEX 23.2からAPEXワークフローが提供されたため、承認タスクによる多段階承認の記事に以下のコメントが追記されました。
Note: With the availability of Workflow feature in APEX 23.2 release, it is now possible to visualize and design multi-level approvals in a more declarative manner, which you can read about in another blog. This blog is still relevant if you are looking to use using Approval Components, standalone, without Workflow and is also relevant for pre 23.2 versions of APEX.

APEX 23.2以降あれば、多段階承認はAPEXワークフローで実装することを推奨していると言えます。

以下より、ブログ記事「Multi Level Expense Approval using APEX Workflow」で作成しているワークフローで、多段階承認をどう実装しているのか説明しようと思います。ワークフローを組み込んだアプリケーションは、元記事の手順にそって作業を行うことで作成できます。英語ですが、手順が具体的でコードおよびスクリーンショットも揃っていることから、作業はそれほど難しくありません。

本記事では、ワークフローを以下のように若干簡素にしています。電子メールの送信アクティビティを削除し、ワークフロー終了に接続しています。


以下より、多段階承認のワークフローを確認していきます。

最初に経費精算の承認ワークフローを開始します。

ユーザーSTEVEでサインインし、経費申請を行います。以下の画面で重要なパラメータはExpense Amount、つまり費用です。


費用はページ・アイテムP4_EXPENSE_AMOUNTに入力されます。


ボタンSUBMITを押すと、経費精算のワークフロー(定義はExpense Reimbursement Workflow)が開始します。


ワークフロー・パラメータAmountにページ・アイテムP4_EXPENSE_AMOUNTの値を割り当てています。ワークフロー・パラメータはワークフローの開始時に値が設定され、開始後は値を変更することはできません。経費精算の承認処理を行なっている間に、申請した費用が変更されたら困ります。経費申請の申請者や費用といった、ワークフローの処理中に変更できない値をワークフロー・パラメータとして設定します。


ワークフローExpense Reimbursement Workflowを確認します。

ワークフロー・パラメータとしてAmountが設定されています。このパラメータにページ・アイテムP4_EXPENSE_AMOUNTの値が設定されます。ワークフローの中でこのパラメータは静的IDAMOUNTより参照します。

Oracle APEXでは、ページ・アイテムアプリケーション・アイテムの値をバインド変数置換文字列として参照できますが、その際はページ・アイテムやアプリケーション・アイテムの名前を指定します。ワークフローのワークフロー・パラメータおよびワークフロー・バージョン変数は名前の代わりに静的IDを指定して参照します。


ワークフローが開始すると、最初にアクティビティCompute Max Levelが実行されます。このアクティビティでは以下のPL/SQLコードが実行されます。
declare
    level_no number;
begin
    if :AMOUNT < 500 then
        level_no := -1;
    elsif :AMOUNT < 1000 then
        level_no := 1;
    elsif :AMOUNT < 5000 then
        level_no := 2;
    else
        level_no := 3;
    end if;
    :MAX_LEVEL := level_no;
end;
申請した費用が500より少なければMAX_LEVEL-11000より少なければ 15000より少なければ 2、それ以上は 3 を設定しています。

表APPROVAL_LEVELSに、以下のシード・データが挿入されています。
insert into APPROVAL_LEVELS values (10, 'JANE', 'jane@expenseteam.com', 1);
insert into APPROVAL_LEVELS values (20, 'MATT', 'martin@expenseteam.com', 1);
insert into APPROVAL_LEVELS values (30, 'BO', 'bo@expenseteam.com', 2);
insert into APPROVAL_LEVELS values (40, 'CLARA', 'clara@expenseteam.com', 2);
insert into APPROVAL_LEVELS values (50, 'SUSIE', 'susie@expenseteam.com', 3);
このワークフローでは、費用が500より少なければ自動承認、1000より少なければ承認レベル(表APPROVAL_LEVELSの列LEVEL_CODEの値)が1であるJANEかMATTが承認が必要、1000以上5000未満ではさらに承認レベルが2であるBOかCLARAの承認が必要、それ以上はさらに承認レベルが3であるSUSIEの承認が必要、という承認フローを実装しています。


MAX_LEVELワークフロー・バージョン変数として作成されています。


続く切替えApproval Needed?では、ワークフロー・バージョン変数MAX_LEVEL-1であれば自動承認としてワークフローを終了させ、それ以外(1か2か3)であれば、ヒューマン・タスクを生成するアクティビティCreate Approved Requestへ進みます。


アクティビティCreate Approval Requestでは、承認タスクReimbursement Requestを作成します。承認タスクの結果はワークフロー・バージョン変数TASK_OUTCOMEに設定され、後続の切替えApproved?により参照されます。承認タスクの結果はAPPROVEDまたはREJECTEDです。


承認タスクReimbursement RequestのパラメータにLevel Noがあります。Level Noには、ワークフロー・バージョン変数CURRENT_LEVELが割り当てられています。


ワークフロー・バージョン変数CURRENT_LEVELには、タイプ静的値静的値として1が設定されています。ワークフロー・バージョン変数はアクティビティによって変更できるため、この値は初期値またはデフォルト値になります。


承認タスクReimbursement Requestのタスク定義では、潜在的所有者SQL問合せが設定されています。
select mgr_name from approval_levels where level_code = :LEVEL_NO
パラメータLEVEL_NOにはアクティビティCreate Approval Requestが呼び出された時点でのワークフロー・バージョン変数CURRENT_LEVELの値が割り当てられて、承認タスクが作成されます。つまりCreate Approval Requestの初回呼び出し時はCURRENT_LEVELは初期値のなので、LEVEL_NOになります。

結果として費用が500以上の経費申請(自動承認の対象にならない経費申請)は、最初に承認レベルが1のJANEかMATTのどちらかの承認を必要とします。


JANEかMATTが承認タスクを承認すると、切替えApproved?を経由して切替えAll Approvals Completed?へ進みます。

反対に承認タスクを却下すると、切替えRejected At First Level?に進みます。


切替えAll Approvals Completed?では、ワークフロー・バージョン変数CURRENT_LEVELと比較する切替えタイプが設定されています。タイプCheck Workflow Variableでは、実際の条件は切替えから伸びている接続に設定されます。


切替えAll Approvals Completed?とアクティビティIncrement Levelの接続No条件として&MAX_LEVEL.より小さいが設定されています。申請した費用が4000のときはMAX_LEVELが2なのでCURRENT_LEVELより小さいため、こちらの接続が選択されます。

それ以外、つまりMAX_LEVELCURRENT_LEVELが同じ値であれば、経費申請が承認されてワークフローは終了します。


アクティビティIncrement Levelでは以下のPL/SQLコードが実行されます。ワークフロー・バージョン変数CURRENT_LEVELに1が加算されます。
begin
:CURRENT_LEVEL := :CURRENT_LEVEL+1;
end;
その後、アクティビティCreate Approval Requestが呼び出されます。アクティビティCreate Approval Requestにて作成される承認タスクの潜在的所有者はパラメータLEVEL_NO、つまりワークフロー・バージョン変数CURRENT_LEVELで決まります。CURRENT_LEVEL2の場合、承認レベルがのBOかCLARAの承認が必要になります。


JANEかMATTが承認タスクを却下した場合は、切替えRejected at First Level?に進みます。この切替えは条件として、CURRENT_LEVEL1であれば経費申請を却下してワークフローを終了します。

JANEかMATTが経費申請を承認し、次の承認レベルのBOからCLARAにより経費申請が却下されるとCURRENT_LEVELは2になるため、アクティビティReset Levelに進みます。


アクティビティReset Levelでは以下のPL/SQLコードを実行し、CURRENT_LEVELに戻しています。
begin
:CURRENT_LEVEL := 1;
end;
つまり経費申請の承認は、承認レベルが1のJANEとMATTの承認から取り直しになります。


以上が、ブログ記事Multi Level Expense Approval using APEX Workflowで実装しているワークフローの説明になります。

今回の説明に使用したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/expense-reimbursement.zip

ワークスペースへのユーザー作成を避けるため、以下のPL/SQLファンクションによるカスタム認証をカレント・スキームにしています。
function demo_authentication (
    p_username in varchar2,
    p_password in varchar2 )
    return boolean
is
begin
    if upper(p_username) in (
        'STEVE','JANE','BO','SUSIE','CLARA'
    ) then
        return true;
    end if;
    return false;
end;

Oracle APEXのアプリケーション作成の参考になれば幸いです。

2024年2月15日木曜日

リージョンにヘルプを表示するボタンを設置する

Oracle APEXでは、ページ・アイテムや対話グリッドや対話モード・レポートの列にヘルプ文書を埋め込むことができます。これらのヘルプ文書の埋め込みについては、以前に記事「APEXアプリケーションへのヘルプ文書の埋め込み」にて、その使い方を紹介しています。

以下より、リージョンに配置したヘルプ(?アイコン)をクリックして、ヘルプをポップアップする機能を実装してみます。Oracle APEXの標準機能としては、リージョンにヘルプを設定する方法はありません。

実装したヘルプは以下のように動作します。


ヘルプに使用するアイコンは、Oracle APEXにバンドルされているフォントFontAPEXから探します。


helpで検索して見つけたfa-question-circle-oをアイコンとして使用することにします。


SizeScaleAnimationRotateModifierの選択により、アイコンを修飾できます。今回はアイコンの修飾は行いません。

ページにHTMLまたはIconの記述を埋め込むことにより、?アイコンを表示します。


最初に、外観テンプレートとしてStandardを選択しているリージョンにヘルプを実装します。


ヘルプの表示を、ボタンのクリックで行うように実装します。

レイアウト位置Editを選択することにより、ボタンを右上に配置します。外観ボタン・テンプレートとしてIconを選択し、ボタンの表示をアイコンだけにします。テンプレート・オプションStyleRemove UI Decorationを選択しボタンとしての修飾を無くし、アイコンだけが表示されるようにします。アイコンはFontAPEXで見つけたアイコンfa-question-circle-oを設定します。

動作アクション動的アクションとします。


ボタンをクリックしたときに実行される動的アクションTRUEアクションとして、JavaScriptコードの実行を選択します。設定コードには以下を記述します。apex.theme.popupFieldHelpを呼び出すことにより、Oracle APEXが標準で提供しているヘルプと同じ動作でヘルプを表示できます。
const title1 = apex.lang.getMessage("CUSTOM_HELP_R1_TITLE");
const help1 = apex.lang.getMessage("CUSTOM_HELP_R1_HELP");
apex.theme.popupFieldHelp( {title: title1, helpText: help1} );

実際にヘルプとして表示するタイトルやヘルプ本文をアプリケーションに埋め込むことを避けるために、apex.lang.getMessageを呼び出しています。apex.lang.getMessageで取り出す文字列は、共有コンポーネントテキスト・メッセージ(本来はアプリケーションの翻訳に使用します)に作成します。


テキスト・メッセージを開くと、作成済みのテキスト・メッセージが一覧されます。


作成するテキスト・メッセージ名前apex.lang.getMessageの引数となる値を設定し、テキストとして取り出す文字列を記述します。言語としてAPEXアプリケーションのプライマリ言語(通常は日本語(ja))を選択します。アプリケーションの言語に一致しているテキスト・メッセージが選択されます。apex.lang.getMessageより文字列を取り出す場合は、JavaScriptで使用オンにします。

ヘルプのテキストはHTMLによる修飾が有効なので、ここで設定するテキストHTMLを記述することができます。


以上で外観テンプレートStandardのリージョンに、ヘルプを組み込むことができました。

次に外観テンプレートBlank with Attributesのリージョンに、ヘルプを組み込みます。


先ほどのアイコンはボタンで実装しています。ボタンによる実装の場合、ボタンをクリックした際などに、ボタンの境界が表示されることがあります。


動作に影響しないため気にしなくても良いですが、ボタンの代わりにリージョンを使って実装してみます。

静的コンテンツのリージョンを作成し、ソースHTMLコードとしてFontAPEXで見つけたアイコンのHTMLを記述します。

<span aria-hidden="true" class="fa fa-question-circle-o"></span>

外観テンプレートとして、ほとんど修飾のないBlank with Attributes (No Grid)を選択します。親リージョンのテンプレートはBlank with Attributesであるため、レイアウト位置Editはありません。そのため、CSSクラスにUniversal Themeが提供しているLayout Modifiersに含まれるu-pullRight u-alignTopを指定します。

 

リージョンであってもクリックイベントを取ることができます。このアイコンを表示しているリージョンに、タイミングイベントクリック動的アクションを作成します。


TRUEアクションは、先ほどの実装とほぼ同じです。


以上で、リージョンにヘルプを表示するボタンを配置することができました。

簡単なアプリケーションですが、今回作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-region-help.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。

MermaidJSを使ってダイアグラムを描画する

Oracle APEXのアプリケーションにMermaidJSを組み込んで、ダイアグラムを描画してみます。

作成したアプリケーションは以下のように動作します。簡単なアプリケーションですが、Mermaidを組み込む手順の参考になります。


以下より、組み込み方法について紹介します。MermaidのAPIの使い方については、主にAPI-Usageの説明を参照しています。


空のAPEXアプリケーションを作成し、ホーム・ページにすべての機能を実装します。

最初に、ページにMermaidをロードします。

ページ・プロパティJavaScriptファイルURLに、以下を指定します。

https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid#MIN#.js

ページ・ロード時に実行に以下を記述します。ダイアグラムはmermaid.runを呼び出して描画するため、startOnLoadfalseにします。

mermaid.initialize({ startOnLoad: false });

startOnLoad以外のmermaidAPIのConfigurationについては、以下のページが参考になります。



ダイアグラムのソースとなるデータは、ページ・アイテムP1_DIAGRAM_DEFINITIONに入力します。タイプテキスト領域を選択し、複数行の入力ができるようにしています。


Mermaidによるダイアグラムを描画するリージョンとして、タイプ動的コンテンツのリージョンを作成します。ソースCLOBを返すPL/SQLファンクション本体として、以下を記述します。ダイアグラムのソースはpre要素のテキストとし、IDDIAGRAMを割り当てています。

送信するページ・アイテムとしてP1_DIAGRAM_DEFINITIONを設定します。今回の実装ではMermaidが解釈できるデータをP1_DIAGRA_DEFINITIONより受け取って、それをそのまま描画に使用しています。一般的な実装では、他のデータからMermaidが解釈できるデータを生成するようなコードを記述することになると思います。

リージョンの修飾を減らすために、外観テンプレートとしてBlank with Attributesを選択しています。


ボタンRENDERをクリックしたときに、動的コンテンツのリージョンMermaid Diagramリフレッシュしています。動的コンテンツのリージョンの送信するページ・アイテムとしてP1_DIAGRAM_DEFINITIONが設定されているため、ボタンをクリックした時点のP1_DIAGRAM_DEFINITIONの内容が動的コンテンツの表示に反映されます。


動的コンテンツのリージョンのリフレッシュが完了した後にMermaidによる描画が実行されるように、動的アクションを作成します。タイミングイベントリフレッシュ後です。


リフレッシュ後に実行されるTRUEアクションとして、JavaScript コードの実行を選択します。設定コードとして以下を記述します。IDがDIAGRAMの要素はMermaidの描画データを保持しているpre要素であり、その要素の位置にダイアグラムが描画されます。
mermaid.run({
  nodes: [document.getElementById("DIAGRAM")],
});

Oracle APEXのアプリケーションへのMermaidの組み込み方法の紹介は以上になります。

Oracle CorporationのAPEX開発チームのメンバーであるSteve Meunchさんが、Mermaidに関するブログ記事を書いています。

Data-Driven Diagrams
https://diveintoapex.com/2023/01/02/data-driven-diagrams/

こちらの記事ではデータベースのスキーマ情報よりER図を生成していたり、別のオープン・ソースのライブラリsvg-pan-zoomを使用して、ダイアグラムの拡大表示なども実装しています。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-mermaid-diagram-drawer.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。

2024年2月14日水曜日

OllamaでCode Llamaを実行しAPEXアプリケーションからコードを生成させる

Oracle APEX界隈で著名なPlamen Muskovさんが、X(旧Twitter)にてOllamaを使ってLLaVAを呼び出すAPEXアプリケーションを作ったと投稿していました。


Ollamaであれば簡単にCode Llamaを動かすことができそうなので、以前に作成した環境で試してみました。Ollamallama_cpp.serverと同様に、APIサーバーとして動作します。

llama_cpp.serverをAmpere A1のインスタンス上で動かしてみる
https://apexugj.blogspot.com/2023/07/llamacppserver-on-ap.html

以下はその作業の記録です。

OllamaのGitHubのページに、Ollamaのインストール手順が記載されています。

Always FreeのAmpere A1のコンピュート・インスタンスが作成済みとします。OSはUbuntuです。接続ユーザーはubuntu(Oracle Linuxのインスタンスでのopcに当たります)になります。

ユーザーubuntuで接続し、Linux & WSL2のインストール手順として記載されている以下のコマンドを実行します。

ubuntu@mywhisper2:~$ curl -fsSL https://ollama.com/install.sh | sh

>>> Downloading ollama...

######################################################################## 100.0%######################################################################### 100.0%

>>> Installing ollama to /usr/local/bin...

>>> Creating ollama user...

>>> Adding ollama user to render group...

>>> Adding current user to ollama group...

>>> Creating ollama systemd service...

>>> Enabling and starting ollama service...

Created symlink /etc/systemd/system/default.target.wants/ollama.service → /etc/systemd/system/ollama.service.

>>> The Ollama API is now available at 0.0.0.0:11434.

>>> Install complete. Run "ollama" from the command line.

WARNING: No NVIDIA GPU detected. Ollama will run in CPU-only mode.

ubuntu@mywhisper2:~$


インストールを実行しているユーザーがroot権限を持っているか、sudoでroot権限を取れることが前提のようです。スクリプトの実行が完了すると、OSのサービスとしてollamaがインストールされます。また/usr/local/bin以下にollamaが作成されます。

インストール直後にollamaがサービスとして起動します。サービスの起動と終了にはsystemctlコマンドを使用します。

モデルcodellamaを呼び出せるように、ダウンロードします。

ubuntu@mywhisper2:~$ ollama run codellama

pulling manifest 

pulling 3a43f93b78ec... 100% ▕████████████████▏ 3.8 GB                         

pulling 8c17c2ebb0ea... 100% ▕████████████████▏ 7.0 KB                         

pulling 590d74a5569b... 100% ▕████████████████▏ 4.8 KB                         

pulling 2e0493f67d0c... 100% ▕████████████████▏   59 B                         

pulling 7f6a57943a88... 100% ▕████████████████▏  120 B                         

pulling 316526ac7323... 100% ▕████████████████▏  529 B                         

verifying sha256 digest 

writing manifest 

removing any unused layers 

success 

>>> /?

Available Commands:

  /set            Set session variables

  /show           Show model information

  /load <model>   Load a session or model

  /save <model>   Save your current session

  /bye            Exit

  /?, /help       Help for a command

  /? shortcuts    Help for keyboard shortcuts


Use """ to begin a multi-line message.


>>> /bye

ubuntu@mywhisper2:~$


以上でCode Llamaを呼び出す準備ができました。

OllamaはデフォルトでTCPポート11434を開けて、REST APIの要求を待ち受けます。

firewalldに対して、TCPポート11434への接続を許可します。

ubuntu@mywhisper2:~$ sudo firewall-cmd --add-port=11434/tcp

You're performing an operation over default zone ('public'),

but your connections/interfaces are in zone 'docker' (see --get-active-zones)

You most likely need to use --zone=docker option.


success

ubuntu@mywhisper2:~$ 


変更を永続化します。

ubuntu@mywhisper2:~$ sudo firewall-cmd --runtime-to-permanent

success

ubuntu@mywhisper2:~$ 


リクエストをHTTPSで受け付けてHTTPでllama_cpp.serverを呼び出していたNginxの設定を変更します。/etc/nginx/conf.d以下のserver.confに含まれるproxy_passの行のポート番号を8000から11434に変更します。

proxy_pass http://localhost:11434/;

以上の変更を行なった後にNginxを再起動すると、Ollamaを呼び出せる状態になります。

OllamaとCode Llamaを呼び出すAPEXアプリケーションについて、簡単に紹介します。

OllamaはOpenAIのchat completions互換APIをサポートしているとのことですが、今回はCode Llamaを呼び出すので、単純にGenerate a completionを呼び出すことにしました。

ページ・アイテムP1_MODELモデル名を設定します。今回はcodellamaの指定だけを想定していますが、一応変更できます。P1_MESSAGEプロンプトとなる文章を入力します。Generation APIの呼び出しに与える値は以上です。

ページ・アイテムP1_RESPONSEにCode Llamaの出力を表示します。マークダウンが返されるため、アイテム・タイプMarkdownエディタを選択しています。ページ・アイテムP1_STATSにAPI呼び出しに関する統計情報を表示します。

Ollama/Code Llamaの呼び出しは、ボタンSEND_MESSAGEに実装した動的アクションにより実行します。TRUEアクションサーバー側のコードを実行PL/SQLコードとして以下を記述します。Ollamaのレスポンスはデフォルトでストリーミングで、ストリーミング出力にしないとNginxがタイムアウトするため、APEX側でCode Llamaのレスポンスをつなげ合わせています。



アプリケーション定義置換に置換文字列G_ENDPOINTとして、OllamaのAPI呼び出しのエンドポイント(https://ホスト名/api/generate)、G_TRANSFER_TIMEOUTにAPEX側のAPEX_WEB_SERVICE.MAKE_REST_REQUESTのp_transfer_timeoutに与える秒数を指定します。

以下、プロンプトとして以下を与えた結果です。

「フィボナッチ数列の12番目の数を表示するJavaScriptのコードを教えてください。」

レスポンスが返されるまで2分はかかるので実用性はありませんが、Code Llamaが日本語を受け付けてレスポンスも日本語で返してきたのには、少し驚きました。


今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/ollama-codellama-app.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。

2024年2月13日火曜日

アクション・タスクで承認と却下ではない任意の分岐を実装する

Oracle APEX 23.2のAPEXワークフローではユーザーからの入力は、アクティビティタイプヒューマン・タスクの作成、つまり承認タスクまたはアクション・タスクといったタスクより行います。ユーザーにアサインされたタスクは、統合タスク・リストのページに一覧され、承認タスクであれば割り当たっているタスクの承認または却下アクション・タスクであれば、タスク完了させます。

今回の記事では、承認または却下ではない選択肢を、アクション・タスクを使って実装します。散歩途中の曲がり角で、に曲がるか、中心を進むか、に曲がるか、この3つの選択肢よりひとつの方向を選択します。

作成するアプリケーションは以下のように動作します。


最初に空のアプリケーションを作成します。名前歩く方向とします。


アプリケーションが作成されたら、共有コンポーネントタスク定義を開きます。


タスク定義の一覧より作成をクリックし、タスク定義の作成を開始します。

名前方向を決定するタイプアクション・タスクを選択します。件名歩く方向 - &CORNER.とします。静的IDDECIDE_DIRECTION潜在的所有者は以下のスクリーンショットではAPEXDEVとなっていますが、現在開発作業を行なっているユーザー名を指定します。

作成したアプリケーションにサインインして動作を確認する作業も、開発しているユーザーで実施します。

作成をクリックします。


アクション・タスクが作成されたら、パラメータを2つ追加します。

最初に件名に含まれるパラメータとして、CORNERを追加します。静的IDCORNERラベルCornerデータ型文字列必須Yes表示可能Yes更新可能Noを選択します。

次にアクション・タスクとして選択した選択肢を保存するパラメータとして、DIRECTIONを追加します。静的IDDIRECTIONラベルDirectionデータ型文字列必須No表示可能Yes(Noで良いかもしれません)、更新可能Yesを選択します


以上でタスク定義は完成です。


共有コンポーネントワークフローを開き、以下のワークフローを作成します。

識別名前散歩タイトル散歩 - &APP_USER.静的IDWALKINGとします。


ワークフロー・バージョン1.0とします。


ワークフロー・パラメータとしてCornerを作成します。

識別静的IDCORNERラベルCorner変数データ型VARCHAR2必須オンデフォルト値空白にします。


ワークフロー・バージョン変数としてDirectionTaskIDを作成します。

Direction静的IDDIRECTIONラベルDirection変数データ型VARCHAR2タイプNULLです。DirectionTaskIDともにアクティビティによって値が設定されます。


TaskID静的IDTASK_IDとします。それ以外はDirectionと同じ設定です。


最初のアクティビティ方向を決めるのタイプにヒューマン・タスク - 作成を選び、設定定義として先ほど作成したタスク定義方向を決定するを選択します。このアクティビティにより作成されたタスク(タスク定義方向を決定するを基に作成されたタスク)のタスクIDの保存先(タスクIDアイテム)として、ワークフロー・バージョン変数TASK_IDを設定します。


タスク・パラメータCornerに、ワークフロー・パラメータCORNERを設定します。


タスク・パラメータDirectionは入力は不要なので、タイプNULLを設定します。


続くアクティビティ方向の設定タイプコードの実行です。タスク・パラメータDirectionの値を、ワークフロー・バージョン変数DIRECTIONに代入します。

ソースPL/SQLコードに以下を記述します。



続く切替えのアクティビティ曲がるでは、切替えタイプCheck Workflow Variableを選択し、タスク・パラメータのDirectionから値を代入したワークフロー・バージョン変数のDIRECTIONを、比較変数の比較に選択します。


ワークフロー終了として中心を作成します。設定終了状態完了とします。


切替え曲がるとそれぞれの終了を接続します。

接続名前はそれぞれ、中心条件演算子次と等しいを選択し、LEFTCENTERRIGHTを設定します。アクティビティ宛先中心になります。


以上でワークフローは完成です。

ホーム・ページに対話モード・レポートを作成し、方向を決める処理を実装します。

識別タイトルMy Tasksタイプ対話モード・レポートです。

ソースタイプSQL問合せを選択し、SQL問合せとして以下を記述します。

select task_id, subject, 'L' as LEFT, 'C' as CENTER, 'R' as RIGHT from apex_approval.get_tasks()

RIGHTCENTERLEFT左に曲がる中心へ進む右へ曲がる処理を実装します。これらの処理は動的アクションで実装するため、対話モード・レポートの静的IDとしてMYTASKSを設定します。


LEFT列の書式HTML式に以下を記述し、列にボタンを表示します。CSSクラスactionLeftはボタンの見かけの修飾のためではなく、クリックのイベントを認識させるために使用します。

<button type="button" class="t-Button actionLeft" data-id=#TASK_ID#>左</button>


CENTERHTML式は以下です。

<button type="button" class="t-Button actionCenter" data-id=#TASK_ID#>中心</button>

RIGHTHTML式は以下です。

<button type="button" class="t-Button actionRight" data-id=#TASK_ID#>右</button>

カスタム属性のdata-idとして受け取ったタスクIDを、サーバー側の処理に渡すために使用するページ・アイテムP1_TASK_IDを作成します。

タイプ非表示、JavaScriptのコードより値を設定するため、設定保護された値オフにします。


動的アクションMove Leftを作成します。

実行イベント有効範囲動的を選択し、静的コンテナ(jQueryセレクタ)として対話モード・レポートの静的IDを指定します。idを指定するjQueryセレクタなので#を付加し、#MYTASKSになります。

タイミングクリック選択タイプjQueryセレクタを選択し、jQueryセレクタとしてクラスを指定するため先頭に. (ピリオド)を付加し、.actionLeftを設定します。

以上で列LEFTのボタンをクリックしたときに、この動的アクションMove Leftが呼び出されます。


最初に実行するTRUEアクションとして、値の設定を実行します。

設定タイプの設定としてJavaScript式を選択し、JavaScript式として以下を記述します。変更イベントの禁止オンにします。カスタム属性data-idの値を取り出しています。

this.triggeringElement.dataset.id

影響を受ける要素選択タイプアイテムアイテムとしてP1_TASK_IDを選択します。上記のdata-idの値がページ・アイテムP1_TASK_IDに設定されます。

実行初期化時に実行オフ結果を待機オンにします。


続くTRUEアクションサーバー側のコードを実行します。実行するコードは以下になります。タスク・パラメータのDIRECTIONに値としてLEFTを設定し、タスクを完了しています。

送信するアイテムとしてP1_TASK_IDを指定します。


最後のTRUEアクションとしてJavaScriptコードの実行を選択し、設定コードに以下を記述して、画面にメッセージを表示します。

apex.message.showPageSuccess("左に曲がりました。");


作成した動的アクションMove Leftをコピー(重複)し、動的アクションMove CenterMove Rightを作成します。コピーした動的アクションのLeft(LEFT)となっている部分をそれぞれCenter(CENTER)Right(RIGHT)に置き換えます。


ワークフローを開始する機能を加えます。

静的コンテンツのリージョンStart Workflowを作成します。外観テンプレートItem Containerを選択します。


曲がり角の名前(タスクの件名に含める文字列)を設定するページ・アイテムP1_CORNERを作成します。タイプテキスト・フィールドとします。

レイアウトリージョンにItem ContainerのStart Workflowを選択します。位置Itemになります。


ボタンSUBMITを作成します。レイアウトリージョンStart Workflow位置Button Endを選択します。

動作アクションはデフォルトのページの送信です。


ボタンSUBMITをクリックしたときに実行されるプロセスStart Workflowを作成します。

設定タイプ開始定義としてワークフロー散歩を選択します。

サーバー側の条件ボタン押下時SUBMITを指定します。


以上でアプリケーションは完成ですが、ワークフローの進捗を確認するためにワークフロー・コンソールのページを作成します。

ページの作成を実行し、ワークフロー・コンソールを選択します。


レポート・ページの名前Workflowsレポート・コンテキストとして自分で開始を選択します。フォーム・ページ名Workflow Detailsとします。

ページの作成をクリックします。


以上でアプリケーションは完成です。アプリケーションを実行すると、記事の最初のGIF動画のように動作します。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-workflow-walk-direction.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。