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の値が設定されます。ワークフローの中でこのパラメータは静的IDのAMOUNTより参照します。

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は -1 、1000より少なければ 1、5000より少なければ 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は初期値の1なので、LEVEL_NOは1になります。

結果として費用が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の1より小さいため、こちらの接続が選択されます。

それ以外、つまりMAX_LEVELとCURRENT_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_LEVELが2の場合、承認レベルが2のBOかCLARAの承認が必要になります。


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

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


アクティビティReset Levelでは以下のPL/SQLコードを実行し、CURRENT_LEVELを1に戻しています。
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をアイコンとして使用することにします。


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

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


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


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

レイアウトの位置にEditを選択することにより、ボタンを右上に配置します。外観のボタン・テンプレートとしてIconを選択し、ボタンの表示をアイコンだけにします。テンプレート・オプションのStyleにRemove 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を呼び出して描画するため、startOnLoadはfalseにします。

mermaid.initialize({ startOnLoad: false });

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



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


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

送信するページ・アイテムとして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を動かすことができそうなので、以前に作成した環境で試してみました。Ollamaはllama_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.とします。静的IDはDECIDE_DIRECTION、潜在的所有者は以下のスクリーンショットではAPEXDEVとなっていますが、現在開発作業を行なっているユーザー名を指定します。

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

作成をクリックします。


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

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

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


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


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

識別の名前は散歩、タイトルは散歩 - &APP_USER.、静的IDはWALKINGとします。


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


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

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


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

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


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


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


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


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


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

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



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


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


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

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


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

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

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

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

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

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


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

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


列CENTERのHTML式は以下です。

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

列RIGHTのHTML式は以下です。

<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 CenterとMove 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のアプリケーション作成の参考になれば幸いです。

完