Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
olmobrutall committed Jul 15, 2019
2 parents 7ddc8ec + b46defd commit 9dfe0be
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 33 deletions.
3 changes: 3 additions & 0 deletions Signum.Engine/Schema/EntityEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ internal IEnumerable<FilterQueryResult<T>> OnFilterQuery()
return FilterQuery.GetInvocationListTyped().Select(f => f()).NotNull().ToList();
}

public IDisposable? OnPreUnsafeDelete(IQueryable entityQuery) => this.OnPreUnsafeDelete((IQueryable<T/*Entity*/>)entityQuery);
internal IDisposable? OnPreUnsafeDelete(IQueryable<T> entityQuery)
{
IDisposable? result = null;
Expand Down Expand Up @@ -151,6 +152,7 @@ void IEntityEvents.OnRetrieved(Entity entity)

}


ICacheController? IEntityEvents.CacheController
{
get { return CacheController; }
Expand Down Expand Up @@ -297,6 +299,7 @@ internal interface IEntityEvents

void OnRetrieved(Entity entity);

IDisposable? OnPreUnsafeDelete(IQueryable entityQuery);
IDisposable? OnPreUnsafeUpdate(IUpdateable update);
LambdaExpression OnPreUnsafeInsert(IQueryable query, LambdaExpression constructor, IQueryable entityQuery);
void OnPreBulkInsert(bool inMListTable);
Expand Down
2 changes: 1 addition & 1 deletion Signum.Engine/Schema/Schema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ internal void OnRetrieved(Entity entity)
if (ee == null)
return null;

return ee.OnPreUnsafeDelete(entityQuery);
return Disposable.Combine(ee?.OnPreUnsafeDelete(entityQuery), entityEventsGlobal.OnPreUnsafeDelete(entityQuery));
}

