We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

How To Implement JWT Token Send With Every FileManager Request

So after a few hours of trying to get the beforeSend event to work properly, I have given up. Could you provide an example of proper implementation?

Background: Angular 7 front end that communicates with a Asp.Net Core 2.1 Web Api. Security uses JWT token.

file-explorer.component.html

<ejs-filemanager id='default-filemanager' #filemanagerObj [ajaxSettings]='ajaxSettings' (beforeSend)="beforeSend($event)" allow-drag-and-drop="true"></ejs-filemanager>

file-explorer.component.ts

import { Component, OnInit } from '@angular/core';
import { environment } from '../../environments/environment';

const token = localStorage.getItem('token');

@Component({
selector: 'app-file-explorer',
templateUrl: './file-explorer.component.html',
styleUrls: ['./file-explorer.component.css']
})
export class FileExplorerComponent implements OnInit {
baseUrl = environment.apiUrl;
public hostUrl: string = this.baseUrl;
public ajaxSettings: object = {
url: this.hostUrl + 'AzureStorage/FileOperations',
getImageUrl: this.hostUrl + 'AzureStorage/GetImage',
uploadUrl: this.hostUrl + 'AzureStorage/Upload',
downloadUrl: this.hostUrl + 'AzureStorage/Download',
}

constructor() { }

ngOnInit() {
}

beforeSend(args: any){
args.setRequestHeader("Authorization","Bearer" + token);
}
}

How do I set the Authorization header properly in the beforeSend event?

Thanks in advance for your help.


26 Replies

CI Christopher Issac Sunder K Syncfusion Team April 29, 2019 09:30 AM UTC

Hi Jason, 

Greetings from Syncfusion support. 

Currently, the EJ2 File Manager does not have support to receive and modify the JWT tokens in the beforeSend event. We have logged this as a feature request from our end. We will provide support for this and include it in the weekly patch release on 3rd week of May, 2019. You can track the status of this feature through the following feedback portal link, 

We appreciate your patience until then. 

Thanks, 
Christo 



CI Christopher Issac Sunder K Syncfusion Team May 22, 2019 10:57 AM UTC

Hi Jason, 

Thanks for being patient. 

We have provided the support to receive and modify the JWT tokens in the ajax beforeSend event and have included this in our latest Syncfusion packages(version - 17.1.48). Please update the Syncfusion packages to the latest version(v17.1.48) to include this support.  

You can access the ajax beforeSend event in the beforeSend event of the File Manager and set authorization header there. Please check below code snippet, 
<ejs-filemanager id='overview' (beforeSend)="beforeSend($event)" [ajaxSettings]='ajaxSettings' [view]='view'> 
</ejs-filemanager> 
 
//File Manager's beforeSend event 
beforeSend(args: any){ 
    //Ajax beforeSend event 
    args.ajaxSettings.beforeSend = function (args) { 
        //Setting authorization header 
        args.httpRequest.setRequestHeader("Authorization", "Bearer-1233") 
    } 
} 

We have prepared a sample for your reference. Please find it below, 

Let us know if you have any concerns. 

Thanks, 
Christo 



JO Jason Osborne May 22, 2019 01:41 PM UTC

Christo,

Thank you for the update. I will test this later today.


CI Christopher Issac Sunder K Syncfusion Team May 23, 2019 10:07 AM UTC

Hi Jason, 

Thanks for the update. We will wait until we hear from you. 

Thanks,
Christo 



AB acid blue May 29, 2019 01:35 PM UTC

I have succesfully tested the FileManager with JWT with v17.1.48 but on the GetImage and Download calls don't send JWT token because the args.ajaxSettings.beforeSend function isn't called.

Is this a bug?


CI Christopher Issac Sunder K Syncfusion Team May 31, 2019 12:08 PM UTC

Hi Jason, 
 
We have processed the operations in File Manager using ajax except for GetImage, Download, and Upload operations. 
 
For GetImage, instead of Ajax, we have processed it using query string parameter and similarly, for download, we have used form element to process the operation. As these operations are not based on ajax requests, we have not provided the beforeSend event for them. 
 
However, we will further validate and check the feasibility of implementing ajax requests to process these operations and provide you the further details for this on 3rd June 2019. 
 
We appreciate your patience until then. 
 
