All Downloads are FREE. Search and download functionalities are using the official Maven repository.

components.gantt.Schedule.js Maven / Gradle / Ivy

There is a newer version: 0.80.3
Show newest version
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
import { useConfig } from 'hooks/config';
import { MomentSvelteGanttDateAdapter, SvelteGantt, SvelteGanttDependencies, SvelteGanttTable } from 'svelte-gantt';
import { useEffect, useRef, useState } from 'react';
import { Box } from '@mui/material';
import 'moment/locale/nl'; // required to load the dutch language for moment
import GanttDrawer from 'components/gantt/Settings';
import { mformat } from './utils/date';
import { createConfig, getResourceUsage, createSvelteResources, createSvelteTasks, handleSvelteData } from 'components/gantt/common';
import { useParams } from 'react-router';
import { GET_LIST_DATA, GET_LIST_WITH_SCHEMA } from 'queries/list';
import { useQuery } from '@apollo/client';
import { useNotifier } from 'hooks/notification';
import { NotFound } from 'pages';
import LambdaComponent from 'components/common/LambdaComponent';
import CenteredLoader from 'components/common/CenteredLoader';
import moment from 'moment-business-days';
import SidebarLayout from 'components/layout/common/SidebarLayout';

const Schedule = () => {
  const { t }                    = useTranslation()
  const { project }              = useConfig()
  const { resourceKey, taskKey } = useParams()

  // TODO: set holidays:
  //var july4th = '2015-07-04';
  //var laborDay = '2015-09-07';
  //var boxingDay = '2020-12-26';

  //moment.updateLocale('us', {
  //  holidays: [ july4th, laborDay ],
  //  holidayFormat: 'YYYY-MM-DD',
  //  forcedBusinessDays: [ boxingDay ],
  //  forcedBusinessDaysFormat: 'YYYY-MM-DD',
  //  workingWeekdays: [1, 2, 3, 4, 5, 6] // Defines days from 1 (Monday) to 6 (Saturday) as business days. Note that Sunday is day 0.
  //});'

  const momentConfig = {
    nextBusinessDayLimit: 365
  }

  moment.updateLocale('en', momentConfig)
  moment.updateLocale('nl', momentConfig)

  console.log("Creating gantt chart with:\nresources: %o\ntasks    : %o",
    resourceKey || 'planningresources',
    taskKey || 'productionplanning'
  )

  return (
    <>
      
        {t('schedule')} | {project}
      

      
        
      
    
  )
}

const GanttDataProvider = ({children}) => {
  const { resourceKey, taskKey }  = useParams()
  const notifier                  = useNotifier()
  const resourceRequest           = createRequest(resourceKey || 'planningresources' )
  const taskRequest               = createRequest(taskKey || 'productionplanning')
  const resourceResult            = useQuery(GET_LIST_WITH_SCHEMA, resourceRequest)
  const taskResult                = useQuery(GET_LIST_WITH_SCHEMA, taskRequest)
  const [loading, setLoading]     = useState(true)
  const [error, setError]         = useState(false)
  const [resources, setResources] = useState()
  const [tasks, setTasks]         = useState()
  const ops                       = {setError, setLoading, notifier, setResources, setTasks}

  // create rows
  useEffect(() => {
    handleSvelteData({
      result: resourceResult,
      createRows: createSvelteResources,
      setData: setResources,
      ops
    })
  }, [resourceResult.loading])

  // create tasks
  useEffect(() => {
    if (resources != null) {
      handleSvelteData({
        result: taskResult,
        createRows: (schema, rows) => createSvelteTasks(schema, rows, resources),
        setData: setTasks,
        ops
      })
    }
  }, [taskResult.loading, resources])

  useEffect(() => {
    if (resources && tasks)
      setLoading(false)
  }, [resources, tasks])

  if (loading) {
    return 
  } else if (error) {
    return 
  } else {
    return (
      
        {children}
      
    )
  }
}

const GanttSchedule = ({resources, tasks}) => {
  const config       = useRef(createConfig(resources, tasks))

  return (
      }
      sidebarProps={{
        shortcut: "BracketRight",
        enabled: {
          collapsed: false
        }
      }}
    >
      
    
  )
}

const GanttComponent = ({config}) => {
  const { t } = useTranslation()

  const timeRanges = [
    {
        id: 0,
        from: moment().startOf('day'),
        to: moment().endOf('day'),
        classes: null,
        label: t("gantt.today"),
    },
  ];

  config.current.options = {
    from: config.current.from,
    to: config.current.to,
    rows: config.current.rows,
    tasks: config.current.tasks,
    ...config.current.createWindowConfig(),

    dateAdapter: new MomentSvelteGanttDateAdapter(moment),
    timeRanges,
    zoomLevels: [],
    rowHeight: 30,
    rowPadding: 6,
    minWidth: 800,
    tableHeaders: [{ title: t('gantt.resource'), property: 'label', width: 140, type: 'tree' }],
    tableWidth: 245,
    reflectOnParentRows: true,
    ganttTableModules: [SvelteGanttTable],
    ganttBodyModules: [SvelteGanttDependencies],

    taskElementHook: (node, task) => {
      let popup;
      function onHover(e) {
        popup = createPopup(task, config.current.resources, node, t);
      }

      function onLeave(e) {
        if(popup) {
          popup.remove();
        }
      }

      node.addEventListener('mouseenter', onHover);
      node.addEventListener('mouseleave', onLeave);

      return {
        destroy() {
          node.removeEventListener('mouseenter', onHover);
          node.removeEventListener('mouseleave', onLeave);
        }
      }
    },
    taskContent: (task) => {
      if (task.gears?.type == "capacity" && task.gears.overcapacity > 0)
        return JSON.stringify(task.gears.demand)
      else
        return ''
    }
  }

  // useEffect to load Gantt
  useEffect(() => {
    if (!config.current.gantt) {
      // Create Gantt
      const ganttInstance = new SvelteGantt({ target: document.getElementById('example-gantt'), props: config.current.options })

      // try out some event handlers
      // ganttInstance.api.tasks.on.select((task) => console.log('Listener: task selected', task));
      // ganttInstance.api.tasks.on.changed((task) => console.log('Listener: task changed', task));

      config.current.gantt = ganttInstance
    }
  }, [])
  return (
      <>
        {/* GANTT CONTAINER */}
        
      
    )
};

