I implemented devextreme to my react project.I'm using file manager system and I'm using devexpress for create system provider with my asp.net project.
I have an issue.
When i try to upload any file I'm getting and error.Download,move,copy is working very well.But i cant upload any file.
File uploaded succesfully my temp folder but then doesnt move to my real path.How can i fix this.Devexpress version 20.1
public object FileSystem(long id, FileSystemCommand command, string arguments, HttpRequest Request)
{
var path = Path.Combine(HostingEnvironment.ContentRootPath, "../files/Images/", id.ToString());
var config = new FileSystemConfiguration
{
Request = Request,
FileSystemProvider = new PhysicalFileSystemProvider(
path,
(fileSystemItem, clientItem) =>
{
if (!clientItem.IsDirectory)
clientItem.CustomFields["url"] = GetFileItemUrl(fileSystemItem, Request);
}
),
//uncomment the code below to enable file/folder management
AllowCopy = true,
AllowCreate = true,
AllowMove = true,
AllowDelete = true,
AllowRename = true,
AllowUpload = true,
AllowDownload = true,
AllowedFileExtensions = new[] { ".txt", ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".png", ".jpg", ".jpeg", ".gif", ".csv" }
};
var processor = new FileSystemCommandProcessor(config);
var result = processor.Execute(command, arguments);
return result.GetClientCommandResult();
}
Here is the front end code
import React from "react";
import FileManager, { Permissions } from "devextreme-react/file-manager";
import RemoteFileSystemProvider from "devextreme/file_management/remote_provider";
import { Popup } from "devextreme-react/popup";
let remoteProvider = new RemoteFileSystemProvider({
endpointUrl: "https://myapiurl.com.tr/api/FileManager/FileSystem/121",
});
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
currentPath: "Widescreen",
popupVisible: false,
imageItemToDisplay: {},
remoteProvider: new RemoteFileSystemProvider({
endpointUrl: "https://myapiurl.com.tr/api/FileManager/FileSystem/121",
}),
};
this.displayImagePopup = this.displayImagePopup.bind(this);
this.hideImagePopup = this.hideImagePopup.bind(this);
this.onCurrentDirectoryChanged = this.onCurrentDirectoryChanged.bind(this);
}
displayImagePopup(e) {
this.setState({
popupVisible: true,
imageItemToDisplay: {
name: e.file.name,
url: e.file.dataItem.url,
},
});
}
hideImagePopup() {
this.setState({
popupVisible: false,
});
}
onCurrentDirectoryChanged(e) {
this.setState({
currentPath: e.component.option("currentPath"),
});
}
render() {
console.log(remoteProvider);
return (
<>
{this.props.investment ? (
<div>
<FileManager
currentPath={this.state.currentPath}
fileSystemProvider={remoteProvider}
onSelectedFileOpened={this.displayImagePopup}
onCurrentDirectoryChanged={this.onCurrentDirectoryChanged}
>
<Permissions
create={true}
copy={true}
move={true}
delete={true}
rename={true}
upload={true}
download={true}
></Permissions>
</FileManager>
<Popup
maxHeight={600}
closeOnOutsideClick={true}
title={this.state.imageItemToDisplay.name}
visible={this.state.popupVisible}
onHiding={this.hideImagePopup}
className="photo-popup-content"
>
<img src={this.state.imageItemToDisplay.url} className="photo-popup-image" />
</Popup>
</div>
) : (
""
)}
</>
);
}
}
export default App;
We had the same issue lately, if I'm not mistaken, it was related to a mismatch between some DLLs versions of the project. The client-side version must match the FileSystemCommandeProcessor version. The DevExtreme team seems to have changed some property name which cause this issue.
Related
I wish to display a mail icon with a counter
With my gnome-shell extension I get an error:
I don't know what the error means.
Keep in mind I do not have much knowledge about gnome..
Syntax error : unexpected token : identifier
const INDICATOR_ICON = 'mail-unread-symbolic';
const PanelMenu = imports.ui.panelMenu;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
class Extension extends PanelMenu.Button {
_init() {
super._init(0.0, null, false);
this._icon = new St.Icon({
icon_name: INDICATOR_ICON,
style_class: 'system-status-icon'});
this._iconBin = new St.Bin({ child: this._icon, x_fill: false, y_fill: false });
this._counterLabel = new St.Label({ text: "0",
x_align: Clutter.ActorAlign.CENTER,
x_expand: true,
y_align: Clutter.ActorAlign.CENTER,
y_expand: true });
this._counterBin = new St.Bin({ style_class: 'mailnag-counter',
child: this._counterLabel,
layout_manager: new Clutter.BinLayout() });
this.add_actor(this._iconBin);
this.add_actor(this._counterBin);
}
}
function enable() {
return New Extension();
}
function disable() {
}
I'm working on creating a server-side extension in JupyterLab and have been searching for quite a while for a way to get the currently active notebook name inside my index.ts file. I found this existing extension that gets the currently active tab name with ILabShell and sets the browser tab to have the same name. In my case I'll be triggering the process with a button on the notebook toolbar so the active tab will always be a notebook. However, when I try to use the code in the activate section of my extension, I get TypeError: labShell.currentChanged is undefined where labShell is an instance of ILabShell. That extension doesn't support JupyterLab 3.0+ so I believe that's part of the problem. However, currentChanged for ILabShell is clearly defined here. What if anything can I change to make it work? Is there another way to accomplish what I'm trying to do? I'm aware of things like this to get the notebook name inside the notebook but that's not quite what I'm trying to do.
Windows 10,
Node v14.17.0,
npm 6.14.13,
jlpm 1.21.1,
jupyter lab 3.0.14
I'm using this example server extension as a template: https://github.com/jupyterlab/extension-examples/tree/master/server-extension
index.ts file from the existing extension to get the current tab name:
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '#jupyterlab/application';
import { Title, Widget } from '#lumino/widgets';
/**
* Initialization data for the jupyterlab-active-as-tab-name extension.
*/
const extension: JupyterFrontEndPlugin<void> = {
id: 'jupyterlab-active-as-tab-name',
autoStart: true,
requires: [ILabShell],
activate: (app: JupyterFrontEnd, labShell: ILabShell) => {
const onTitleChanged = (title: Title<Widget>) => {
console.log('the JupyterLab main application:', title);
document.title = title.label;
};
// Keep the session object on the status item up-to-date.
labShell.currentChanged.connect((_, change) => {
const { oldValue, newValue } = change;
// Clean up after the old value if it exists,
// listen for changes to the title of the activity
if (oldValue) {
oldValue.title.changed.disconnect(onTitleChanged);
}
if (newValue) {
newValue.title.changed.connect(onTitleChanged);
}
});
}
};
export default extension;
My index.ts file:
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '#jupyterlab/application';
import { ICommandPalette } from '#jupyterlab/apputils';
import { ILauncher } from '#jupyterlab/launcher';
import { requestAPI } from './handler';
import { ToolbarButton } from '#jupyterlab/apputils';
import { DocumentRegistry } from '#jupyterlab/docregistry';
import { INotebookModel, NotebookPanel } from '#jupyterlab/notebook';
import { IDisposable } from '#lumino/disposable';
import { Title, Widget } from '#lumino/widgets';
export class ButtonExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
constructor(app: JupyterFrontEnd) {
this.app = app;
}
readonly app: JupyterFrontEnd
createNew(panel: NotebookPanel, context: DocumentRegistry.IContext<INotebookModel>): IDisposable {
// dummy json data to test post requests
const data2 = {"test message" : "message"}
const options = {
method: 'POST',
body: JSON.stringify(data2),
headers: {'Content-Type': 'application/json'
}
};
// Create the toolbar button
let mybutton = new ToolbarButton({
label: 'Measure Energy Usage',
onClick: async () => {
// POST request to Jupyter server
const dataToSend = { file: 'nbtest.ipynb' };
try {
const reply = await requestAPI<any>('hello', {
body: JSON.stringify(dataToSend),
method: 'POST'
});
console.log(reply);
} catch (reason) {
console.error(
`Error on POST /jlab-ext-example/hello ${dataToSend}.\n${reason}`
);
}
// sample POST request to svr.js
fetch('http://localhost:9898/api', options);
}
});
// Add the toolbar button to the notebook toolbar
panel.toolbar.insertItem(10, 'MeasureEnergyUsage', mybutton);
console.log("MeasEnerUsage activated");
// The ToolbarButton class implements `IDisposable`, so the
// button *is* the extension for the purposes of this method.
return mybutton;
}
}
/**
* Initialization data for the server-extension-example extension.
*/
const extension: JupyterFrontEndPlugin<void> = {
id: 'server-extension-example',
autoStart: true,
optional: [ILauncher],
requires: [ICommandPalette, ILabShell],
activate: async (
app: JupyterFrontEnd,
palette: ICommandPalette,
launcher: ILauncher | null,
labShell: ILabShell
) => {
console.log('JupyterLab extension server-extension-example is activated!');
const your_button = new ButtonExtension(app);
app.docRegistry.addWidgetExtension('Notebook', your_button);
// sample GET request to jupyter server
try {
const data = await requestAPI<any>('hello');
console.log(data);
} catch (reason) {
console.error(`Error on GET /jlab-ext-example/hello.\n${reason}`);
}
// get name of active tab
const onTitleChanged = (title: Title<Widget>) => {
console.log('the JupyterLab main application:', title);
document.title = title.label;
};
// Keep the session object on the status item up-to-date.
labShell.currentChanged.connect((_, change) => {
const { oldValue, newValue } = change;
// Clean up after the old value if it exists,
// listen for changes to the title of the activity
if (oldValue) {
oldValue.title.changed.disconnect(onTitleChanged);
}
if (newValue) {
newValue.title.changed.connect(onTitleChanged);
}
});
}
};
export default extension;
There are two ways to fix it and one way to improve it. I recommend using (2) and (3).
Your order of arguments in activate is wrong. There is no magic matching of argument types to signature function; instead arguments are passed in the order given in requires and then optional. This means that you will receive:
...[JupyterFrontEnd, ICommandPalette, ILabShell, ILauncher]
but what you are expecting is:
...[JupyterFrontEnd, ICommandPalette, ILauncher, ILabShell]
In other words, optionals are always at the end. There is no static type check so this is a common source of mistakes - just make sure you double check the order next time (or debug/console.log to see what you are getting).
Actually, don't require ILabShell as a token. Use the ILabShell that comes in app.shell instead. This way your extension will be also compatible with other frontends built using JupyterLab components.
shell = app.shell as ILabShell
(optional improvement) install RetroLab as a development-only requirement and use import type (this way it is not a runtime requirement) to ensure compatibility with RetroLab:
import type { IRetroShell } from '#retrolab/application';
// ... and then in `activate()`:
shell = app.shell as ILabShell | IRetroShell
to be clear: not doing so would not make your extension incompatible; what it does is ensures you do not make it incompatible by depending on lab-specific behaviour of the ILabShell in the future.
So in total it would look like:
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '#jupyterlab/application';
import type { IRetroShell } from '#retrolab/application';
// ...
const extension: JupyterFrontEndPlugin<void> = {
id: 'server-extension-example',
autoStart: true,
optional: [ILauncher],
requires: [ICommandPalette],
activate: async (
app: JupyterFrontEnd,
palette: ICommandPalette,
launcher: ILauncher | null
) => {
let shell = app.shell as ILabShell | IRetroShell ;
shell.currentChanged.connect((_, change) => {
console.log(change);
// ...
});
}
};
export default extension;
audioData: undefined,
errorDetails: "Unable to contact server. StatusCode: 500,
ErrorDetails: "Unable to contact server. StatusCode: 500, undefin…external_ocsp_ocsp.Agent is not a constructor",
//code
synthesizeSpeech() {
let that = this;
const speechConfig = SpeechConfig.fromSubscription(
"********",
"********"
);
speechConfig.speechSynthesisLanguage = "zh-CN";
const synthesizer = new SpeechSynthesizer(speechConfig);
var soundContext = undefined;
try {
var AudioContext = window.AudioContext ||window.webkitAudioContext || false;
if(AudioContext){
soundContext = new AudioContext();
}
} catch (err) {
console.log(err)
}
synthesizer.speakTextAsync(
"你好你好你好你好你好你好你好.",
result => {
console.log(result)
if(result.audioData && soundContext){
var source = soundContext.createBufferSource();
soundContext.decodeAudioData(result.audioData,function(newBuffer){
source.buffer = newBuffer;
source.connect(soundContext.destination);
source.start(0);
})
}
synthesizer.close();
},
error => {
console.log(error);
synthesizer.close();
}
);
},
This is fixed in Microsoft Azure Cognitive Services Speech SDK for JavaScript v1.12, which will be released recently. You can download the compiled js file after the release or you can compile it from the master of the sdk repo.
upload image using file transfer in ionic 3 works fine on android,
but give me error on iOS when try it in simulator ..
* this is the error:
My Ionic Code:
chooseImageFromGallery()
{
this.type="0"
const options: CameraOptions = {
quality: 60,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
saveToPhotoAlbum:true,
sourceType:0
}
this.camera.getPicture(options)
.then((imageData) => {
if (this.platform.is('ios'))
{
this.base64Image = imageData;
}
else
{
this.base64Image = imageData;
}
this.uploadimage(); // this function to upload img to server
},
(err) => {
}).then((path)=>{
})
}
uploadimage(){
this.photoSrc="";
this.translate.get("uploading Image...").subscribe(
value => {
this.sucesss=false
const fileTransfer: FileTransferObject = this.transfer.create();
let options: FileUploadOptions = {
fileKey: "file",
fileName:'test',
chunkedMode:false,
mimeType:"image/jpeg",
headers:{
Connection:"close"
},
httpMethod: "POST",
}
//------------ android ------------//
this.base64Image =this.base64Image
//------------ ios ------------//
//this.base64Image =this.base64Image.substring(28)
fileTransfer.upload(this.base64Image,encodeURI('mydomain/api/Product/upload'), options)
.then((data:any) => {
alert("upload success ")
}, (err) => {
this.translate.get( "error in upload Data").subscribe(
value => {
this.service.presentToast(value,2000)
}
)
})
})
}
using asp.net api2 .. My server Code :
[HttpPost]
[Route("upload")]
[AllowAnonymous]
public HttpResponseMessage uploadImage()
{
var request = HttpContext.Current.Request;
if (Request.Content.IsMimeMultipartContent())
{
foreach (string file in request.Files)
{
var postedFile = request.Files[file];
if (postedFile != null && postedFile.ContentLength > 0)
{
string root = HttpContext.Current.Server.MapPath("~/ServerImg");
root = root + "/" + postedFile.FileName;
postedFile.SaveAs(root);
//Save post to DB
return Request.CreateResponse(HttpStatusCode.Found, new
{
error = false,
status = "created",
path = root
});
}
else
{
return Request.CreateResponse(HttpStatusCode.NotFound, new
{
error = true
});
}
// var title = request.Params["title"];
}
// }
return null;
}
else
{
return Request.CreateResponse(HttpStatusCode.Forbidden, new
{
error = true
});
}
}
I spend more than 4 days.. but nothing is work for me ..
And this code works fine on Android but not iOS I don't know what's the wrong, I tried real iPhone and Xcode simulator and not worked
always upload error {"code":3... "http_status":500,..
Can anyone Help me please...
I'm using aurelia-validate and my validation works fine if I use variables, but I need it to validate properties of an object rather than a variable:
Here's what works:
import {Validation} from 'aurelia-validation';
import {ensure} from 'aurelia-validation';
import {ItemService} from './service';
export class EditItem {
static inject() {
return [Validation, ItemService];
}
#ensure(function(it){
it.isNotEmpty()
.hasLengthBetween(3,10);
})
name = '';
#ensure(function(it){
it.isNotEmpty()
.hasMinLength(10)
.matches(/^https?:\/\/.{3,}$/) //looks like a url
.matches(/^\S*$/); //no spaces
})
url = '';
constructor(validation, service) {
this.validation = validation.on(this);
this.service = service;
}
activate(params){
return this.service.getItem(params.id).then(res => {
console.log(res);
this.name = res.content.name; //populate
this.url = res.content.url;
});
}
update() {
this.validation.validate().then(
() => {
var data = {
name: this.name,
url: this.url
};
this.service.updateItem(data).then(res => {
this.message = "Thank you!";
})
}
);
}
}
Here's what I'm trying to do (but doesn't work)...also I'm not sure if it's better to keep the properties on the class or have a property called this.item which contains the properties (this is the typical angular way):
import {Validation} from 'aurelia-validation';
import {ensure} from 'aurelia-validation';
import {ItemService} from './service';
export class EditItem {
static inject() {
return [Validation, ItemService];
}
#ensure(function(it){
it.isNotEmpty()
.hasLengthBetween(3,10);
})
this.item.name; //no assignment here should happen
#ensure(function(it){
it.isNotEmpty()
.hasMinLength(10)
.matches(/^https?:\/\/.{3,}$/) //looks like a url
.matches(/^\S*$/); //no spaces
})
this.item.url; //no assignment?
constructor(validation, service) {
this.validation = validation.on(this);
this.service = service;
this.item = null;
}
activate(params){
return this.service.getItem(params.id).then(res => {
console.log(res);
this.item = res.content; //populate with object from api call
});
}
update() {
this.validation.validate().then(
() => {
var data = {
name: this.item.name,
url: this.item.url
};
this.service.updateItem(data).then(res => {
this.message = "Thank you!";
})
}
);
}
}
Can someone give me some guidance here on how to use a validator against an existing object (for an edit page)?
The validation works in all kinds of situations, but using the #ensure decorator can only be used to declare your rules on simple properties (like you found out).
Hence...
Option a: replace the ensure decorator with the fluent API 'ensure' method, this supports 'nested' or 'complex' binding paths such as:
import {Validation} from 'aurelia-validation';
import {ItemService} from './service';
export class EditItem {
static inject() {
return [Validation, ItemService];
}
constructor(validation, service) {
this.validation = validation.on(this)
.ensure('item.url')
.isNotEmpty()
.hasMinLength(10)
.matches(/^https?:\/\/.{3,}$/) //looks like a url
.matches(/^\S*$/)
.ensure('item.name')
.isNotEmpty()
.hasLengthBetween(3,10);
this.service = service;
this.item = null;
}
activate(params){
return this.service.getItem(params.id).then(res => {
console.log(res);
this.item = res.content; //populate with object from api call
});
}
update() {
this.validation.validate().then(
() => {
var data = {
name: this.item.name,
url: this.item.url
};
this.service.updateItem(data).then(res => {
this.message = "Thank you!";
})
}
);
}
}
Note: you can set up your validation even before item is set. Cool, no?
Option b: Since the validation rules are specific to the item, you could move your validation rules inside your item class using the #ensure decorator inside that class instead.
You can then set up validation in your VM after you've retrieved the item: this.validation = validation.on(this.item); or, your service can set up the validation when it returns your item to your VM and make it an intrinsic part of the model: item.validation = validation.on(item);
Option a is easiest and seems to match your experience. Option b is more maintainable, as the validation rules for your model will live on the model, not on the view-model. However if you go with option b, you might have to adjust your HTML a bit to make sure validation hints appear.
Use the .on method of the validator to apply your rules to object properties.
The example below is called after I retrieve an object named stock, it validates that the quantity is not empty and is numeric only. Hope this helps...
let stock = {
name: 'some name'
minimumQuantity: '1'
};
applyRules() {
ValidationRules
.ensure((m: EditStock) => m.minimumQuantity)
.displayName("Minimum Quantity")
.required()
.withMessage(`\${$displayName} cannot be blank.`)
.matches( /^[0-9]*$/)
.withMessage(`\${$displayName} must be numeric only.`)
.on(this.stock);
}