Thanks,
Christo
 



AB Ashokkumar Balasubramanian Syncfusion Team June 4, 2019 04:55 AM UTC

Hi Jason, 
 
Thanks for your patience. 
 
We checked the feasibility for implementing this requirement, but as mentioned in our previous update since the GetImage is processed using query string parameter and download processed using form element. So, it is not possible to implement these operations using Ajax requests. However, as it is possible to implement the upload operation using ajax request, we will include support for this. 
 
Please let us know if you have any concerns. 
 
Regards, 
Ashokkumar B. 



AB Ashokkumar Balasubramanian Syncfusion Team October 8, 2019 04:26 PM UTC

Hi Jason,  
 
Query1 – Header for Upload and FileOperations. 
 
We have provided the support to receive and modify the JWT tokens in the ajax beforeSend event for upload and fileOperations. You can access the ajax beforeSend event in the beforeSend event of the File Manager and set authorization header. Refer the below code snippet to set the header for upload and fileOperations. 
 
 <ejs-filemanager   #filemanager id='overview' [ajaxSettings]='ajaxSettings'   (beforeSend)="beforeSend($event)" [view]='view'  (toolbarClick)='toolbarClick($event)' (menuClick)='menuClick($event)'> 
        </ejs-filemanager> 
 
  beforeSend(args: any) { 
    //Ajax beforeSend event 
    args.ajaxSettings.beforeSend = function (args) { 
      //Setting authorization header 
      args.httpRequest.setRequestHeader("Authorization", "Bearer-1233") 
    } 
  } 
 
 
 
Query 2 - Authorisation header in download request 
 
Currently, we have used the form option for download a file from the file manager. Here, you are unable to add the authorisation header. To achieve your requirement, we need to use the XHRHttpRequest to download the file from the server. Using the XHRHttpRequest approach for downloading, it will download the file into browser cache once before saving the file locally. This will slow down the download process, since double the time file will be downloaded also it utilizes more bandwidth. Due to that, we couldn’t include this support in component level. 
 
However, as a workaround, we have achieved your requirement by preventing the default file manager download operation and added the custom download using XHRHttpRequest. Please refer the below code example. 
 
[Controller] 
 
Route("Download")] 
        public IActionResult Download(string downloadInput) 
        { 
            // To expose content disposition header at client side. 
            Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition"); 
            FileManagerDirectoryContent args = JsonConvert.DeserializeObject<FileManagerDirectoryContent>(downloadInput); 
            return operation.Download(args.Path, args.Names); 
        } 
 
 
[TS] 
 
public toolbarClick(args: any): void { 
    if (args.item.id === this.filemanagerObj.element.id + '_tb_download') { 
      //Preventing default download using toolbar 
      args.cancel = true; 
      this.customDownload([]); 
    } 
  } 
  public menuClick(args: any) { 
    if (args.item.id === this.filemanagerObj.element.id + '_cm_download') { 
      //Preventing default download using context menu 
      args.cancel = true; 
      this.customDownload(args.fileDetails); 
    } 
  } 
  public customDownload(files) { 
    var flag = (this.filemanagerObj.selectedItems.length !== 0); 
    if ((files.length !== 0) || flag) { 
      //Creating data for the controller 
   ..... 
   ..... 
      let fdata: FormData = new FormData(); 
      fdata.append('downloadInput', JSON.stringify(data)); 
      //Custom Header Added to XHR 
      xhr.setRequestHeader('Custom-Header', 'Syncfusion'); 
      xhr.send(fdata); 
    } 
  } 
 
 
For your reference, we have prepared file operation services based on your requirement in below-mentioned link:  
 
 
a.     Extract the downloaded file operation services. 
b.     Run the service and copy the hosted URL. 
c.      Enter the hosted URL in below sample. 
 
 
Query 3 – Header request for GetImage 
 
We are using the query string parameter to load the images in file manager. So, we are unable to add the custom header in GetImage request. If we are going to use ajax (asynchronous request) then, each image creates individual request and its having certain time delay based in image size, network bandwidth and server respond time. So, we are unable to update the headers to the corresponding image tag value. Also, in search operations the images will be listed from different folders for each keypress, this will creates more request and increases the complexity to update the image tag values. 
  