internal IDisposable? OnPreUnsafeMListDelete<T>(IQueryable mlistQuery, IQueryable<T> entityQuery) where T : Entity
Expand Down
3 changes: 2 additions & 1 deletion Signum.React/Scripts/Finder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -743,8 +743,9 @@ export function toFilterRequest(fop: FilterOptionParsed, overridenValue?: Overri
if (fop.token == null || fop.token.filterType == null || fop.operation == null)
return undefined;

if (overridenValue == null && fop.pinned && fop.pinned.disableOnNull && (fop.value == null || fop.value == ""))
if (overridenValue == null && fop.pinned && fop.pinned.disableOnNull && (fop.value == null || fop.value === "")) {
return undefined;
}

if (overridenValue && fop.token && typeof overridenValue.value == "string") {
if (fop.token.type.name == "number") {
Expand Down
11 changes: 4 additions & 7 deletions Signum.React/Scripts/Frames/FrameModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,15 +240,12 @@ export default class FrameModal extends React.Component<FrameModalProps, FrameMo
const frame: EntityFrame = {
frameComponent: this,
entityComponent: this.entityComponent,
onReload: pack => {
onReload: (pack, reloadComponent) => {
var newPack = pack || this.state.pack!;

if (is(this.state.pack!.entity as Entity, newPack.entity as Entity))
this.setPack(newPack);
else {
this.setPack(newPack);

this.setPack(newPack);
if (reloadComponent)
this.setState({ getComponent: undefined }, () => this.loadComponent(newPack).done()); //For AutoFocus and potentialy another view
}
},
pack: this.state.pack,
onClose: (ok?: boolean) => this.props.onExited!(ok ? this.state.pack!.entity : undefined),
Expand Down
7 changes: 7 additions & 0 deletions Signum.React/Scripts/Globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ declare global {
dataForChildWindow?: any;
}

interface RegExpConstructor {
escape(str: string): string;
}

interface Array<T> {
groupBy<K extends string | number>(this: Array<T>, keySelector: (element: T) => K): { key: K; elements: T[] }[];
groupToObject(this: Array<T>, keySelector: (element: T) => string): { [key: string]: T[] };
Expand Down Expand Up @@ -996,6 +1000,9 @@ export function combineFunction<F extends Function>(func1?: F | null, func2?: F
} as any;
}

RegExp.escape = function (s: string) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
};


export function areEqual<T>(a: T | undefined, b: T | undefined, field: (value: T) => any): boolean {
Expand Down
4 changes: 2 additions & 2 deletions Signum.React/Scripts/Operations/EntityOperations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ export function andNew<T extends Entity>(eoc: EntityOperationContext<T>, inDropd

if (createNew)
createNew()
.then(newPack => newPack && eoc.frame.onReload(newPack))
.then(newPack => newPack && eoc.frame.onReload(newPack, true))
.done();
else
Constructor.constructPack(pack.entity.Type)
.then(newPack => newPack && eoc.frame.onReload(newPack))
.then(newPack => newPack && eoc.frame.onReload(newPack, true))
.done();
};
eoc.defaultClick();
Expand Down
55 changes: 35 additions & 20 deletions Signum.React/Scripts/SearchControl/FilterBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as moment from 'moment'
import { Dic, areEqual, classes } from '../Globals'
import { FilterOptionParsed, QueryDescription, QueryToken, SubTokensOptions, filterOperations, isList, FilterOperation, FilterConditionOptionParsed, FilterGroupOptionParsed, isFilterGroupOptionParsed, hasAnyOrAll, getTokenParents, isPrefix, FilterConditionOption, PinnedFilter } from '../FindOptions'
import { SearchMessage } from '../Signum.Entities'
import { ValueLine, EntityLine, EntityCombo, StyleContext } from '../Lines'
import { ValueLine, EntityLine, EntityCombo, StyleContext, FormControlReadonly } from '../Lines'
import { Binding, IsByAll, getTypeInfos, toMomentFormat } from '../Reflection'
import { TypeContext } from '../TypeContext'
import QueryTokenBuilder from './QueryTokenBuilder'
Expand Down Expand Up @@ -250,7 +250,7 @@ export class FilterGroupComponent extends React.Component<FilterGroupComponentsP
</div>}
<div>
{this.props.showPinnedFilters &&
<button className={classes("btn", "btn-link", "btn-sm", "sf-user-filter", fg.pinned && "active")} onClick={e => { fg.pinned = fg.pinned ? undefined : {}; this.changeFilter(); }}>
<button className={classes("btn", "btn-link", "btn-sm", "sf-user-filter", fg.pinned && "active")} onClick={e => { fg.pinned = fg.pinned ? undefined : {}; this.changeFilter(); }} disabled={this.props.readOnly}>
<FontAwesomeIcon color="orange" icon={[fg.pinned ? "fas" : "far", "star"]} />
</button>
}
Expand All @@ -259,7 +259,7 @@ export class FilterGroupComponent extends React.Component<FilterGroupComponentsP
<div className="sf-filters-list table-responsive" style={{ overflowX: "visible" }}>
<table className="table-sm" style={{ width: "100%" }}>
<thead>
{fg.pinned && <PinnedFilterEditor pinned={fg.pinned} onChange={() => this.changeFilter()} />}
{fg.pinned && <PinnedFilterEditor pinned={fg.pinned} onChange={() => this.changeFilter()} readonly={readOnly} />}
<tr>
<th style={{ minWidth: "24px" }}></th>
<th>{SearchMessage.Field.niceToString()}</th>
Expand Down Expand Up @@ -446,13 +446,13 @@ export class FilterConditionComponent extends React.Component<FilterConditionCom
</td>
{f.token && f.token.filterType && f.operation && this.props.showPinnedFilters &&
<td>
<button className={classes("btn", "btn-link", "btn-sm", "sf-user-filter", f.pinned && "active")} onClick={e => { f.pinned = f.pinned ? undefined : {}; this.changeFilter(); }}>
<button className={classes("btn", "btn-link", "btn-sm", "sf-user-filter", f.pinned && "active")} onClick={e => { f.pinned = f.pinned ? undefined : {}; this.changeFilter(); }} disabled={this.props.readOnly}>
<FontAwesomeIcon color="orange" icon={[f.pinned ? "fas" : "far", "star"]} />
</button>
</td>
}
</tr>
{this.props.showPinnedFilters && f.pinned && <PinnedFilterEditor pinned={f.pinned} onChange={() => this.changeFilter()} />}
{this.props.showPinnedFilters && f.pinned && <PinnedFilterEditor pinned={f.pinned} onChange={() => this.changeFilter()} readonly={readOnly} />}
</>
);
}
Expand Down Expand Up @@ -488,6 +488,7 @@ export class FilterConditionComponent extends React.Component<FilterConditionCom

interface PinnedFilterEditorProps {
pinned: PinnedFilter;
readonly: boolean;
onChange: () => void;
}

Expand All @@ -499,17 +500,15 @@ export class PinnedFilterEditor extends React.Component<PinnedFilterEditorProps>
<td></td>
<td>
<div>
<input type="text" className="form-control form-control-xs" placeholder={SearchMessage.Label.niceToString()}
<input type="text" className="form-control form-control-xs" placeholder={SearchMessage.Label.niceToString()} readOnly={this.props.readonly}
value={p.label || ""}
onChange={e => { p!.label = e.currentTarget.value; this.props.onChange(); }} />
</div>
</td>
<td>
<div className="input-group input-group-xs">
<NumericTextBox value={p.column == undefined ? null : p.column} onChange={n => { p!.column = n == null ? undefined : n; this.props.onChange(); }}
validateKey={ValueLine.isNumber} formControlClass="form-control form-control-xs" htmlAttributes={{ placeholder: SearchMessage.Column.niceToString(), style: { width: "30px" } }} />
<NumericTextBox value={p.row == undefined ? null : p.row} onChange={n => { p!.row = n == null ? undefined : n; this.props.onChange(); }}
validateKey={ValueLine.isNumber} formControlClass="form-control form-control-xs" htmlAttributes={{ placeholder: SearchMessage.Row.niceToString(), style: { width: "30px" } }} />
{this.numericTextBox(Binding.create(p, _ => _.column), SearchMessage.Column.niceToString())}
{this.numericTextBox(Binding.create(p, _ => _.row), SearchMessage.Row.niceToString())}
</div>
</td>
<td colSpan={2}>
Expand All @@ -522,9 +521,21 @@ export class PinnedFilterEditor extends React.Component<PinnedFilterEditorProps>
);
}

