Calendar: Fix some kanban listen problems

- Status filter isn't really applicable
- Priority was missing its options
This commit is contained in:
nathan 2022-08-25 10:13:32 -06:00
parent 924bea48e5
commit 59e64cd908
4 changed files with 421 additions and 4 deletions

View File

@ -390,7 +390,7 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(ValidateMixin(LitFl
* @see https://flatpickr.js.org/options/
* @returns {any}
*/
protected getOptions()
getOptions()
{
let options = super.getOptions();

View File

@ -0,0 +1,356 @@
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {dateStyles} from "./DateStyles";
import {css, html, LitElement, repeat, TemplateResult} from "@lion/core";
import {egw} from "../../jsapi/egw_global";
import {Et2Select} from "../Et2Select/Et2Select";
import {Et2widgetWithSelectMixin} from "../Et2Select/Et2WidgetWithSelectMixin";
import {SelectOption} from "../Et2Select/FindSelectOptions";
import "flatpickr/dist/plugins/rangePlugin.js";
import {Et2Date} from "./Et2Date";
export class Et2DateRange extends Et2widgetWithSelectMixin(Et2InputWidget(LitElement))
{
static get styles()
{
return [
...super.styles,
dateStyles,
css`
:host {
width: auto;
}
`,
];
}
static get properties()
{
return {
...super.properties,
/**
* An object with keys 'from' and 'to' for absolute ranges, or a relative range string
*/
value: {type: Object},
/**
* Is the date range relative (this week) or absolute (2016-02-15 - 2016-02-21). This will affect the value returned.
*/
relative: {type: Boolean},
placeholder: {type: String}
}
}
// Class Constants
static readonly relative_dates = [
// Start and end are relative offsets, see et2_date.set_min()
// or Date objects
{
value: 'Today',
label: 'Today',
from(date) {return date;},
to(date) {return date;}
},
{
label: 'Yesterday',
value: 'Yesterday',
from(date)
{
date.setUTCDate(date.getUTCDate() - 1);
return date;
},
to: ''
},
{
label: 'This week',
value: 'This week',
from(date) {return egw.week_start(date);},
to(date)
{
date.setUTCDate(date.getUTCDate() + 6);
return date;
}
},
{
label: 'Last week',
value: 'Last week',
from(date)
{
var d = egw.week_start(date);
d.setUTCDate(d.getUTCDate() - 7);
return d;
},
to(date)
{
date.setUTCDate(date.getUTCDate() + 6);
return date;
}
},
{
label: 'This month',
value: 'This month',
from(date)
{
date.setUTCDate(1);
return date;
},
to(date)
{
date.setUTCMonth(date.getUTCMonth() + 1);
date.setUTCDate(0);
return date;
}
},
{
label: 'Last month',
value: 'Last month',
from(date)
{
date.setUTCMonth(date.getUTCMonth() - 1);
date.setUTCDate(1);
return date;
},
to(date)
{
date.setUTCMonth(date.getUTCMonth() + 1);
date.setUTCDate(0);
return date;
}
},
{
label: 'Last 3 months',
value: 'Last 3 months',
from(date)
{
date.setUTCMonth(date.getUTCMonth() - 2);
date.setUTCDate(1);
return date;
},
to(date)
{
date.setUTCMonth(date.getUTCMonth() + 3);
date.setUTCDate(0);
return date;
}
},
/*
'This quarter'=> array(0,0,0,0, 0,0,0,0), // Just a marker, needs special handling
'Last quarter'=> array(0,-4,0,0, 0,-4,0,0), // Just a marker
*/
{
label: 'This year',
value: 'This year',
from(d)
{
d.setUTCMonth(0);
d.setUTCDate(1);
return d;
},
to(d)
{
d.setUTCMonth(11);
d.setUTCDate(31);
return d;
}
},
{
label: 'Last year',
value: 'Last year',
from(d)
{
d.setUTCMonth(0);
d.setUTCDate(1);
d.setUTCYear(d.getUTCYear() - 1);
return d;
},
to(d)
{
d.setUTCMonth(11);
d.setUTCDate(31);
d.setUTCYear(d.getUTCYear() - 1);
return d;
}
}
];
connectedCallback()
{
super.connectedCallback();
this.updateComplete.then(() =>
{
if(!this.relative)
{
let options = this._fromNode.getOptions();
//@ts-ignore rangePlugin is there, really
options.plugins.push(rangePlugin({input: this._toNode.findInputField()}));
}
})
}
render()
{
if(this.relative)
{
return this.relativeTemplate();
}
return this.absoluteTemplate();
}
protected relativeTemplate()
{
return html`
<et2-select part="relative" empty_label="${this.empty_label}" placeholder="${this.placeholder}"
value="${this.value}">
${repeat(this.select_options, (d) => d.value, (o) => this._optionTemplate(o))}
</et2-select>
`;
}
_optionTemplate(option : SelectOption) : TemplateResult
{
let icon = option.icon ? html`
<et2-image slot="prefix" part="icon" style="width: var(--icon-width)"
src="${option.icon}"></et2-image>` : "";
// Tag used must match this.optionTag, but you can't use the variable directly.
// Pass option along so SearchMixin can grab it if needed
return html`
<sl-menu-item value="${option.value}"
title="${!option.title || this.noLang ? option.title : this.egw().lang(option.title)}"
class="${option.class}" .option=${option}>
${icon}
${this.egw().lang(option.label)}
</sl-menu-item>`;
}
protected absoluteTemplate()
{
return html`
<et2-date part="from" id="from"></et2-date>
<et2-date part="to" id="to"></et2-date>`;
}
get select_options() : SelectOption[]
{
// @ts-ignore
const options = super.select_options || [];
// make sure result is unique
return [...new Map([...options, ...(Et2DateRange.relative_dates || [])].map(item =>
[item.value, item])).values()];
}
get value() : string | string[] | { from : string; to : string }
{
return this.relative ?
(this._selectNode?.value || this.__value) :
{from: <string>this._fromNode?.value, to: <string>this._toNode?.value};
}
set value(new_value : string | string[] | { from : string, to : string })
{
let oldValue = this.value;
if(!new_value || new_value == null || typeof new_value == "undefined")
{
this._selectNode.value = '';
this._fromNode.value = null;
this._toNode.value = null;
}
// Relative
else if(new_value && typeof new_value === 'string')
{
this._set_relative_value(new_value);
}
else if(new_value && typeof new_value.from === 'undefined' && new_value[0])
{
new_value = {
from: new_value[0],
to: new_value[1] || ''
};
}
if(new_value && new_value.from && new_value.to)
{
this._fromNode._instance.setDate([new_value.from, new_value.to], false);
}
}
_set_relative_value(_value)
{
// Show description
this.__value = _value;
/*
let tempDate = new Date();
let today = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate(), 0, -tempDate.getTimezoneOffset(), 0);
// Use strings to avoid references
this._fromNode.value = today.toJSON();
this._toNode.value = today.toJSON();
let relative = null;
for(var index in Et2DateRange.relative_dates)
{
if(Et2DateRange.relative_dates[index].value === _value)
{
relative = Et2DateRange.relative_dates[index];
break;
}
}
if(relative)
{
let dates = ["from", "to"];
let value = today.toJSON();
for(let i = 0; i < dates.length; i++)
{
let date = dates[i];
if(typeof relative[date] == "function")
{
value = relative[date](new Date(value));
}
else
{
value = this[date]._relativeDate(relative[date]);
}
this["_" + date + "Node"].value = value;
}
}
*/
}
/**
* Get the node where we're putting the options
*
* @returns {HTMLElement}
*/
get _optionTargetNode() : HTMLElement
{
return this._selectNode;
}
/**
* Render select_options as child DOM Nodes
* Overridden here because we can do it in the normal way (render())
* @protected
*/
protected _renderOptions()
{}
get _selectNode() : Et2Select
{
return this.shadowRoot?.querySelector("[part='relative']");
}
get _fromNode() : Et2Date
{
return this.shadowRoot?.querySelector("[part='from']")
}
get _toNode() : Et2Date
{
return this.shadowRoot?.querySelector("[part='to']")
}
}
customElements.define("et2-date-range", Et2DateRange);

View File

@ -101,5 +101,34 @@ export function inputBasicTests(before : Function, test_value : string, value_se
// widget returns what we gave it
assert.equal(element.get_value(), test_value);
});
})
});
describe("Required", () =>
{
beforeEach(async() =>
{
element = await before();
});
// This is just visually comparing for a difference, no deep inspection
it("looks different when required")
/*
Not yet working attempt to have playwright compare visually
const pre = await page.locator(element.localName).screenshot();
element.required = true;
// wait for asychronous changes to the DOM
await elementUpdated(<Element><unknown>element);
const post = await page.locator(element.localName).screenshot();
expect(post).toMatchSnapshot(pre);
*/
});
}