Regarding this, we will never include the support for adding the authentication headers to the GetImage action 
 
 
Query 4 – Add custom parameter  
 
Yes, it is possible to add the custom parameter in file manager operations. You can add the custom parameters using beforeSend() event. Refer the below code snippet to add the custom parameters. 
  beforeSend(args: any) { 
      var data = JSON.parse(args.ajaxSettings.data); 
     // Add custom parameter column 
      data["column"] = "value"; 
     // Add custom parameter in ajax settings 
      args.ajaxSettings.data = JSON.stringify(data); 
    //Ajax beforeSend event 
      args.ajaxSettings.beforeSend = function (args) { 
      //Setting authorization header 
      args.httpRequest.setRequestHeader("Authorization", "Bearer-1233") 
    } 
  } 
 
 
You can add the custom class in controller part and use the class in fileOperations. 
 
  public class FileManagerDirectoryContent1 
    { 
        public string Action { get; set; } 
        public string Path { get; set; } 
        public FileManagerDirectoryContent TargetData { get; set; } 
        public AccessPermission Permission { get; set; } 
        public string column { get; set; } 
    } 
 
Refer the below screenshot, we can get the custom parameter value in event argument. 
 
 
 
 
Please let us know if you have any concerns. 
 
Regards, 
Ashokkumar B. 



AB Ashokkumar Balasubramanian Syncfusion Team October 10, 2019 12:11 PM UTC

Hi Jason,   
 
We are glad to hear that the provided solution worked for you. Please let us know, if you need any further assistance. 
 
Regards, 
Ashokkumar B. 



MV Michiel Van Der Lee March 27, 2020 04:22 PM UTC

Regarding:
  beforeSend(args: any) { 
      var data = JSON.parse(args.ajaxSettings.data); 
     // Add custom parameter column 
      data["column"] = "value"; 
     // Add custom parameter in ajax settings 
      args.ajaxSettings.data = JSON.stringify(data); 
    //Ajax beforeSend event 
      args.ajaxSettings.beforeSend = function (args) { 
      //Setting authorization header 
      args.httpRequest.setRequestHeader("Authorization", "Bearer-1233") 
    } 
  } 
 

This doesn't work for us. This assumes a static token. What happens if the token is expired?

beforeSend should be of an asynchronous nature, preferably a Promise. So that I can check if a token is expired, get a new token if needed, and then set the Authorization header.


SP Sowmiya Padmanaban Syncfusion Team March 30, 2020 10:36 AM UTC

Hi Michiel,  
 
We have checked your reported query. We would like to let you know that it is not a static token. In our previously attached sample, we have used that token for explaining the use case scenario. You can set the token based on your requirement. 
 
beforeSend(args: any) {  
    //Ajax beforeSend event  
      args.ajaxSettings.beforeSend = function (args) {  
      //Setting authorization header  
      // It is not a static token.  
      args.httpRequest.setRequestHeader("Authorization", "Bearer-1233")  
    }  
  }  
 
 
If we misunderstand your requirement. Can you please share the additional details regarding your requirement. It will helpful for us to resolve your issue at earlier. 
·       Exact requirement. 
·       Video footage or code snippet for your requirement. 
 
Please let us know, if you have any concerns. 
 
Regards,  
Sowmiya.P 



UN Unknown Syncfusion Team June 19, 2020 09:08 AM UTC

Adding the bearer token in beforeSend works quite well, however, not for downloads and uploads, as I can see in this thread.

As far as I can read, I need to make my own implementation of starting a download. That means I no longer receive:

public FileStreamResult Download(string path, string[] names, params FileManagerDirectoryContent[] data)

but instead have to create my own request. I have done that in TypeScript like this:

public customDownload(files) {
const items = files.map((item: FileDetail) => {
return {
name: item.name,
isFile: item.isFile
};
});

the files argument is simply args.fileDetails from the menuClick() and toolbarClick(). customDownload then does the XMLHttpRequest like written before in this post. Nothing new there.

This works perfectly if my path is / aka root, but if I change path, I never send the actual path to the file provider. I cannot seem to find a way of sending in the current path. I have tried:

<ejs-filemanager id='default-filemanager' ....... [path]="path"></ejs-filemanager>

but path never gets updated, when I traverse down directories. It's always / in the code:

public path = "/";

So I have two questions:
  1. Is this custom download posted by Ashokkumar still the prefered way to add a bearer token to every request?
  2. If it is, how do I send the path to my file provider? If I console.log(args) from menuClick() and toolbarClick() it does not contain the path anywhere.
Thanks


UN Unknown Syncfusion Team June 19, 2020 09:26 AM UTC

Okay, just saw I could get the path from:

this.filemanagerObj.path

So that is good. However, still wondering if there is a better way than the answer already posted here, where we have to create our own XMLHttpRequest


SA Shameer Ali Baig Sulaiman Ali Baig Syncfusion Team June 22, 2020 06:23 AM UTC

Hi Morten ,  
 
Greetings from Syncfusion support. 
 
Query 1- Path of FileManager component. 
 
Yes. By setting the path of FileManager component, navigation takes place from the current folder to the specified path. 
 
Refer the below link to know more about the path property. 
 
 
Query2 – Custom download. 
 
In FileManager component, we have provided beforeDownload method. By setting the args.cancel as true in this method, we can prevent the default download action of FileManager component.  And then you can create your custom download within this method. 
 
But your custom method should send data to the controller side, must contain the below arguments. 
 
  var data = { 
        'action':  
        'path':  
        'names':  
        'data':  
      }; 

Refer the below link to know more about the request parameter for Download operation. 
 
 
Please let us know, if you have any need any further assistance. 
 
Regards,  
Shameer Ali Baig S. 



UN Unknown Syncfusion Team June 22, 2020 08:14 AM UTC

Hello Shameer. I am not interested in implementing my own method just for providing a token in the header. That should not be necessary.


SP Sowmiya Padmanaban Syncfusion Team June 23, 2020 04:33 PM UTC

Hi Morten,  
 
Currently, we have used the form option for download a file from the file manager. So, In Download operation, we are unable to add the header token for FileManager component. To achieve your requirement, we need to use the XHRHttpRequest to download the file from the server. Using the XHRHttpRequest approach for downloading, it will download the file into browser cache once before saving the file locally. This will slow down the download process, since double the time file will be downloaded also it utilizes more bandwidth.  
 
Due to that, we couldn’t consider this support in our FileManager component level.  
 
In our previous update [October 8, 2019], we have provided a details regarding your requirement. You can achieve your requirement by using custom download. 
 
Please let us know, if you need any further assistance. 
 
Regards,  
Sowmiya.P  



JH James Harrelson December 14, 2020 04:42 PM UTC

On GetImages could there be a way to add a query parm? I could then pass my token in the url.



SP Sowmiya Padmanaban Syncfusion Team December 15, 2020 08:37 AM UTC

Hi James Harrelson,  
  
You can send the custom attribute as query parameter in image URL for GetImage operation by using beforeImageLoad event.  
 
Please refer the below code snippet. 
 
 <ejs-filemanager 
    id="overview" 
    [ajaxSettings]="ajaxSettings" 
    (beforeImageLoad)="beforeImageLoad($event)" 
    [view]="view" 
  > 
  </ejs-filemanager> 
 
  beforeImageLoad(args) { 
    // Add custom parameter in image URL 
    args.imageUrl = args.imageUrl + "&custom_attribute=" + "Syncfusion"; 
  } 
 
Also, to receive the custom parameter in server side GetImage method, you need to add the custom attribute in base class file. Please, refer the below code. 
 
public class FileManagerDirectoryContent1 
    { 
        public string Name { get; set; } 
        public string custom_attribute { get; set; } 
        public string[] Names { get; set; } 
} 
[Route("GetImage")] 
        public IActionResult GetImage(FileManagerDirectoryContent1 args) 
        { 
            return this.operation.GetImage(args.Path, args.Id,false,null, null); 
        }      
 
Please, refer the below output screenshot of the above suggested solution. 
 
 
 
Please, refer the below sample link. 
 
 
 
Note: Run the service and refer the local host URL in the sample. 
 
Please, refer the below forum link for your reference. 
 
 
Please let us know, if you need any further assistance. 
 
Regards,  
Sowmiya.P 



LM Luke Mitchell January 8, 2021 11:35 PM UTC

It is not secure or good practice to send auth tokens as query parameters. Do you have plans to address this? There should be an easy way to provide auth headers before every request that this component sends. Security should be the number one priority.

Edit: Something like what you've done here would be excellent! https://help.syncfusion.com/js/datamanager/adavancedfunctionalities#custom-request-headers


SP Sowmiya Padmanaban Syncfusion Team January 11, 2021 12:38 PM UTC

Hi Luke Mitchell,  
 
Based on the current implementation of FileManager component, we have used form submit for download operations of FileManager component and not a ajax request. So, we can’t add the JWT token with this request. However, you can add the custom data to the download operations using beforeDownload event. 
 
Please, refer the below forum link for beforeDownload operations. 
 
 
However, we have used Query parameter for GetImage operations of FileManager component. Other than the two operations ( Download, GetImage), you can send the JWT token using beforeSend event of FileManager component. 
 
Please let us know, if you need any further assistance. 
 
Regards,  
Sowmiya.P 



LM Luke Mitchell replied to Sowmiya Padmanaban January 11, 2021 04:52 PM UTC

Hi Luke Mitchell,  
 
Based on the current implementation of FileManager component, we have used form submit for download operations of FileManager component and not a ajax request. So, we can’t add the JWT token with this request. However, you can add the custom data to the download operations using beforeDownload event. 
 
Please, refer the below forum link for beforeDownload operations. 
 
 
However, we have used Query parameter for GetImage operations of FileManager component. Other than the two operations ( Download, GetImage), you can send the JWT token using beforeSend event of FileManager component. 
 
Please let us know, if you need any further assistance. 
 
Regards,  
Sowmiya.P 


When do you plan on fixing the implementation of the file manager to allow for easily setting headers? Providing a token as a query param for GetImageUrl is bad security and not good practice. Users should be able to set headers for all requests that this component makes very easily.

I must say, our team purchased a license for Syncfusion solely for this component and I'm not impressed with its design for not taking security and private filesystems into account.

Please escalate this issue if you can and fix this component to allow for properly settings headers for all requests.


KR Keerthana Rajendran Syncfusion Team January 12, 2021 03:56 PM UTC

  
Hi Luke, 
 
We have validated your concerns with the FileManager component. We would like to let you know that, all the file operations in FileManager is being performed in a secured way. To pass different token values for each request based on user’s requirement, we have provided beforeSend event and this is the solution to pass token. 
 
We have used GetImage operation to show image preview in LargeIcons view. We have not used Ajax for this action and if this is not required in your end, you can also disable the GetImage option using showThumbanil property(defaults to true)  to prevent the request sent to fetch the image.  
 
As mentioned earlier, we have used the form option for downloading a file from the file manager. Here, you are unable to add the authorization header. To achieve your requirement, you can also cancel our default download actions using beforeDownload event and perform custom download based on your scenario.  
 
Please let us know if you need further assistance.  
 
Regards, 
Keerthana.  



JB Jyoti Bajpai replied to Ashokkumar Balasubramanian October 7, 2022 11:25 AM UTC

We have implemented customdownload() function in react and now we are able to pass the keycloak username and token to download api in file manager. But the downloaded file is of 'file' type instead of original file type. For eg: if we download word document, downloaded file is of 'file' type instead of '.doc' and  we have to open it using ms word only. Also, the name of the file is also changed. 




SS Sivakumar ShunmugaSundaram Syncfusion Team October 10, 2022 11:52 AM UTC

Hi Jyoti,


We have prepared a simple sample of the React FileManager component with a custom download operation, and the sample works fine with the proper downloaded file. We suspect that the issue occurs due to missing Content-Disposition code details on your controller side.


To overcome the issue, we suggest you include the below code changes in your controller Download method. We have attached the prepared service provider with a sample for your reference.


Refer to the below code snippet.


[FileManagerController.cs]

 

[Route("Download")]

        public IActionResult Download(string downloadInput)

        {

            var headerValue = Request.Headers["Custom-Header"].ToString();

            Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");

            FileManagerDirectoryContent args = JsonConvert.DeserializeObject<FileManagerDirectoryContent>(downloadInput);

            return operation.Download(args.Path, args.Names, args.Data);

        }

 


Sample: https://stackblitz.com/edit/react-vuwczm?file=index.js


Service provider: https://www.syncfusion.com/downloads/support/directtrac/general/ze/ej2-aspcore-file-provider1999555932.zip


Please check the attached sample and get back to us if you need any further assistance.


Regards,

Sivakumar S




MM Matthew Marichiba January 17, 2023 10:50 PM UTC

Here is an entirely client-side solution that is working for me, which I prefer strongly over the solutions discussed above. In my case, I couldn't adjust the auth behavior of the server-side code, because we integrated the FileManager service's controllers into our overall app and I didn't want to start making one-off tweaks to accommodate this SyncFusion quirk.


So here you go...

In my Angular app I have a service providing custom operations to the FileManager back-end. This service is also the source-of-truth that provides the AjaxSettings​ properies everywhere throughout the app. You could structure it differently, but whatever the case, the following code needs to run before the FileManager component starts firing HTTP requests to the server.


this.ajaxSettings = {
url: `${baseUrl}/fileOperations&syncfusion`,
getImageUrl: `${baseUrl}/image&syncfusion`,
uploadUrl: `${baseUrl}/upload&syncfusion`,
downloadUrl: `${baseUrl}/download&syncfusion`,
};

this.patchXMLHttpRequestForAuth();

...

/**
* This is a kludge that patches auth tokens into the HTTP requests made by the FileManager component.
* This is necessary because SyncFusion's FileManager component makes HTTP requests to the back-end
* service with XMLHttpRequest directly, outside the scope of Angular's HttpClient.
* This function monkey-patches an updated version of XMLHttpRequest.open(), which is ugly but
* gets the job done.
*/
private patchXMLHttpRequestForAuth(): void {
const xhr = XMLHttpRequest as any;
const origOpen = XMLHttpRequest.prototype.open;
const getHeaders: () => { [key: string]: string } = this.getHttpAuthHeaders;

// Overwrite the open() method with a new definition.
XMLHttpRequest.prototype.open = function(...args) {
// Check the URL to see if this request comes from syncfusion
let url = args[1];
let needsAuth: boolean;
if (typeof url !== 'string') {
needsAuth = false;
} else {
needsAuth = url?.includes('&syncfusion');
}

if (needsAuth) {
url = (url as string).replace('&syncfusion', '');
args[1] = url;
}

// First call the original open() method and get its result.
// open() must finish before setRequestHeader() can be called.
const origResult = origOpen.apply(this, args);

if (needsAuth) {
const headers = getHeaders();
if (!headers) {
return;
}

for(const key of Object.keys(headers)) {
this.setRequestHeader(key, headers[key]);
}
}

return origResult;
}
}


The &syncfusion​ slug in the ajax settings URLs allows the updated version of XMLHttpRequest.open() to identify just the requests coming from the syncfusion component. We don't​ want to add headers to all other requests, leaving auth headers to the services provided by Angular.


TO THE SYNCFUSION TEAM: For what it's worth, I *wish* there was a solution to provide a getHeaders()function on the AjaxSettings object. If such a feature were available, it seems trivial for FileManager's HTTP request logic to call getHeaders() when creating each request, and add whatever user-defined headers are needed. Something like this:

this.ajaxSettings: AjaxSettingsModel = {
getHeaders: () => this.dynamicHeaders,
url: `${baseUrl}/fileOperations&syncfusion`,
getImageUrl: `${baseUrl}/image&syncfusion`, // Currently unused.
uploadUrl: `${baseUrl}/upload&syncfusion`,
downloadUrl: `${baseUrl}/download&syncfusion`,
};


SS Sivakumar ShunmugaSundaram Syncfusion Team January 18, 2023 03:17 PM UTC

Matthew, we understand that you want to pass the HTTP header from the FileManager client side to the server side through the FileManager ajax setting instead of passing it in the FileManager operations event. We would like to inform you that our FileManager component's read, and upload operations are done through HTTP requests. Therefore, you can pass the header for those operations in the FileManager's beforeSend event. However, we do not have direct support for passing the header in the FileManager's download and GetImage operations as the download operation is done by the form submit method.

To overcome this issue, we suggest you follow the way suggested in this forum's previous update. However, if we misunderstood your exact requirement, please share some additional details related to your exact requirement with the FileManager component. This will allow us to fully understand your requirement and provide a solution that meets your needs.



Loader.
Live Chat Icon For mobile
Up arrow icon