function createPopup(task, resources, node, t) {
  const rect = node.getBoundingClientRect();
  const div = document.createElement('div');
  div.zIndex = "10"
  div.style = "z-index:1;background-color:white;padding:10px; border-radius:5px;box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);"
  div.className = 'sg-popup';

  const getResource = (task) => resources.find(resource => resource.id == task.gears.resourceId)
  const resource    = getResource(task)


  const space = (repeat) => " ".repeat(repeat)
  const createKeyValueRow = (key, value) => {
    return `
      
        ${key}
        :${space(2)}
        ${value}
      
    `
  }

  const createListTable = (entries, columnGetters = [(entry) => entry]) => {
    const createTableRow  = (body) => `${body}`
    const createTableCols = (entry, getters) => getters.map(getter => `${getter(entry)}`).join("\n")
    const createEntryRows = () => entries.map(entry => createTableRow(createTableCols(entry, columnGetters))).join("\n")

    if (Array.isArray(entries) && entries.length) {
      if (!Array.isArray(columnGetters))
        return createListTable(entries, [columnGetters])
      else {
        return `
          
            ${createEntryRows()}
          
` } } else return '' } const createCapacityHtml = (task) => { const addStatusTasks = (label, task, taskGetter) => createKeyValueRow(label, createListTable(taskGetter(task), (task) => task.label)) const addResourceTasks = (label, task, taskGetter) => createKeyValueRow(label, createListTable(taskGetter(task), [(task) => `(${getResourceUsage(task)})`, (task) => space(1), (task) => task.label])) const statusHtml = (status) => { const createBorder = (color, content) => `
${t(`gantt.status-${content}`)}
` switch(status) { case "high": return createBorder("#ff0000", status) case "full": return createBorder("rgba(255, 140, 0)", status) case "low": return createBorder("#3CB043", status) default: return status } } return ` ${createKeyValueRow(t("gantt.status"), statusHtml(task.gears.state))} ${createKeyValueRow(t("gantt.week"), task.from.isoWeek())} ${createKeyValueRow(t("gantt.capacity"), task.gears.capacity)} ${createKeyValueRow(t("gantt.required"), `${task.gears.demand} (${task.gears.overcapacity})`)} ${addStatusTasks(t("gantt.running"), task, (task) => task.gears.running)} ${addResourceTasks(t("gantt.backlog"), task, (task) => task.gears.planned)} ${addStatusTasks(t("gantt.finished"), task, (task) => task.gears.finished)}
` } const createTaskHtml = (task) => { const conflictLine = task.gears.conflicts ? createKeyValueRow("Conflict", createListTable(Array.from(task.gears.conflicts, task => `${task.label} ${t('gantt.withresource')} ${getResource(task).label}`))) : `` const hoursPerWeek = resource.gears.capacity // in hours const hoursPerDay = hoursPerWeek/5 // per working day const roundToTwo = (num) => +(Math.round(num + "e+2") + "e-2") const dayMaximum = roundToTwo(hoursPerDay) return ` ${createKeyValueRow(t("gantt.task"), task.label)} ${createKeyValueRow(t("gantt.name"), task.gears.name)} ${createKeyValueRow(t("gantt.client"), task.gears.client)} ${createKeyValueRow(t("gantt.drawingnumber"), task.gears.drawingNumber)} ${createKeyValueRow(t("gantt.required"), task.gears.hours)} ${createKeyValueRow(t("gantt.daymax"), dayMaximum)} ${createKeyValueRow(t("gantt.duration"), t('gantt.taskduration', {days: task.gears.duration.days, hours: task.gears.duration.hours, minutes: task.gears.duration.minutes}))} ${createKeyValueRow(t("gantt.from"), mformat(task.from))} ${createKeyValueRow(t("gantt.to"), mformat(task.to))} ${createKeyValueRow(t("gantt.resource"), resource.label)} ${conflictLine}
` } div.innerHTML = task.gears.type == "capacity" ? createCapacityHtml(task) : createTaskHtml(task) div.style.position = 'absolute'; div.style.top = `${rect.bottom}px`; div.style.left = `${rect.left + rect.width / 2}px`; document.body.appendChild(div); return div; } const createRequest = (key) => ({ variables: { key, filter: null, count: 999999, start: 0 }, query: GET_LIST_DATA, path: 'list.data', countPath: 'list.count' }) export default Schedule;




© 2015 - 2024 Weber Informatics LLC | Privacy Policy