Статьи

Создайте приложение Kanban TaskManager за 10 минут

Управление задачами является одной из наиболее важных функций для бизнеса. Хотя есть много решений этой проблемы, пока еще нет серебряной пули, потому что каждая сфера бизнеса имеет свою специфику. Разработка приложения для удовлетворения конкретных требований в этих условиях не редкость. AllcountJS позволяет довольно быстро создавать собственные приложения для управления задачами.

Если вы не знакомы с AllcountJS, сначала ознакомьтесь с   руководством по началу работы . Хотя AllcountJS позволяет вам использовать всю мощь Node.js, в этой статье мы будем работать только с кодом App Config. Для того , чтобы запустить демо — код , который вы должны сделать  npm install allcountjs-cli то  allcountjs init или просто запустить код из нашей демонстрационной страницы  здесь ,  и вы получите что — то вроде:

модель

Давайте начнем с объявления модели. Вероятно, наиболее важной вещью в управлении задачами является наличие объекта задачи (очевидно) и некоторого потока состояния. Давайте определим нашу модель в  main.js:

A.app({
  appName: "Task manager",
  onlyAuthenticated: true,
  menuItems: [
    {
      name: "Planning",
      entityTypeId: "Task"
    }, {
      name: "Statuses",
      entityTypeId: "Status"
    }
  ],
  entities: function(Fields) {
    return {
      Task: {
        fields: {
          summary: Fields.textarea("Summary").required(),
          dueDate: Fields.date("Due Date").required(),
          status: Fields.fixedReference("Status", "Status")
        }
      },
      Status: {
        fields: {
          name: Fields.text("Name").required(),
          order: Fields.integer("Order").required()
        },
        referenceName: "name"
      }
    }
  }
});

Этот App Config создает рабочее приложение, которое имеет две сущности: Task и Status. Объект задачи имеет поля сводки и даты выполнения, а также ссылку на статус. Сущность состояния имеет поле имени, используемое в качестве ссылочного имени при отображении поля со списком, и поле заказа, которое будет использоваться позже для определения порядка статусов. Как видите, обязательные поля помечены  .required(). Это означает, что объект не может быть создан или сохранен, пока эти поля не будут заполнены. Также вы можете отметить  onlyAuthenticated флаг, который обозначает, что приложение не может быть доступно без аутентификации.

Порядок статусов

Мы могли бы определить наши приоритеты статуса, просто добавив  sorting: [['order', 1]], к  Statusтипу объекта:

A.app({
  appName: "Task manager",
  onlyAuthenticated: true,
  menuItems: [
    {
      name: "Planning",
      entityTypeId: "Task"
    }, {
      name: "Statuses",
      entityTypeId: "Status"
    }
  ],
  entities: function(Fields) {
    return {
      Task: {
        fields: {
          summary: Fields.textarea("Summary").required(),
          dueDate: Fields.date("Due Date").required(),
          status: Fields.fixedReference("Status", "Status")
        }
      },
      Status: {
        fields: {
          name: Fields.text("Name").required(),
          order: Fields.integer("Order").required()
        },
        sorting: [['order', 1]],
        referenceName: "name"
      }
    }
  }
});

Это объявление указывает AllcountJS сортировать  Status сущность по полю заказа в порядке возрастания.

Board View

Одной из самых мощных функций AllcountJS является концепция Views. Представление также является сущностью, но в качестве хранилища оно использует другую сущность. Таким образом, существует возможность создания множества вариантов поведения и визуализаций для одного и того же источника данных. Давайте создадим представление доски для нашей  Task сущности, добавив следующее свойство

views: {
  TaskBoard: {
    customView: "board"
  }
}

И создайте новый пункт меню, чтобы открыть доску:

{
  name: "Board",
  entityTypeId: "TaskBoard",
  icon: "bars"
}

Также мы должны создать пользовательскую доску просмотра, на которую мы ссылаемся ( board.jade)

extends project/card-board
block panelBody
  .panel-body
    h4 {{item.summary}}
    p {{item.dueDate | date}}

AllcountJS  по умолчанию использует язык шаблонов Jade  . Код в  board.jade определяет шаблон для пользовательского просмотра нашего форума. Он определяет  panelBody блок, который описывает, как будет выглядеть карта. Мы должны получить следующий результат для main.js

A.app({
  appName: "Task manager",
  onlyAuthenticated: true,
  menuItems: [
    {
      name: "Planning",
      entityTypeId: "Task"
    }, {
      name: "Board",
      entityTypeId: "TaskBoard",
      icon: "bars"
    }, {
      name: "Statuses",
      entityTypeId: "Status"
    }
  ],
  entities: function(Fields) {
    return {
      Task: {
        fields: {
          summary: Fields.textarea("Summary").required(),
          dueDate: Fields.date("Due Date").required(),
          status: Fields.fixedReference("Status", "Status")
        },
        views: {
          TaskBoard: {
            customView: "board"
          }
        }
      },
      Status: {
        fields: {
          name: Fields.text("Name").required(),
          order: Fields.integer("Order").required()
        },
        sorting: [['order', 1]],
        referenceName: "name"
      }
    }
  }
});

Если вы запустите этот пример кода, вы увидите доску Канбан со статусом, где вы можете перемещать карты между статусами. Порядок статусов определяется  order полем из-за сортировки.

Полировка

Для полировки вещей вы, вероятно, хотите добавить значки для пунктов меню и приложения. Вы можете сделать это, просто обратившись к  значкам Font Awesome . Давайте добавим  appIcon и иконки для меню, и мы получим финальную версию для приложения.

A.app({
  appName: "Task manager",
  appIcon: "book",
  onlyAuthenticated: true,
  menuItems: [
    {
      name: "Planning",
      entityTypeId: "Task",
      icon: "tasks"
    }, {
      name: "Board",
      entityTypeId: "TaskBoard",
      icon: "bars"
    }, {
      name: "Statuses",
      entityTypeId: "Status",
      icon: "sort"
    }
  ],
  entities: function(Fields) {
    return {
      Task: {
        fields: {
          summary: Fields.textarea("Summary").required(),
          dueDate: Fields.date("Due Date").required(),
          status: Fields.fixedReference("Status", "Status")
        },
        views: {
          TaskBoard: {
            customView: "board"
          }
        }
      },
      Status: {
        fields: {
          name: Fields.text("Name").required(),
          order: Fields.integer("Order").required()
        },
        sorting: [['order', 1]],
        referenceName: "name"
      }
    }
  }
});

Попробуйте запустить это в нашей  демо-галерее .