numericTextBox(binding: Binding<number | undefined>, title: string) {

var val = binding.getValue();
if (this.props.readonly)
return <span className="numeric form-control form-control-xs" style={{ width: "30px" }}>{val}</span>;

return (
<NumericTextBox value={val == undefined ? null : val} onChange={n => { binding.setValue(n == null ? undefined : n); this.props.onChange(); }}
validateKey={ValueLine.isNumber} formControlClass="form-control form-control-xs" htmlAttributes={{ placeholder: title, style: { width: "30px" } }} />
);
}

renderButton(binding: Binding<boolean | undefined>, label: string, title: string) {
return (
<button type="button" className={classes("btn btn-light", binding.getValue() && "active")}
<button type="button" className={classes("btn btn-light", binding.getValue() && "active")} disabled={this.props.readonly}
onClick={e => { binding.setValue(!binding.getValue()); this.props.onChange(); }}
title={TitleManager.useTitle ? title : undefined}>
{label}
Expand All @@ -533,24 +544,28 @@ export class PinnedFilterEditor extends React.Component<PinnedFilterEditorProps>
}
}

export function createFilterValueControl(ctx: TypeContext<any>, token: QueryToken, handleValueChange: () => void, labelText?: string): React.ReactElement<any> {
export function createFilterValueControl(ctx: TypeContext<any>, token: QueryToken, handleValueChange: () => void, labelText?: string, forceNullable?: boolean): React.ReactElement<any> {

var tokenType = token.type;
if (forceNullable)
tokenType = { ...tokenType, isNotNullable: false };

switch (token.filterType) {
case "Lite":
if (token.type.name == IsByAll || getTypeInfos(token.type).some(ti => !ti.isLowPopulation))
return <EntityLine ctx={ctx} type={token.type} create={false} onChange={handleValueChange} labelText={labelText} />;
if (tokenType.name == IsByAll || getTypeInfos(tokenType).some(ti => !ti.isLowPopulation))
return <EntityLine ctx={ctx} type={tokenType} create={false} onChange={handleValueChange} labelText={labelText} />;
else
return <EntityCombo ctx={ctx} type={token.type} create={false} onChange={handleValueChange} labelText={labelText} />
return <EntityCombo ctx={ctx} type={tokenType} create={false} onChange={handleValueChange} labelText={labelText} />
case "Embedded":
return <EntityLine ctx={ctx} type={token.type} create={false} autocomplete={null} onChange={handleValueChange} labelText={labelText} />;
return <EntityLine ctx={ctx} type={tokenType} create={false} autocomplete={null} onChange={handleValueChange} labelText={labelText} />;
case "Enum":
const ti = getTypeInfos(token.type).single();
const ti = getTypeInfos(tokenType).single();
if (!ti)
throw new Error(`EnumType ${token.type.name} not found`);
throw new Error(`EnumType ${tokenType.name} not found`);
const members = Dic.getValues(ti.members).filter(a => !a.isIgnoredEnum);
return <ValueLine ctx={ctx} type={token.type} formatText={token.format} unitText={token.unit} comboBoxItems={members} onChange={handleValueChange} labelText={labelText} />;
return <ValueLine ctx={ctx} type={tokenType} formatText={token.format} unitText={token.unit} comboBoxItems={members} onChange={handleValueChange} labelText={labelText} />;
default:
return <ValueLine ctx={ctx} type={token.type} formatText={token.format} unitText={token.unit} onChange={handleValueChange} labelText={labelText} />;
return <ValueLine ctx={ctx} type={tokenType} formatText={token.format} unitText={token.unit} onChange={handleValueChange} labelText={labelText} />;
}
}

Expand Down
2 changes: 1 addition & 1 deletion Signum.React/Scripts/SearchControl/PinnedFilterBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default class PinnedFilterBuilder extends React.Component<PinnedFilterBui
</FormGroup>
);

return createFilterValueControl(ctx, f.token!, () => this.handleValueChange(f), labelText);
return createFilterValueControl(ctx, f.token!, () => this.handleValueChange(f), labelText, f.pinned!.disableOnNull);
}

timeoutWriteText?: number | null;
Expand Down
2 changes: 1 addition & 1 deletion Signum.React/Scripts/TypeContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ export interface EntityFrame {
frameComponent: React.Component<any, any>;
entityComponent: React.Component<any, any> | null | undefined;
pack: EntityPack<ModifiableEntity> | undefined;
onReload: (pack?: EntityPack<ModifiableEntity>) => void;
onReload: (pack?: EntityPack<ModifiableEntity>, reloadComponent?: boolean) => void;
setError: (modelState: ModelState, initialPrefix?: string) => void;
revalidate: () => void;
onClose: (ok?: boolean) => void;
Expand Down

0 comments on commit 9dfe0be

Please sign in to comment.