Drafts

A entidade Draft representa uma transação pendente do utilizador.

Pressupostos

  • Carregar e listar todos os drafts ativos do utilizador a partir da BD;
  • Drafts agrupados por grupos temporais (today, yesterday, last week, etc);
  • Drafts identificados pela cor do módulo a que pertencem;
  • Eliminar drafts definitivamente.

Desenho

Associadas (de forma “indireta”) aos drafts, existem também as entidades Process e Operation que serão detalhadas com mais pormenor mais à frente.

O modelo de entidades definido é o seguinte:

Modelo de entidades

A entidade draft está associada diretamente às operações.

Uma operação é responsável por toda a lógica de construção dos links de navegação, se determinada view utiliza drafts e se um draft é listado no menu de trabalho pendente.

Desta forma, quando é criado um draft é obrigatório definir qual é a sua operação e todo o mecanismo de drafts e recuperação de trabalho pendente fica automaticamente associado a essa operação, o que serve de base para obter toda a informação necessária para que o mecanismo de drafts funcione corretamente.

O carregamento a partir da BD e funcionamento dos drafts segue a seguinte lógica:

Lógica dos Drafts

A arquitetura lógica pode ser definida no seguinte esquema:

Arquitetura Lógica

Contador de Total de Drafts

De forma a saber o total de drafts que foram criados pelo utilizador existe um “badge” na barra lateral do menu que exibe o número total de drafts criados pelo mesmo.

Quando esse valor é zero, o “badge” não é exibido. Quando o valor é superior a 99, é exibido o texto “99+”

Modelação

Service Operation GetTotalDrafts

A service operation GetTotalDrafts é do tipo Query e retorna um valor do tipo Number (int) que representará o número total de drafts do utilizador.

Servidor

Através da modelação, é gerado um serviço GET que é o método disponibilizado pela WebApi:

Servico GetTotalDrafts WebApi

Cliente

O badge do total de drafts foi implementado junto do botão de acesso à listagem de drafts presente na sidebar (Menu.cshtml).

A manipulação do valor a apresentar no badge é da responsabilidade do controlador do menu (Menu.Controller.js).

A obtenção do total de drafts é feita recorrendo à função getTotalDrafts() do serviço draftsService (Shell.drafts.service.js).

Grupos Temporais

Para facilitar a organização dos drafts, estes estão organizados em grupos temporais.

Modelação

Service Operation GetAllDraftsTimeGroups

A service operation GetAllDraftsTimeGroups é do tipo Query e retorna uma lista de Resource Models (que são constituídas unicamente por atributos custom e desligadas de entidade), onde cada resource representa um grupo temporal.

Servidor

Através da modelação, é gerado um serviço GET que é o método disponibilizado pela WebApi:

Servico GetAllDraftsTimeGroups WebApi

Cliente

A lista de grupos de drafts é acedido através do ícone presente na sidebar.

O desenho de cada um dos grupos de drafts é da responsabilidade da directiva shellDraftGroupItem (drafts.directives.js).

A gestão dos grupos é feita pela diretiva shellDrafts (drafts.directives.js).

A obtenção da lista dos grupos é feita recorrendo à função getDraftsGroups() do serviço draftsService (“Shell.drafts.service.js”).

Drafts do Grupo

Como referido anteriormente os drafts, para o utilizador, encontram-se divididos em grupos.

Do lado do servidor, os “drafts de um grupo” são na realidade drafts com data de modificação entre dois determinados valores.

Modelação

Service Operation GetDraftsFromGroup

A service operation GetDraftsFromGroup é do tipo Query e retorna uma lista de Resource Models, onde cada resource representa um draft.

Além das informações provenientes da entidade draft, as resources possuem dois atributos custom (timestamp e url).

Servidor

Através da modelação, é gerado um serviço GET que é o método disponibilizado pela WebApi:

Servico GetDraftsFromGroup WebApi

Cliente

Após aceder à lista de grupos temporais é possível aceder-se aos drafts de um grupo clicando no respetivo grupo.

O desenho de cada um dos drafts do grupo é da responsabilidade da diretiva shellDraftItem (drafts.directives.js).

A gestão dos drafts é feita pela diretiva shellDrafts (drafts.directives.js).

Eliminação de Drafts

Os drafts de um grupo podem ser eliminados individualmente, clicando no ícone de remoção do mesmo, ou através do botão “Remove All” que permite eliminar todos os drafts contidos no grupo (que estão listados no momento).

De notar que não é possível eliminar um draft que o utilizador tenha aberto nesse momento.

Modelação

Service Operation DeleteDraftsFromGroup

A service operation DeleteDraftsFromGroup é do tipo Command e recebe 4 parâmetros: minDate e maxDate que correspondem às datas que definem um grupo, permitindo selecionar os drafts, que estão dentro espaço temporal e que são para eliminar. O parâmetro openedDrafKey permite indicar qual o draft que o utilizador tem aberto no momento de forma a este não ser eliminado.

Nota: para eliminar um draft individualmente é utilizado o método Delete percentence aos CRUD, não sendo um serviço modelado.

Servidor

Para eliminar um draft individualmente é utilizado o método de delete, pertencente aos métodos CRUD, gerado.

Para eliminar todos os drafts de um grupo existe um pedido que recebe duas datas, que definem o grupo temporal, elimina os drafts respetivos e retorna uma resposta de sucesso caso sejam eliminados os drafts com sucesso.

Este serviço encontra-se ainda implementado de forma totalmente manual, sendo um serviço do tipo POST:

Servico DeleteDraftsFromGroup WebApi

Cliente

Dentro de um grupo, é possível eliminar-se os respetivos drafts.

O desenho do botão de remoção individual de cada um dos drafts é da responsabilidade da diretiva shellDraftItem (drafts.directives.js).

O desenho do botão de remoção de todos os drafts é da responsabilidade da diretiva shellDrafts.

A eliminação individual de um draft de um grupo é feita recorrendo à função deleteDraft(key) do serviço draftsService (shell.drafts.service.js).

A eliminação de todos os drafts do grupo é feita recorrendo à função deleteAllDraftsFromGroup([] keys).

Eventos de Create/Update/Delete de Drafts

Para ser possível ter a informação relativa a drafts no menu sempre atualizada (lista de drafts e badges indicadores do número) implementaram-se eventos que são disparados aquando a alteração do estado de um draft por parte do utilizador, para notificar a existência de alterações.

Existem 5 eventos distintos:

  • draftsSaveEvent: emitido quando um draft é eliminado (o utilizador clica em ‘save’ quando está a criar/editar uma entidade)
  • draftsResetEvent: emitido quando um draft volta ao estado ‘init’ (o utilizador clica em ‘reset’ quando está a criar/editar uma entidade)
  • draftsUpdateEvent: emitido quando a informação contida num draft é atualizada (o utilizador edita o campo de uma entidade e “sai” desse campo)
  • draftsDeletedEvent: emitido quando um draft é eliminado (o utilizador elimina um draft (ou mais) da lista de drafts)
  • reloadDraftsEvent: emitido quando, por falha de conexão, é necessário recarregar os grupos de drafts (o utilizador clica em ‘try again’ após falha de conexão)

O serviço angular dos drafts (draftsService) contém os métodos responsáveis pela emissão dos eventos.

    //Emit save event
    var saveNotification = function () {
        $rootScope.$emit('draftsSaveEvent', 'Draft Removed');
    };

    //Emit reset event
    var resetNotification = function () {
        $rootScope.$emit('draftsResetEvent', 'Draft Reseted');
    };

    //Emit update event
    var draftUpdate = function () {
        $rootScope.$emit('draftsUpdateEvent', 'Draft Updated');
    };
    //Emit delete event
    var draftDeletedNotification = function () {
        $rootScope.$emit('draftsDeletedEvent', 'Draft Deleted');
    };

    //Emit reload event
    var reloadDraftsNotification = function () {
        $rootScope.$emit('reloadDraftsEvent', 'Total Drafts Updated');
    };

Os métodos saveNotification e resetNotification são invocados nos controladores das entidades, controlador create e controlador update, tendo sido modificadas as .tt’s responsáveis pela geração destes controladores, Controllers.WriteCreateController.JS.tt e Controllers.WriteUpdateController.JS.tt.

Quando o utilizador clica com sucesso em ‘save’ ou ‘reset’, aquando a criação ou edição de uma entidade, é então feita uma chamada aos métodos do serviço dos drafts.

    var onAcceptModelSuccess = function (result) {
        (…)
        draftsService.saveNotification();
        (…)
    };
    var onResetModelSuccess = function (result) {
        (…)
        draftsService.resetNotification();
        (…)
    };

O método draftUpdate é invocado na diretiva entityViewController (entityViewController.directive.js) sempre que o estado de um draft muda (por exemplo, quando o utilizador preenche o primeiro campo da entidade, o draft passa do estado ‘init’ ao estado ‘create’).

     var onModelChanged = function (model, data) {
         (…)
         draftsService.draftUpdated();
     };

O método draftDeletedNotification é invocado sempre que um draft é eliminado, seja através da remoção individual (controlador da diretiva shellDraftItem) ou da remoção de todos os drafts de um grupo (controlador da diretiva shellDrafts).

     var promise = draftsService.deleteDraft($scope.item.uiid);
        promise.then(
            function (draft) {
                draftsService.draftDeletedNotification();
                (…)
                }
     var promise = draftsService.deleteAllDraftsFromGroup(drafts);
        promise.then(
            function (result) {
                draftsService.draftDeletedNotification();
                (…)
                }

No controlador angular do Menu (menu.controller.js) e no controlador da diretiva de Drafts (shell.controller.js) os eventos são apanhados, sendo estes responsáveis por reagir aos mesmos.

Atualmente a reação é idêntica para todos os eventos, sendo feito um reload à informação dos drafts, de forma a serem atualizados todos os badges.

Apesar da atual reação aos eventos ser a mesma para todos, o facto de existirem diversos eventos permitirá no futuro, se necessário, alterar e personalizar a reação a cada evento específico.

Conceito de Processo: Cor e Caption dos drafts

Drafts Caption and Color

Cada MenuItem presente no ProductMenu (root menu) representa um Processo.

Um processo possui uma Caption (localizada) e uma Color associados.

No momento em que as operações presentes no menu são lidas, na geração de código, é feita a atribuição do respetivo processo a cada uma das operações: cada operação ficará assim associada ao processo correspondente ao MenuItem origem daquele “ramo” do menu.

Processos

Processos

MenuItems

MenuItems

Operations

Operations

Uma vez que cada draft possui a informação do módulo e operação a que diz respeito, é possível, fazer-se a associação com a respetiva operação e daí aceder à informação do processo, sendo possível aceder-se à cor e caption respetivas.

É esta cor que é visível para o utilizador quer na lista de drafts quer na pesquisa.