View File

@ -70,7 +70,14 @@ class Date extends Transformer
$form_name = self::form_name($cname, $this->id, $expand);
$value =& self::get_array(self::$request->content, $form_name, false, true);
if($this->type != 'date-duration' && $value)
if($this->type == 'et2-date-range')
{
$value = $this->attrs['relative'] || $this->getElementAttribute($form_name, 'relative') ?
$value :
['from' => is_array($value) && array_key_exists('from', $value) ? $this->format_date($value['from']) : '',
'to' => is_array($value) && array_key_exists('from', $value) ? $this->format_date($value['to']) : ''];
}
elseif($this->type != 'date-duration' && $value)
{
$value = $this->format_date($value);
}
@ -165,6 +172,10 @@ class Date extends Transformer
$value = self::get_array($content, $form_name);
$valid =& self::get_array($validated, $form_name, true);
if($value && $this->type == 'et2-date-range')
{
return $this->validateRange($form_name, $value, $valid);
}
if($value && $this->type !== 'date-duration')
{
try
@ -282,8 +293,29 @@ class Date extends Transformer
//error_log("$this : ($valid)" . Api\DateTime::to($valid));
}
}
protected function validateRange($form_name, $value, &$valid)
{
if($this->attrs['relative'] || $this->getElementAttribute($form_name, "relative"))
{
$valid = "" . $value;
return;
}
foreach(['from', 'to'] as $field)
{
if(!$value[$field])
{
continue;
}
if(substr($value[$field], -1) === 'Z')
{
$value[$field] = substr($value[$field], 0, -1);
}
$valid[$field] = new Api\DateTime($value[$field]);
}
}
}
\EGroupware\Api\Etemplate\Widget::registerWidget(__NAMESPACE__ . '\\Date',
array('et2-date', 'et2-date-time', 'time_or_date')
array('et2-date', 'et2-date-time', 'et2-date-range', 'time_or_date')
);