mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-20 22:53:49 +00:00
Merge remote-tracking branch 'origin/master' into cire16
This commit is contained in:
@@ -80,7 +80,9 @@ header {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
z-index: 1500;
|
||||
a.dropdown-item {
|
||||
padding: 0.5rem 1rem;
|
||||
width: 120%;
|
||||
border: 0;
|
||||
border-bottom: 1px solid $gray-200;
|
||||
@@ -517,3 +519,16 @@ div.popover {
|
||||
div.v-toast {
|
||||
z-index: 10000!important;
|
||||
}
|
||||
|
||||
// export index page
|
||||
div.exports-list {
|
||||
div.flex-bloc .item-bloc {
|
||||
flex-basis: 33%;
|
||||
@include media-breakpoint-down(lg) { flex-basis: 50%; }
|
||||
@include media-breakpoint-down(sm) { flex-basis: 100%; }
|
||||
div:last-child,
|
||||
p:last-child {
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ require('./chillmain.scss');
|
||||
import { chill } from './js/chill.js';
|
||||
global.chill = chill;
|
||||
|
||||
require('./js/date.js');
|
||||
require('./js/date');
|
||||
require('./js/counter.js');
|
||||
|
||||
/// Load fonts
|
||||
|
@@ -12,7 +12,7 @@
|
||||
* Do not take time into account
|
||||
*
|
||||
*/
|
||||
const dateToISO = (date) => {
|
||||
export const dateToISO = (date: Date|null): string|null => {
|
||||
if (null === date) {
|
||||
return null;
|
||||
}
|
||||
@@ -29,7 +29,7 @@ const dateToISO = (date) => {
|
||||
*
|
||||
* **Experimental**
|
||||
*/
|
||||
const ISOToDate = (str) => {
|
||||
export const ISOToDate = (str: string|null): Date|null => {
|
||||
if (null === str) {
|
||||
return null;
|
||||
}
|
||||
@@ -38,25 +38,25 @@ const ISOToDate = (str) => {
|
||||
}
|
||||
|
||||
let
|
||||
[year, month, day] = str.split('-');
|
||||
[year, month, day] = str.split('-').map(p => parseInt(p));
|
||||
|
||||
return new Date(year, month-1, day);
|
||||
return new Date(year, month-1, day, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a date object from iso string formatted as YYYY-mm-dd:HH:MM:ss+01:00
|
||||
*
|
||||
*/
|
||||
const ISOToDatetime = (str) => {
|
||||
export const ISOToDatetime = (str: string|null): Date|null => {
|
||||
if (null === str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let
|
||||
[cal, times] = str.split('T'),
|
||||
[year, month, date] = cal.split('-'),
|
||||
[year, month, date] = cal.split('-').map(s => parseInt(s)),
|
||||
[time, timezone] = times.split(times.charAt(8)),
|
||||
[hours, minutes, seconds] = time.split(':')
|
||||
[hours, minutes, seconds] = time.split(':').map(s => parseInt(s));
|
||||
;
|
||||
|
||||
return new Date(year, month-1, date, hours, minutes, seconds);
|
||||
@@ -66,7 +66,7 @@ const ISOToDatetime = (str) => {
|
||||
* Convert a date to ISO8601, valid for usage in api
|
||||
*
|
||||
*/
|
||||
const datetimeToISO = (date) => {
|
||||
export const datetimeToISO = (date: Date): string => {
|
||||
let cal, time, offset;
|
||||
cal = [
|
||||
date.getFullYear(),
|
||||
@@ -92,7 +92,7 @@ const datetimeToISO = (date) => {
|
||||
return x;
|
||||
};
|
||||
|
||||
const intervalDaysToISO = (days) => {
|
||||
export const intervalDaysToISO = (days: number|string|null): string => {
|
||||
if (null === days) {
|
||||
return 'P0D';
|
||||
}
|
||||
@@ -100,7 +100,7 @@ const intervalDaysToISO = (days) => {
|
||||
return `P${days}D`;
|
||||
}
|
||||
|
||||
const intervalISOToDays = (str) => {
|
||||
export const intervalISOToDays = (str: string|null): number|null => {
|
||||
if (null === str) {
|
||||
return null
|
||||
}
|
||||
@@ -154,12 +154,3 @@ const intervalISOToDays = (str) => {
|
||||
|
||||
return days;
|
||||
}
|
||||
|
||||
export {
|
||||
dateToISO,
|
||||
ISOToDate,
|
||||
ISOToDatetime,
|
||||
datetimeToISO,
|
||||
intervalISOToDays,
|
||||
intervalDaysToISO,
|
||||
};
|
@@ -5,6 +5,10 @@ ul.record_actions {
|
||||
justify-content: flex-end;
|
||||
padding: 0.5em 0;
|
||||
|
||||
&.inline {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&.column {
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -18,6 +22,13 @@ ul.record_actions {
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
&.small {
|
||||
.btn {
|
||||
padding: .25rem .5rem;
|
||||
font-size: .75rem;
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
list-style-type: none;
|
||||
|
@@ -0,0 +1,4 @@
|
||||
export function fetchResults<T>(uri: string, params: {item_per_page?: number}): Promise<T[]>;
|
||||
|
||||
export function makeFetch<T, B>(method: "GET"|"POST"|"PATCH"|"DELETE", url: string, body: B, options: {[key: string]: string}): Promise<T>;
|
||||
|
@@ -1,110 +0,0 @@
|
||||
/**
|
||||
* Generic api method that can be adapted to any fetch request
|
||||
*/
|
||||
const makeFetch = (method, url, body, options) => {
|
||||
let opts = {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
},
|
||||
body: (body !== null) ? JSON.stringify(body) : null
|
||||
};
|
||||
|
||||
if (typeof options !== 'undefined') {
|
||||
opts = Object.assign(opts, options);
|
||||
}
|
||||
|
||||
return fetch(url, opts)
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
if (response.status === 422) {
|
||||
return response.json().then(response => {
|
||||
throw ValidationException(response)
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status === 403) {
|
||||
throw AccessException(response);
|
||||
}
|
||||
|
||||
throw {
|
||||
name: 'Exception',
|
||||
sta: response.status,
|
||||
txt: response.statusText,
|
||||
err: new Error(),
|
||||
violations: response.body
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch results with certain parameters
|
||||
*/
|
||||
const _fetchAction = (page, uri, params) => {
|
||||
const item_per_page = 50;
|
||||
if (params === undefined) {
|
||||
params = {};
|
||||
}
|
||||
let url = uri + '?' + new URLSearchParams({ item_per_page, page, ...params });
|
||||
|
||||
return fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
},
|
||||
}).then(response => {
|
||||
if (response.ok) { return response.json(); }
|
||||
throw Error({ m: response.statusText });
|
||||
});
|
||||
};
|
||||
|
||||
const fetchResults = async (uri, params) => {
|
||||
let promises = [],
|
||||
page = 1;
|
||||
let firstData = await _fetchAction(page, uri, params);
|
||||
|
||||
promises.push(Promise.resolve(firstData.results));
|
||||
|
||||
if (firstData.pagination.more) {
|
||||
do {
|
||||
page = ++page;
|
||||
promises.push(_fetchAction(page, uri, params).then(r => Promise.resolve(r.results)));
|
||||
} while (page * firstData.pagination.items_per_page < firstData.count)
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(values => values.flat());
|
||||
};
|
||||
|
||||
const fetchScopes = () => {
|
||||
return fetchResults('/api/1.0/main/scope.json');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Error objects to be thrown
|
||||
*/
|
||||
const ValidationException = (response) => {
|
||||
const error = {};
|
||||
error.name = 'ValidationException';
|
||||
error.violations = response.violations.map((violation) => `${violation.title}: ${violation.propertyPath}`);
|
||||
error.titles = response.violations.map((violation) => violation.title);
|
||||
error.propertyPaths = response.violations.map((violation) => violation.propertyPath);
|
||||
return error;
|
||||
}
|
||||
|
||||
const AccessException = (response) => {
|
||||
const error = {};
|
||||
error.name = 'AccessException';
|
||||
error.violations = ['You are not allowed to perform this action'];
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
export {
|
||||
makeFetch,
|
||||
fetchResults,
|
||||
fetchScopes
|
||||
}
|
@@ -0,0 +1,223 @@
|
||||
import {Scope} from '../../types';
|
||||
|
||||
export type body = {[key: string]: boolean|string|number|null};
|
||||
export type fetchOption = {[key: string]: boolean|string|number|null};
|
||||
|
||||
export interface Params {
|
||||
[key: string]: number|string
|
||||
}
|
||||
|
||||
export interface PaginationResponse<T> {
|
||||
pagination: {
|
||||
more: boolean;
|
||||
items_per_page: number;
|
||||
};
|
||||
results: T[];
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface FetchParams {
|
||||
[K: string]: string|number|null;
|
||||
};
|
||||
|
||||
export interface TransportExceptionInterface {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ValidationExceptionInterface extends TransportExceptionInterface {
|
||||
name: 'ValidationException';
|
||||
error: object;
|
||||
violations: string[];
|
||||
titles: string[];
|
||||
propertyPaths: string[];
|
||||
}
|
||||
|
||||
export interface ValidationErrorResponse extends TransportExceptionInterface {
|
||||
violations: {
|
||||
title: string;
|
||||
propertyPath: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface AccessExceptionInterface extends TransportExceptionInterface {
|
||||
name: 'AccessException';
|
||||
violations: string[];
|
||||
}
|
||||
|
||||
export interface NotFoundExceptionInterface extends TransportExceptionInterface {
|
||||
name: 'NotFoundException';
|
||||
}
|
||||
|
||||
export interface ServerExceptionInterface extends TransportExceptionInterface {
|
||||
name: 'ServerException';
|
||||
message: string;
|
||||
code: number;
|
||||
body: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generic api method that can be adapted to any fetch request
|
||||
*/
|
||||
export const makeFetch = <Input, Output>(method: 'POST'|'GET'|'PUT'|'PATCH'|'DELETE', url: string, body?: body | Input | null, options?: FetchParams): Promise<Output> => {
|
||||
let opts = {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
},
|
||||
};
|
||||
|
||||
if (body !== null || typeof body !== 'undefined') {
|
||||
Object.assign(opts, {body: JSON.stringify(body)})
|
||||
}
|
||||
|
||||
if (typeof options !== 'undefined') {
|
||||
opts = Object.assign(opts, options);
|
||||
}
|
||||
|
||||
return fetch(url, opts)
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
if (response.status === 422) {
|
||||
return response.json().then(response => {
|
||||
throw ValidationException(response)
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status === 403) {
|
||||
throw AccessException(response);
|
||||
}
|
||||
|
||||
throw {
|
||||
name: 'Exception',
|
||||
sta: response.status,
|
||||
txt: response.statusText,
|
||||
err: new Error(),
|
||||
violations: response.body
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch results with certain parameters
|
||||
*/
|
||||
function _fetchAction<T>(page: number, uri: string, params?: FetchParams): Promise<PaginationResponse<T>> {
|
||||
const item_per_page: number = 50;
|
||||
|
||||
let searchParams = new URLSearchParams();
|
||||
searchParams.append('item_per_page', item_per_page.toString());
|
||||
searchParams.append('page', page.toString());
|
||||
|
||||
if (params !== undefined) {
|
||||
Object.keys(params).forEach(key => {
|
||||
let v = params[key];
|
||||
if (typeof v === 'string') {
|
||||
searchParams.append(key, v);
|
||||
} else if (typeof v === 'number') {
|
||||
searchParams.append(key, v.toString());
|
||||
} else if (v === null) {
|
||||
searchParams.append(key, '');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let url = uri + '?' + searchParams.toString();
|
||||
|
||||
return fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8'
|
||||
},
|
||||
}).then((response) => {
|
||||
if (response.ok) { return response.json(); }
|
||||
|
||||
if (response.status === 404) {
|
||||
throw NotFoundException(response);
|
||||
}
|
||||
|
||||
if (response.status === 422) {
|
||||
return response.json().then(response => {
|
||||
throw ValidationException(response)
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status === 403) {
|
||||
throw AccessException(response);
|
||||
}
|
||||
|
||||
if (response.status >= 500) {
|
||||
return response.text().then(body => {
|
||||
throw ServerException(response.status, body);
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error("other network error");
|
||||
}).catch((reason: any) => {
|
||||
console.error(reason);
|
||||
throw new Error(reason);
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchResults = async<T> (uri: string, params?: FetchParams): Promise<T[]> => {
|
||||
let promises: Promise<T[]>[] = [],
|
||||
page = 1;
|
||||
let firstData: PaginationResponse<T> = await _fetchAction(page, uri, params) as PaginationResponse<T>;
|
||||
|
||||
promises.push(Promise.resolve(firstData.results));
|
||||
|
||||
if (firstData.pagination.more) {
|
||||
do {
|
||||
page = ++page;
|
||||
promises.push(
|
||||
_fetchAction<T>(page, uri, params)
|
||||
.then(r => Promise.resolve(r.results))
|
||||
);
|
||||
} while (page * firstData.pagination.items_per_page < firstData.count)
|
||||
}
|
||||
|
||||
return Promise.all(promises).then((values) => values.flat());
|
||||
};
|
||||
|
||||
export const fetchScopes = (): Promise<Scope[]> => {
|
||||
return fetchResults('/api/1.0/main/scope.json');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Error objects to be thrown
|
||||
*/
|
||||
const ValidationException = (response: ValidationErrorResponse): ValidationExceptionInterface => {
|
||||
const error = {} as ValidationExceptionInterface;
|
||||
error.name = 'ValidationException';
|
||||
error.violations = response.violations.map((violation) => `${violation.title}: ${violation.propertyPath}`);
|
||||
error.titles = response.violations.map((violation) => violation.title);
|
||||
error.propertyPaths = response.violations.map((violation) => violation.propertyPath);
|
||||
return error;
|
||||
}
|
||||
|
||||
const AccessException = (response: Response): AccessExceptionInterface => {
|
||||
const error = {} as AccessExceptionInterface;
|
||||
error.name = 'AccessException';
|
||||
error.violations = ['You are not allowed to perform this action'];
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
const NotFoundException = (response: Response): NotFoundExceptionInterface => {
|
||||
const error = {} as NotFoundExceptionInterface;
|
||||
error.name = 'NotFoundException';
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
const ServerException = (code: number, body: string): ServerExceptionInterface => {
|
||||
const error = {} as ServerExceptionInterface;
|
||||
error.name = 'ServerException';
|
||||
error.code = code;
|
||||
error.body = body;
|
||||
|
||||
return error;
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
import {fetchResults} from "./apiMethods";
|
||||
import {Location, LocationType} from "../../types";
|
||||
|
||||
export const getLocations = (): Promise<Location[]> => fetchResults('/api/1.0/main/location.json');
|
||||
|
||||
export const getLocationTypes = (): Promise<LocationType[]> => fetchResults('/api/1.0/main/location-type.json');
|
25
src/Bundle/ChillMainBundle/Resources/public/lib/api/user.ts
Normal file
25
src/Bundle/ChillMainBundle/Resources/public/lib/api/user.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import {User} from "../../types";
|
||||
import {makeFetch} from "./apiMethods";
|
||||
|
||||
export const whoami = (): Promise<User> => {
|
||||
const url = `/api/1.0/main/whoami.json`;
|
||||
return fetch(url)
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
throw {
|
||||
msg: 'Error while getting whoami.',
|
||||
sta: response.status,
|
||||
txt: response.statusText,
|
||||
err: new Error(),
|
||||
body: response.body
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const whereami = (): Promise<Location | null> => {
|
||||
const url = `/api/1.0/main/user-current-location.json`;
|
||||
|
||||
return makeFetch<null, Location|null>("GET", url);
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@@ -15,12 +15,12 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var mime = require('mime-types')
|
||||
var mime = require('mime')
|
||||
|
||||
var download_report = (url, container) => {
|
||||
var download_text = container.dataset.downloadText,
|
||||
alias = container.dataset.alias;
|
||||
|
||||
|
||||
window.fetch(url, { credentials: 'same-origin' })
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
@@ -29,21 +29,21 @@ var download_report = (url, container) => {
|
||||
|
||||
return response.blob();
|
||||
}).then(blob => {
|
||||
|
||||
|
||||
var content = URL.createObjectURL(blob),
|
||||
link = document.createElement("a"),
|
||||
type = blob.type,
|
||||
hasForcedType = 'mimeType' in container.dataset,
|
||||
extension;
|
||||
|
||||
|
||||
if (hasForcedType) {
|
||||
// force a type
|
||||
type = container.dataset.mimeType;
|
||||
blob = new Blob([ blob ], { 'type': type });
|
||||
content = URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
extension = mime.extension(type);
|
||||
|
||||
extension = mime.getExtension(type);
|
||||
|
||||
link.appendChild(document.createTextNode(download_text));
|
||||
link.classList.add("btn", "btn-action");
|
||||
@@ -56,7 +56,7 @@ var download_report = (url, container) => {
|
||||
container.appendChild(link);
|
||||
}).catch(function(error) {
|
||||
console.log(error);
|
||||
var problem_text =
|
||||
var problem_text =
|
||||
document.createTextNode("Problem during download");
|
||||
|
||||
container
|
||||
@@ -64,4 +64,4 @@ var download_report = (url, container) => {
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = download_report;
|
||||
module.exports = download_report;
|
||||
|
@@ -14,9 +14,11 @@
|
||||
|
||||
// 4. Include any default map overrides here
|
||||
@import "custom/_maps";
|
||||
@import "bootstrap/scss/maps";
|
||||
|
||||
// 5. Include remainder of required parts
|
||||
@import "bootstrap/scss/mixins";
|
||||
@import "bootstrap/scss/utilities";
|
||||
@import "bootstrap/scss/root";
|
||||
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import { appMessages } from 'ChillMainAssets/vuejs/PickEntity/i18n';
|
||||
const i18n = _createI18n(appMessages);
|
||||
|
||||
let appsOnPage = new Map();
|
||||
let appsPerInput = new Map();
|
||||
|
||||
function loadDynamicPicker(element) {
|
||||
|
||||
@@ -78,13 +79,14 @@ function loadDynamicPicker(element) {
|
||||
.mount(el);
|
||||
|
||||
appsOnPage.set(uniqId, app);
|
||||
appsPerInput.set(input.name, app);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('show-hide-show', function(e) {
|
||||
loadDynamicPicker(e.detail.container)
|
||||
})
|
||||
});
|
||||
|
||||
document.addEventListener('show-hide-hide', function(e) {
|
||||
console.log('hiding event caught')
|
||||
@@ -95,13 +97,25 @@ document.addEventListener('show-hide-hide', function(e) {
|
||||
appsOnPage.delete(uniqId);
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
document.addEventListener('pick-entity-type-action', function (e) {
|
||||
console.log('pick entity event', e);
|
||||
if (!appsPerInput.has(e.detail.name)) {
|
||||
console.error('no app with this name');
|
||||
return;
|
||||
}
|
||||
const app = appsPerInput.get(e.detail.name);
|
||||
if (e.detail.action === 'add') {
|
||||
app.addNewEntity(e.detail.entity);
|
||||
} else if (e.detail.action === 'remove') {
|
||||
app.removeEntity(e.detail.entity);
|
||||
} else {
|
||||
console.error('action not supported: '+e.detail.action);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function(e) {
|
||||
loadDynamicPicker(document)
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -0,0 +1,28 @@
|
||||
import {ShowHide} from 'ChillMainAssets/lib/show_hide/index';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function(_e) {
|
||||
console.log('pick-rolling-date');
|
||||
document.querySelectorAll('div[data-rolling-date]').forEach( (picker) => {
|
||||
const
|
||||
roll_wrapper = picker.querySelector('div.roll-wrapper'),
|
||||
fixed_wrapper = picker.querySelector('div.fixed-wrapper');
|
||||
|
||||
new ShowHide({
|
||||
froms: [roll_wrapper],
|
||||
container: [fixed_wrapper],
|
||||
test: function (elems) {
|
||||
console.log('testing');
|
||||
console.log('elems', elems);
|
||||
for (let el of elems) {
|
||||
for (let select_roll of el.querySelectorAll('select[data-roll-picker]')) {
|
||||
console.log('select_roll', select_roll);
|
||||
console.log('value', select_roll.value);
|
||||
return select_roll.value === 'fixed_date';
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
139
src/Bundle/ChillMainBundle/Resources/public/types.ts
Normal file
139
src/Bundle/ChillMainBundle/Resources/public/types.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
export interface DateTime {
|
||||
datetime: string;
|
||||
datetime8601: string
|
||||
}
|
||||
|
||||
export interface Civility {
|
||||
id: number;
|
||||
// TODO
|
||||
}
|
||||
|
||||
export interface Job {
|
||||
id: number;
|
||||
type: "user_job";
|
||||
label: {
|
||||
"fr": string; // could have other key. How to do that in ts ?
|
||||
}
|
||||
}
|
||||
|
||||
export interface Center {
|
||||
id: number;
|
||||
type: "center";
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Scope {
|
||||
id: number;
|
||||
type: "scope";
|
||||
name: {
|
||||
"fr": string
|
||||
}
|
||||
}
|
||||
|
||||
export interface User {
|
||||
type: "user";
|
||||
id: number;
|
||||
username: string;
|
||||
text: string;
|
||||
email: string;
|
||||
user_job: Job;
|
||||
label: string;
|
||||
// todo: mainCenter; mainJob; etc..
|
||||
}
|
||||
|
||||
export interface UserAssociatedInterface {
|
||||
type: "user";
|
||||
id: number;
|
||||
};
|
||||
|
||||
export type TranslatableString = {
|
||||
fr?: string;
|
||||
nl?: string;
|
||||
}
|
||||
|
||||
export interface Postcode {
|
||||
id: number;
|
||||
name: string;
|
||||
code: string;
|
||||
center: Point;
|
||||
}
|
||||
|
||||
export type Point = {
|
||||
type: "Point";
|
||||
coordinates: [lat: number, lon: number];
|
||||
}
|
||||
|
||||
export interface Country {
|
||||
id: number;
|
||||
name: TranslatableString;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface Address {
|
||||
type: "address";
|
||||
address_id: number;
|
||||
text: string;
|
||||
street: string;
|
||||
streetNumber: string;
|
||||
postcode: Postcode;
|
||||
country: Country;
|
||||
floor: string | null;
|
||||
corridor: string | null;
|
||||
steps: string | null;
|
||||
flat: string | null;
|
||||
buildingName: string | null;
|
||||
distribution: string | null;
|
||||
extra: string | null;
|
||||
confidential: boolean;
|
||||
lines: string[];
|
||||
addressReference: AddressReference | null;
|
||||
validFrom: DateTime;
|
||||
validTo: DateTime | null;
|
||||
}
|
||||
|
||||
export interface AddressReference {
|
||||
id: number;
|
||||
createdAt: DateTime | null;
|
||||
deletedAt: DateTime | null;
|
||||
municipalityCode: string;
|
||||
point: Point;
|
||||
postcode: Postcode;
|
||||
refId: string;
|
||||
source: string;
|
||||
street: string;
|
||||
streetNumber: string;
|
||||
updatedAt: DateTime | null;
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
type: "location";
|
||||
id: number;
|
||||
active: boolean;
|
||||
address: Address | null;
|
||||
availableForUsers: boolean;
|
||||
createdAt: DateTime | null;
|
||||
createdBy: User | null;
|
||||
updatedAt: DateTime | null;
|
||||
updatedBy: User | null;
|
||||
email: string | null
|
||||
name: string;
|
||||
phonenumber1: string | null;
|
||||
phonenumber2: string | null;
|
||||
locationType: LocationType;
|
||||
}
|
||||
|
||||
export interface LocationAssociated {
|
||||
type: "location";
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface LocationType {
|
||||
type: "location-type";
|
||||
id: number;
|
||||
active: boolean;
|
||||
addressRequired: "optional" | "required";
|
||||
availableForUsers: boolean;
|
||||
editableByUsers: boolean;
|
||||
contactData: "optional" | "required";
|
||||
title: TranslatableString;
|
||||
}
|
@@ -54,7 +54,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { dateToISO, ISOToDate } from 'ChillMainAssets/chill/js/date.js';
|
||||
import { dateToISO, ISOToDate } from 'ChillMainAssets/chill/js/date';
|
||||
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
|
||||
import ActionButtons from './ActionButtons.vue';
|
||||
|
||||
|
@@ -146,6 +146,9 @@ export default {
|
||||
}
|
||||
},
|
||||
titleCreate() {
|
||||
if (typeof this.allowedTypes === 'undefined') {
|
||||
return 'onthefly.create.title.default';
|
||||
}
|
||||
return this.allowedTypes.every(t => t === 'person')
|
||||
? 'onthefly.create.title.person'
|
||||
: this.allowedTypes.every(t => t === 'thirdparty')
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ul class="list-suggest remove-items" v-if="picked.length">
|
||||
<ul :class="listClasses" v-if="picked.length && displayPicked">
|
||||
<li v-for="p in picked" @click="removeEntity(p)" :key="p.type+p.id">
|
||||
<span class="chill_denomination">{{ p.text }}</span>
|
||||
</li>
|
||||
@@ -40,6 +40,15 @@ export default {
|
||||
uniqid: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
removableIfSet: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
displayPicked: {
|
||||
// display picked entities.
|
||||
type: Boolean,
|
||||
default: true,
|
||||
}
|
||||
},
|
||||
emits: ['addNewEntity', 'removeEntity'],
|
||||
@@ -78,7 +87,13 @@ export default {
|
||||
} else {
|
||||
return appMessages.fr.pick_entity.modal_title_one + trans.join(', ');
|
||||
}
|
||||
}
|
||||
},
|
||||
listClasses() {
|
||||
return {
|
||||
'list-suggest': true,
|
||||
'remove-items': this.$props.removableIfSet,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
addNewEntity({ selected, modal }) {
|
||||
@@ -90,6 +105,9 @@ export default {
|
||||
modal.showModal = false;
|
||||
},
|
||||
removeEntity(entity) {
|
||||
if (!this.$props.removableIfSet) {
|
||||
return;
|
||||
}
|
||||
this.$emit('removeEntity', entity);
|
||||
}
|
||||
},
|
||||
|
@@ -20,7 +20,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {makeFetch} from 'ChillMainAssets/lib/api/apiMethods.js';
|
||||
import {makeFetch} from 'ChillMainAssets/lib/api/apiMethods.ts';
|
||||
|
||||
export default {
|
||||
name: "EntityWorkflowVueSubscriber",
|
||||
|
@@ -2,57 +2,65 @@
|
||||
<transition name="modal">
|
||||
<div class="modal-mask">
|
||||
<!-- :: styles bootstrap :: -->
|
||||
<div class="modal-dialog" :class="modalDialogClass">
|
||||
<div class="modal fade show" style="display: block" aria-modal="true" role="dialog">
|
||||
<div class="modal-dialog" :class="modalDialogClass">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<slot name="header"></slot>
|
||||
<button class="close btn" @click="$emit('close')">
|
||||
<i class="fa fa-times" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
<div class="body-head">
|
||||
<div class="modal-header">
|
||||
<slot name="header"></slot>
|
||||
<button class="close btn" @click="$emit('close')">
|
||||
<i class="fa fa-times" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="body-head">
|
||||
<slot name="body-head"></slot>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<slot name="body"></slot>
|
||||
</div>
|
||||
<div class="modal-footer" v-if="!hideFooter">
|
||||
<button class="btn btn-cancel" @click="$emit('close')">{{ $t('action.close') }}</button>
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<slot name="body"></slot>
|
||||
</div>
|
||||
<div class="modal-footer" v-if="!hideFooter">
|
||||
<button class="btn btn-cancel" @click="$emit('close')">{{ $t('action.close') }}</button>
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- :: end styles bootstrap :: -->
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {defineComponent} from "vue";
|
||||
/*
|
||||
* This Modal component is a mix between Vue3 modal implementation
|
||||
* [+] with 'v-if:showModal' directive:parameter, html scope is added/removed not just shown/hidden
|
||||
* [+] with slot we can pass content from parent component
|
||||
* [+] some classes are passed from parent component
|
||||
* and Bootstrap 4.6 _modal.scss module
|
||||
* and Bootstrap 5 _modal.scss module
|
||||
* [+] using bootstrap css classes, the modal have a responsive behaviour,
|
||||
* [+] modal design can be configured using css classes (size, scroll)
|
||||
*/
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'Modal',
|
||||
props: {
|
||||
modalDialogClass: {
|
||||
type: String,
|
||||
required: false
|
||||
type: Object,
|
||||
required: false,
|
||||
default: {},
|
||||
},
|
||||
hideFooter: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ['close']
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/**
|
||||
* This is a mask behind the modal.
|
||||
*/
|
||||
.modal-mask {
|
||||
position: fixed;
|
||||
z-index: 9998;
|
||||
|
@@ -41,7 +41,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods.js';
|
||||
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods.ts';
|
||||
|
||||
export default {
|
||||
name: "NotificationReadToggle",
|
||||
|
@@ -1,27 +1,6 @@
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import datetimeFormats from '../i18n/datetimeFormats';
|
||||
|
||||
const datetimeFormats = {
|
||||
fr: {
|
||||
short: {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric"
|
||||
},
|
||||
text: {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
},
|
||||
long: {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: false
|
||||
}
|
||||
}
|
||||
};
|
||||
const messages = {
|
||||
fr: {
|
||||
action: {
|
||||
@@ -76,11 +55,13 @@ const messages = {
|
||||
}
|
||||
};
|
||||
|
||||
const _createI18n = (appMessages) => {
|
||||
const _createI18n = (appMessages: any, legacy?: boolean) => {
|
||||
Object.assign(messages.fr, appMessages.fr);
|
||||
return createI18n({
|
||||
legacy: typeof legacy === undefined ? true : legacy,
|
||||
locale: 'fr',
|
||||
fallbackLocale: 'fr',
|
||||
// @ts-ignore
|
||||
datetimeFormats,
|
||||
messages,
|
||||
})
|
@@ -0,0 +1,27 @@
|
||||
export default {
|
||||
fr: {
|
||||
short: {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric"
|
||||
},
|
||||
text: {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
},
|
||||
long: {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: false
|
||||
},
|
||||
hoursOnly: {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: false,
|
||||
}
|
||||
}
|
||||
};
|
@@ -0,0 +1,6 @@
|
||||
<h6>
|
||||
<a href="{{ path('chill_main_export_index') }}" title="{{ 'Back to the list'|trans }}">
|
||||
<i class="fa fa-folder-open-o fa-fw"></i>
|
||||
</a>
|
||||
{{ export_group|trans }}
|
||||
</h6>
|
@@ -0,0 +1,12 @@
|
||||
<ul class="nav nav-pills justify-content-center">
|
||||
<li class="nav-item">
|
||||
<a href="{{ chill_path_forward_return_path('chill_main_export_index') }}" class="nav-link {% if current == 'common' %}active{% endif %}">
|
||||
{{ 'Exports list'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{{ chill_path_forward_return_path('chill_main_export_saved_list_my') }}" class="nav-link {% if current == 'my' %}active{% endif %}">
|
||||
{{ 'saved_export.My saved exports'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
@@ -36,10 +36,7 @@ window.addEventListener("DOMContentLoaded", function(e) {
|
||||
{% block content %}
|
||||
<div class="col-md-10">
|
||||
|
||||
<h6>
|
||||
<i class="fa fa-folder-open-o fa-fw"></i>
|
||||
{{ export_group|trans }}
|
||||
</h6>
|
||||
{{ include('@ChillMain/Export/_breadcrumb.html.twig') }}
|
||||
|
||||
<h1>{{ export.title|trans }}</h1>
|
||||
<h2>{{ "Download export"|trans }}</h2>
|
||||
@@ -52,5 +49,14 @@ window.addEventListener("DOMContentLoaded", function(e) {
|
||||
data-download-text="{{ "Download your report"|trans|escape('html_attr') }}"
|
||||
><span id="waiting_text">{{ "Waiting for your report"|trans ~ '...' }}</span></div>
|
||||
|
||||
</div>
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel"><a href="{{ chill_return_path_or('chill_main_export_index') }}" class="btn btn-cancel">{{ 'Back to the list'|trans }}</a></li>
|
||||
|
||||
{% if not app.request.query.has('prevent_save') %}
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_main_export_save_from_key', { alias: alias, key: app.request.query.get('key')}) }}" class="btn btn-save">{{ 'Save'|trans }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock content %}
|
@@ -22,23 +22,27 @@
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="col-md-10">
|
||||
<h1>{{ 'Exports list'|trans }}</h1>
|
||||
|
||||
|
||||
{{ include('@ChillMain/Export/_navbar.html.twig', {'current' : 'common'}) }}
|
||||
|
||||
<div class="col-md-10 exports-list">
|
||||
|
||||
<div class="container mt-4">
|
||||
|
||||
{% for group, exports in grouped_exports %}{% if group != '_' %}
|
||||
<h2 class="display-6">{{ group|trans }}</h2>
|
||||
<div class="row grouped">
|
||||
<div class="row flex-bloc">
|
||||
{% for export_alias, export in exports %}
|
||||
<div class="col-6 col-md-4 mb-3">
|
||||
<h2>{{ export.title|trans }}</h2>
|
||||
<p>{{ export.description|trans }}</p>
|
||||
<p>
|
||||
<a class="btn btn-action" href="{{ path('chill_main_export_new', { 'alias': export_alias } ) }}">
|
||||
{{ 'Create an export'|trans }}
|
||||
</a>
|
||||
</p>
|
||||
<div class="item-bloc">
|
||||
<div class="item-row card-body">
|
||||
<h2 class="card-title">{{ export.title|trans }}</h2>
|
||||
<p class="card-text my-3">{{ export.description|trans }}</p>
|
||||
<p>
|
||||
<a class="btn btn-action" href="{{ path('chill_main_export_new', { 'alias': export_alias } ) }}">
|
||||
{{ 'Create an export'|trans }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -48,17 +52,19 @@
|
||||
<h2 class="display-6">{{ 'Ungrouped exports'|trans }}</h2>
|
||||
{% endif %}
|
||||
|
||||
<div class="row ungrouped">
|
||||
<div class="row flex-bloc">
|
||||
{% for export_alias,export in grouped_exports['_'] %}
|
||||
|
||||
<div class="col-6 col-md-4 mb-3">
|
||||
<h2>{{ export.title|trans }}</h2>
|
||||
<p>{{ export.description|trans }}</p>
|
||||
<p>
|
||||
<a class="btn btn-action" href="{{ path('chill_main_export_new', { 'alias': export_alias } ) }}">
|
||||
{{ 'Create an export'|trans }}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<div class="item-bloc">
|
||||
<div class="item-row card-body">
|
||||
<h2 class="card-title">{{ export.title|trans }}</h2>
|
||||
<p class="card-text my-3">{{ export.description|trans }}</p>
|
||||
<p>
|
||||
<a class="btn btn-action" href="{{ path('chill_main_export_new', { 'alias': export_alias } ) }}">
|
||||
{{ 'Create an export'|trans }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
@@ -20,17 +20,24 @@
|
||||
|
||||
{% block title %}{{ export.title|trans }}{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
||||
{{ encore_entry_link_tags('mod_pick_rolling_date') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
||||
{{ encore_entry_script_tags('page_export') }}
|
||||
{% if export_alias == 'count_social_work_actions' %}
|
||||
{{ encore_entry_script_tags('vue_export_action_goal_result') }}
|
||||
{% endif %}
|
||||
{{ encore_entry_script_tags('mod_pick_rolling_date') }}
|
||||
{% endblock js %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-md-10">
|
||||
|
||||
<h6>
|
||||
<i class="fa fa-folder-open-o fa-fw"></i>
|
||||
{{ export_group|trans }}
|
||||
</h6>
|
||||
{{ include('@ChillMain/Export/_breadcrumb.html.twig') }}
|
||||
|
||||
<h1>{{ export.title|trans }}</h1>
|
||||
|
||||
|
@@ -22,11 +22,8 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="col-md-10">
|
||||
|
||||
<h6>
|
||||
<i class="fa fa-folder-open-o fa-fw"></i>
|
||||
{{ export_group|trans }}
|
||||
</h6>
|
||||
|
||||
{{ include('@ChillMain/Export/_breadcrumb.html.twig') }}
|
||||
|
||||
<h1>{{ export.title|trans }}</h1>
|
||||
|
||||
|
@@ -23,10 +23,7 @@
|
||||
{% block content %}
|
||||
<div class="col-md-10">
|
||||
|
||||
<h6>
|
||||
<i class="fa fa-folder-open-o fa-fw"></i>
|
||||
{{ export_group|trans }}
|
||||
</h6>
|
||||
{{ include('@ChillMain/Export/_breadcrumb.html.twig') }}
|
||||
|
||||
<h1>{{ export.title|trans }}</h1>
|
||||
|
||||
@@ -36,19 +33,21 @@
|
||||
<section class="formatter mb-4">
|
||||
<h2>{{ 'Formatter'| trans }}</h2>
|
||||
|
||||
<div>
|
||||
{% if form.children.formatter.children|length == 0 %}
|
||||
<p>
|
||||
<span class="chill-no-data-statement">{{ "No options availables. Your report is fully configured."|trans }}</span>
|
||||
</p>
|
||||
{{ form_widget(form.children.formatter) }}
|
||||
{% else %}
|
||||
{# we always have to render children, to mark as rendered #}
|
||||
{% for input in form.children.formatter.children %}
|
||||
{{ form_row(input) }}
|
||||
{% endfor %}
|
||||
<div class="container py-4">
|
||||
{# we always have to render children, to mark as rendered #}
|
||||
{% for input in form.children.formatter.children %}
|
||||
<div class="row">
|
||||
{{ form_row(input) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="mb-4">
|
||||
|
@@ -10,6 +10,30 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if form.dateRanges is defined %}
|
||||
{% if form.dateRanges|length > 0 %}
|
||||
{% for dateRangeName, _o in form.dateRanges %}
|
||||
<div class="row gx-2 justify-content-center">
|
||||
{% if form.dateRanges[dateRangeName].vars.label is not same as(false) %}
|
||||
<div class="col-md-5">
|
||||
{{ form_label(form.dateRanges[dateRangeName])}}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-md-6">
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text">{{ 'chill_calendar.From'|trans }}</span>
|
||||
{{ form_widget(form.dateRanges[dateRangeName]['from']) }}
|
||||
<span class="input-group-text">{{ 'chill_calendar.To'|trans }}</span>
|
||||
{{ form_widget(form.dateRanges[dateRangeName]['to']) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
<button type="submit" class="btn btn-misc"><i class="fa fa-filter"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if form.checkboxes is defined %}
|
||||
{% if form.checkboxes|length > 0 %}
|
||||
{% for checkbox_name, options in form.checkboxes %}
|
||||
|
@@ -233,9 +233,22 @@
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block pick_entity_dynamic_row %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ form_label(form) }}
|
||||
{{ form_help(form) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-end">
|
||||
<div class="col-md-7 col-sm-12">
|
||||
{{ form_widget(form) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block pick_entity_dynamic_widget %}
|
||||
{{ form_help(form)}}
|
||||
<input type="hidden" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %} data-input-uniqid="{{ form.vars['uniqid'] }}"/>
|
||||
<input type="hidden" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value|escape('html_attr') }}" {% endif %} data-input-uniqid="{{ form.vars['uniqid'] }}"/>
|
||||
<div data-module="pick-dynamic" data-types="{{ form.vars['types']|json_encode }}" data-multiple="{{ form.vars['multiple'] }}" data-uniqid="{{ form.vars['uniqid'] }}"></div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -244,3 +257,16 @@
|
||||
<input type="hidden" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %} data-input-uniqid="{{ form.vars['uniqid'] }}"/>
|
||||
<div data-module="pick-postal-code" data-uniqid="{{ form.vars['uniqid'] }}"></div>
|
||||
{% endblock %}
|
||||
|
||||
{% block pick_rolling_date_widget %}
|
||||
<div data-rolling-date="{{ form.vars['uniqid'] }}" class="row">
|
||||
<div class="roll-wrapper col-sm-6">
|
||||
{{ form_widget(form.roll, { 'attr': { 'data-roll-picker': 'data-roll-picker'}}) }}
|
||||
{{ form_errors(form.roll) }}
|
||||
</div>
|
||||
<div class="fixed-wrapper col-sm-6">
|
||||
{{ form_widget(form.fixedDate) }}
|
||||
{{ form_errors(form.fixedDate) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@@ -0,0 +1,25 @@
|
||||
{% extends '@ChillMain/layout.html.twig' %}
|
||||
|
||||
{% block title 'saved_export.Delete saved ?'|trans %}
|
||||
|
||||
{% block display_content %}
|
||||
<div class="col-10">
|
||||
<h3>{{ saved_export.title }}</h3>
|
||||
<p>{{ saved_export.description|chill_markdown_to_html }}</p>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container chill-md-10">
|
||||
{{ include('@ChillMain/Util/confirmation_template.html.twig',
|
||||
{
|
||||
'title' : 'saved_export.Delete saved ?'|trans,
|
||||
'confirm_question' : 'saved_export.Are you sure you want to delete this saved ?'|trans,
|
||||
'display_content' : block('display_content'),
|
||||
'cancel_route' : 'chill_main_export_saved_list_my',
|
||||
'cancel_parameters' : {},
|
||||
'form' : delete_form
|
||||
} ) }}
|
||||
</div>
|
||||
{% endblock %}
|
@@ -0,0 +1,23 @@
|
||||
{% extends "@ChillMain/layout.html.twig" %}
|
||||
|
||||
{% block title %}{{ 'saved_export.Edit'|trans }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-10">
|
||||
<h1>{{ block('title') }}</h1>
|
||||
|
||||
{{ form_start(form) }}
|
||||
{{ form_row(form.title) }}
|
||||
{{ form_row(form.description) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
<a href="{{ chill_return_path_or('chill_main_homepage') }}" class="btn btn-cancel">{{ 'Cancel'|trans }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<button type="submit" class="btn btn-save">{{ 'Save'|trans }}</button>
|
||||
</li>
|
||||
</ul>
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
{% endblock %}
|
@@ -0,0 +1,78 @@
|
||||
{% extends "@ChillMain/layout.html.twig" %}
|
||||
|
||||
{% block title %}{{ 'saved_export.My saved exports'|trans }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-md-10 exports-list">
|
||||
|
||||
{{ include('@ChillMain/Export/_navbar.html.twig', {'current' : 'my'}) }}
|
||||
|
||||
<div class="container mt-4">
|
||||
|
||||
{% if total == 0 %}
|
||||
<p class="chill-no-data-statement" >{{ 'saved_export.Any saved export'|trans }}</p>
|
||||
{% endif %}
|
||||
|
||||
{% for group, saveds in grouped_exports %}
|
||||
{% if group != '_' %}
|
||||
<h2 class="display-6">{{ group }}</h2>
|
||||
<div class="row flex-bloc">
|
||||
{% for s in saveds %}
|
||||
<div class="item-bloc">
|
||||
<div class="item-row card-body">
|
||||
<p class="card-subtitle"><strong>{{ s.export.title|trans }}</strong></p>
|
||||
<h2 class="card-title">{{ s.saved.title }}</h2>
|
||||
|
||||
<div class="createdBy">{{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}</div>
|
||||
|
||||
<div class="card-text my-3">
|
||||
{{ s.saved.description|chill_markdown_to_html }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ul class="record_actions">
|
||||
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_delete', {'id': s.saved.id }) }}" class="btn btn-delete"></a></li>
|
||||
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_edit', {'id': s.saved.id }) }}" class="btn btn-edit"></a></li>
|
||||
<li><a href="{{ path('chill_main_export_generate_from_saved', { id: s.saved.id }) }}" class="btn btn-action"><i class="fa fa-cog"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if grouped_exports|keys|length > 1 and grouped_exports['_']|default([])|length > 0 %}
|
||||
<h2 class="display-6">{{ 'Ungrouped exports'|trans }}</h2>
|
||||
{% endif %}
|
||||
|
||||
<div class="row flex-bloc">
|
||||
{% for saveds in grouped_exports['_']|default([]) %}
|
||||
{% for s in saveds %}
|
||||
<div class="item-bloc">
|
||||
<div class="item-row card-body">
|
||||
<p class="card-subtitle"><strong>{{ s.export.title|trans }}</strong></p>
|
||||
<h2 class="card-title">{{ s.saved.title }}</h2>
|
||||
|
||||
<div class="createdBy">{{ 'saved_export.Created on %date%'|trans({'%date%': s.saved.createdAt|format_datetime('long', 'short')}) }}</div>
|
||||
|
||||
<div class="card-text my-3">
|
||||
{{ s.saved.description|chill_markdown_to_html }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ul class="record_actions">
|
||||
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_delete', {'id': s.saved.id }) }}" class="btn btn-delete"></a></li>
|
||||
<li><a href="{{ chill_path_add_return_path('chill_main_export_saved_edit', {'id': s.saved.id }) }}" class="btn btn-edit"></a></li>
|
||||
<li><a href="{{ path('chill_main_export_generate_from_saved', { id: s.saved.id }) }}" class="btn btn-action"><i class="fa fa-cog"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@@ -0,0 +1,23 @@
|
||||
{% extends "@ChillMain/layout.html.twig" %}
|
||||
|
||||
{% block title %}{{ 'saved_export.New'|trans }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-10">
|
||||
<h1>{{ block('title') }}</h1>
|
||||
|
||||
{{ form_start(form) }}
|
||||
{{ form_row(form.title) }}
|
||||
{{ form_row(form.description) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
<a href="{{ chill_return_path_or('chill_main_homepage') }}" class="btn btn-cancel">{{ 'Cancel'|trans }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<button type="submit" class="btn btn-save">{{ 'Save'|trans }}</button>
|
||||
</li>
|
||||
</ul>
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
{% endblock %}
|
Reference in New Issue
Block a user