Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
olmobrutall committed May 14, 2020
2 parents 25e048c + 6ae63ae commit 31c91da
Show file tree
Hide file tree
Showing 15 changed files with 58 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ protected virtual bool CompareSubquery(SubqueryExpression a, SubqueryExpression
{
if (a.NodeType != b.NodeType)
return false;
switch ((DbExpressionType)a.NodeType)
switch (a.DbNodeType)
{
case DbExpressionType.Scalar:
return CompareScalar((ScalarExpression)a, (ScalarExpression)b);
Expand Down
2 changes: 1 addition & 1 deletion Signum.Entities/EnumMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public enum EngineMessage
ThereAre0ThatReferThisEntity,
[Description("There are records in '{0}' referring to this table by column '{1}'")]
ThereAreRecordsIn0PointingToThisTableByColumn1,
[Description("Unautorized access to {0} because {1}")]
[Description("Unauthorized access to {0} because {1}")]
UnauthorizedAccessTo0Because1,
[Description("There's already a {0} with {1} equals to '{2}'")]
TheresAlreadyA0With1EqualsTo2_G
Expand Down
7 changes: 6 additions & 1 deletion Signum.Entities/Translations/Signum.Entities.de.xml
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@
<Member Name="ImpossibleToSaveIntegrityCheckFailed" Description="Unmöglich zu speichern, Integritätsprüfung fehlgeschlagen:&#xD;&#xA;&#xD;&#xA;" />
<Member Name="Loading0" Description="{0} läd gerade..." />
<Member Name="LoseChanges" Description="Es gibt Änderungen, die noch nicht gespeichert wurden. &#xD;&#xA;Sollen diese Änderungen verloren gehen?" />
<Member Name="Main" Description="Haupt" />
<Member Name="Message" Description="Nachricht" />
<Member Name="New0_G" Description="Neu[m:er|f:e|n:es] {0}" />
<Member Name="NoDirectErrors" Description="Keine direkten Fehler" />
Expand Down Expand Up @@ -329,6 +330,10 @@
<Member Name="SecondStart" Description="Start Sekunde" />
<Member Name="Step0" Description="Schritt {0}" />
<Member Name="Text" Description="Text" />
<Member Name="TotalDays" Description="Tage insgesamt" />
<Member Name="TotalHours" Description="Stunden insgesamt" />
<Member Name="TotalMilliseconds" Description="Milisekunden insgesamt" />
<Member Name="TotalSeconds" Description="Sekunden insgesamt" />
<Member Name="WeekNumber" Description="Kalenderwoche" />
<Member Name="WeekStart" Description="Wochenstart" />
<Member Name="Year" Description="Jahr" />
Expand Down Expand Up @@ -522,4 +527,4 @@
<Type Name="VoidEnumMessage">
<Member Name="Instance" Description="-" />
</Type>
</Translations>
</Translations>
9 changes: 7 additions & 2 deletions Signum.React/Scripts/Components/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,17 @@ export default function TextArea(p: TextAreaProps) {
}, [innerRef, minHeight]);

return (
<textarea onInput={autoResize ? (e => handleResize(e.currentTarget)) : undefined} style={
<textarea {...props} onInput={e => {
if (p.autoResize)
handleResize(e.currentTarget);
if (p.onInput)
p.onInput(e);
}} style={
{
...(autoResize ? { display: "block", overflow: "hidden", resize: "none" } : {}),
...props.style
}
} {...props} ref={handleRef} />
} ref={handleRef} />
);
}

Expand Down
4 changes: 2 additions & 2 deletions Signum.React/Scripts/Finder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,13 @@ export function smartColumns(current: ColumnOptionParsed[], ideal: ColumnDescrip
else if (current.every((c, i) => i >= ideal.length || similar(c, ideal[i]))) {
return {
mode: "Add",
columns: current.slice(ideal.length).map(c => ({ token: c.token!.fullKey, displayName: c.displayName }) as ColumnOption)
columns: current.slice(ideal.length).map(c => ({ token: c.token!.fullKey, displayName: c.token!.niceName == c.displayName ? undefined : c.displayName }) as ColumnOption)
};
}

return {
mode: "Replace",
columns: current.map(c => ({ token: c.token!.fullKey, displayName: c.displayName }) as ColumnOption),
columns: current.map(c => ({ token: c.token!.fullKey, displayName: c.token!.niceName == c.displayName ? undefined : c.displayName }) as ColumnOption),
};
}

Expand Down
12 changes: 8 additions & 4 deletions Signum.React/Scripts/Frames/Notify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ interface NotifyOptions {
}

interface NotifyHandle {
notify(options: NotifyOptions) : void;
notifyTimeout(options: NotifyOptions, timeout?: number): void
notify(options: NotifyOptions): NotifyOptions;
notifyTimeout(options: NotifyOptions, timeout?: number): NotifyOptions
notifyPendingRequest(pending: number): void;
remove(options: NotifyOptions): void;
}

export default function Notify() {
Expand All @@ -39,12 +40,14 @@ export default function Notify() {
optionsStack.current.extract(a => a == options);
optionsStack.current.push(options);
forceUpdate();
return options;
}

function notifyTimeout(options: NotifyOptions, timeout: number = 2000) {
function notifyTimeout(options: NotifyOptions, timeout: number = 2000): NotifyOptions {
notify(options);

options.timeoutHandler = setTimeout(() => remove(options), timeout);
return options;
}

const loadingRef = React.useRef<NotifyOptions>({ text: JavascriptMessage.loading.niceToString(), type: "loading", priority: 0 });
Expand All @@ -69,7 +72,8 @@ export default function Notify() {
Notify.singleton = {
notify: notify,
notifyTimeout: notifyTimeout,
notifyPendingRequest: notifyPendingRequest
notifyPendingRequest: notifyPendingRequest,
remove: remove,
};

return () => Notify.singleton = undefined;
Expand Down
2 changes: 0 additions & 2 deletions Signum.React/Scripts/Globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -820,8 +820,6 @@ String.prototype.tryAfterLast = function (this: string, separator: string) {
String.prototype.etc = function (this: string, maxLength: number, etcString: string = "(…)") {
let str = this;

str = str.tryBefore("\n") || str;

if (str.length > maxLength)
str = str.substr(0, maxLength - etcString.length) + etcString;

Expand Down
3 changes: 2 additions & 1 deletion Signum.React/Scripts/Lines/AutoCompleteConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ export class FindOptionsAutocompleteConfig implements AutocompleteConfig<ResultR

var filters = [...fo.filterOptions ?? []];

if (fo.includeDefaultFilters ?? true) {
/*When overriden in Finder very often uses not seen columns (like Telephone) that are not seen in autocomplete, better to use false by default and you can opt-in by adding includeDefaultFilters if needed */
if (fo.includeDefaultFilters ?? false) {
var defaultFilters = Finder.getDefaultFilter(qd, qs);
if (defaultFilters)
filters = [...defaultFilters, ...filters];
Expand Down
3 changes: 3 additions & 0 deletions Signum.React/Scripts/Navigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,8 @@ export interface EntitySettingsOptions<T extends ModifiableEntity> {
onNavigateRoute?: (typeName: string, id: string | number) => string;
onNavigate?: (entityOrPack: Lite<Entity & T> | T | EntityPack<T>, navigateOptions?: NavigateOptions) => Promise<void>;
onView?: (entityOrPack: Lite<Entity & T> | T | EntityPack<T>, viewOptions?: ViewOptions) => Promise<T | undefined>;
onCreateNew?: (oldEntity: EntityPack<T>) => (Promise<EntityPack<T> | undefined>) | undefined; /*Save An New*/

namedViews?: NamedViewSettings<T>[];
}

Expand Down Expand Up @@ -853,6 +855,7 @@ export class EntitySettings<T extends ModifiableEntity> {
onNavigate?: (entityOrPack: Lite<Entity & T> | T | EntityPack<T>, navigateOptions?: NavigateOptions) => Promise<void>;
onView?: (entityOrPack: Lite<Entity & T> | T | EntityPack<T>, viewOptions?: ViewOptions) => Promise<T | undefined>;
onNavigateRoute?: (typeName: string, id: string | number, viewName?: string) => string;
onCreateNew?: (oldEntity: EntityPack<T>) => (Promise<EntityPack<T> | undefined>) | undefined; /*Save An New*/

namedViews?: { [viewName: string]: NamedViewSettings<T> };
overrideView(override: (replacer: ViewReplacer<T>) => void, viewName?: string) {
Expand Down
17 changes: 7 additions & 10 deletions Signum.React/Scripts/Operations/EntityOperations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,16 +124,13 @@ export function andNew<T extends Entity>(eoc: EntityOperationContext<T>, inDropd
eoc.onExecuteSuccess = pack => {
notifySuccess();

var createNew = eoc.frame.frameComponent.createNew;

if (createNew)
(createNew() ?? Promise.resolve(undefined))
.then(newPack => newPack && eoc.frame.onReload(newPack, true))
.done();
else
Constructor.constructPack(pack.entity.Type)
.then(newPack => newPack && eoc.frame.onReload(newPack, true))
.done();
var createNew = eoc.frame.frameComponent.createNew ??
Navigator.getSettings(pack.entity.Type)?.onCreateNew ??
(pack => Constructor.constructPack(pack.entity.Type));

(createNew(pack) ?? Promise.resolve(undefined))
.then(newPack => newPack && eoc.frame.onReload(newPack, true))
.done();
};
eoc.defaultClick();
}
Expand Down
7 changes: 5 additions & 2 deletions Signum.React/Scripts/SearchControl/EntityLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,19 @@ export default function EntityLink(p: EntityLinkProps) {
innerRef={p.innerRef as any}
to={Navigator.navigateRoute(lite)}
title={StyleContext.default.titleLabels ? p.title ?? getToString(lite) : undefined}
onClick={handleClick}
data-entity={liteKey(lite)}
{...(htmlAtts as React.HTMLAttributes<HTMLAnchorElement>)}>
{...(htmlAtts as React.HTMLAttributes<HTMLAnchorElement>)}
onClick={handleClick}
>
{children ?? lite.toStr}
</Link>
);

function handleClick(event: React.MouseEvent<any>) {

event.preventDefault();
p.onClick?.call(event.currentTarget, event);

const lite = p.lite;
const s = Navigator.getSettings(lite.EntityType)
const avoidPopup = s != undefined && s.avoidPopup;
Expand Down
6 changes: 3 additions & 3 deletions Signum.React/Scripts/SearchControl/SearchControlLoaded.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ export default class SearchControlLoaded extends React.Component<SearchControlLo
order: -5,
button: <button
className={classes("sf-query-button sf-filters-header btn", s.showFilters && "active", "btn-light")}
style={!s.showFilters && p.findOptions.filterOptions.length > 0 ? { border: "1px solid #b3b3b3" } : undefined}
style={!s.showFilters && p.findOptions.filterOptions.filter(a => !a.pinned).length > 0 ? { border: "1px solid #6c757d" } : undefined}
onClick={this.handleToggleFilters}
title={titleLabels ? s.showFilters ? JavascriptMessage.hideFilters.niceToString() : JavascriptMessage.showFilters.niceToString() : undefined}>
<FontAwesomeIcon icon="filter" />
Expand Down Expand Up @@ -872,9 +872,9 @@ export default class SearchControlLoaded extends React.Component<SearchControlLo
const cm = this.state.contextualMenu!;
const p = this.props;

var fo = this.state.resultFindOptions;
var fo = this.props.findOptions;
function isColumnFilterable(columnIndex: number) {
var token = fo?.columnOptions[columnIndex].token;
var token = fo.columnOptions[columnIndex].token;
return token && token.filterType != "Embedded" && token.filterType != undefined && token.format != "Password";
}

Expand Down
4 changes: 0 additions & 4 deletions Signum.React/Scripts/SearchControl/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ interface SearchPageProps extends RouteComponentProps<{ queryName: string }> {

}

interface SearchPageState {
findOptions: FindOptions;
}

function SearchPage(p: SearchPageProps) {

const fo = Finder.parseFindOptionsPath(p.match.params.queryName, QueryString.parse(p.location.search))
Expand Down
12 changes: 12 additions & 0 deletions Signum.React/Scripts/Services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface AjaxOptions {
url: string;
avoidNotifyPendingRequests?: boolean;
avoidThrowError?: boolean;
avoidRetry?: boolean;
avoidGraphExplorer?: boolean;
avoidAuthToken?: boolean;
avoidVersionCheck?: boolean;
Expand Down Expand Up @@ -103,6 +104,11 @@ export function wrapRequest(options: AjaxOptions, makeCall: () => Promise<Respon
addContextHeaders.forEach(f => f(options));
}

if (!options.avoidRetry) {
const call = makeCall;
makeCall = () => RetryFilter.retryFilter(call);
}

if (!options.avoidVersionCheck) {
const call = makeCall;
makeCall = () => VersionFilter.onVersionFilter(call);
Expand Down Expand Up @@ -132,6 +138,12 @@ export function wrapRequest(options: AjaxOptions, makeCall: () => Promise<Respon

}

export module RetryFilter {
export function retryFilter(makeCall: () => Promise<Response>): Promise<Response>{
return makeCall();
}
}

export module AuthTokenFilter {
export let addAuthToken: (options: AjaxOptions, makeCall: () => Promise<Response>) => Promise<Response>;
}
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 @@ -444,7 +444,7 @@ export interface EntityFrame {
tabs: EmbeddedWidget[] | undefined;
frameComponent: {
forceUpdate(): void,
createNew?(): (Promise<EntityPack<ModifiableEntity> | undefined>) | undefined
createNew?(oldEntity: EntityPack<ModifiableEntity>): (Promise<EntityPack<ModifiableEntity> | undefined>) | undefined
};
entityComponent: React.Component | null | undefined;
pack: EntityPack<ModifiableEntity>;
Expand Down

4 comments on commit 31c91da

@olmobrutall
Copy link
Collaborator Author

@olmobrutall olmobrutall commented on 31c91da May 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slimming Signum.React

The typical use case of Signum Framework is that of a Line-of-business application: power users using on a daily baisis an application hosted in the intranet or private cloud.

There are cases however where this application has a public-facing portal consumed by anonymous users.

A few months ago Signum Framework took the first step to improve this scenario by only providing type information for allowed types. This improves security and performance by delivering less metadata.

Today we do the second step: By splitting some javascript modules, moving things around and using React.lazy / React.Suspense we can save the anonymous user the loading of some signum hevyweight modules like Navigator, Finder, Operations, Constructor...

This, together with some webpack optimizations, can be a big difference for casual users / mobile phone users / google performance benchmarks.

File Size evolution

Before any optimization, vendor.js and main.js are about 7.8 Mb in development mode.
CaptureV0

After tihs Sigum.React changes, vendor.js and main.js are 6.1Mb, almost 1.8 Mb less!.
CaptureV1 Split

By configuring webpack to use production mode build, the numbers go down to 2.2 Mb! What an improvement! This will make debugging client-code in production harder but is totally worth it for public facing applications.
CaptureV2 Split Production

We can also reduce the size of vendor by 300kb by removing d3.js, probably not used in a public catalog.
CaptureV3 Split Production WithoutD3

Finally, we can move font-awesome to vendor.js. This doesn't make any difference in vendor.js + main.js size, but keeps our main.js clean and mean less tranasfer since main.js changes more often than vendor.js.
CaptureV4 Split Production WithoutD3 FontAwesome

What has changed:

In Framework

  • Some basic funtionality from Navigator.tsx has been extracted out to the new AppContext.tsx:
FIND: Navigator.currentUser
REPL: AppContext.currentUser

FIND: Navigator.history
REPL: AppContext.history

FIND: Navigator.toAbsoluteUrl
REPL: AppContext.toAbsoluteUrl
  • Some Navigator-specific hooks have been moved from Hooks.tsx to Navigator.tsx (useFetchInState, useFetchInStateWithReload, useFetchAndRemember,useFetchAll).
  • Some Finder-specific hooks have been moved from Hooks.tsx to Finder.tsx (useQuery, useInDB).
  • FunctionalAdapter has been moved from FrameModal.tsx to Modals.tsx

In Extensions

  • AuthClient has been splitted in AuthClient.tsx (login, logout, change password, etc...) and AuthAdminClient.tsx (for admins).

In Southwind

  • Main.tsx has been splitted in MainPublic.tsx (initial module for everybody) and MainAdmin.tsx, (async loaded only for admins)
  • Home.tsx tries async-loads DashboardClient
  • Layout.tsx async-loads RestClient and uses React.lazy for WorkflowDropdown and ToolbarRenderer
  • vendor.js removes d3 and includes fortawesome
  • package.js removes the internal scripts build:dll and build:webpack, renames build to build-development and creates a new build-production.
  • "Anonymous" user instead of no user at all will be used when PublicCatallog is selected.

Diff of southwind changes: https://github.com/signumsoftware/southwind/compare/8bd40e35607e5965ff21cd1cdb7eb9a30f551157..ef375d3f9e71ff9365be1484f0b9d3b549f8efcf

What's coming next?

In the next days you can expect an update to Typescript 3.9 (with faster builds!) and a new Pivot table chart, so be quick to update your code to get the new goodies :)

Enjoy :)

@antonioh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

@rezanos
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great improvements! Thanks :)

@MehdyKarimpour
Copy link
Contributor

@MehdyKarimpour MehdyKarimpour commented on 31c91da May 15, 2020 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.