How to remove user Labels from Gmail using GScript - google-apps-script

In relation to another question that removes Category Labels, I'd like to use the same code and simply add other user labels to the routines created.
The routines are as follows:
function removeLabelsFromMessages(query, labelsToRemove) {
var foundThreads = Gmail.Users.Threads.list('me', {'q': query}).threads
if (foundThreads) {
foundThreads.forEach(function (thread) {
Gmail.Users.Threads.modify({removeLabelIds: labelsToRemove}, 'me', thread.id);
});
}
}
function ProcessInbox() {
removeLabelsFromMessages(
'label:updates OR label:social OR label:forums OR label:promotions',
['CATEGORY_UPDATES', 'CATEGORY_SOCIAL', 'CATEGORY_FORUMS', 'CATEGORY_PROMOTIONS']
)
<...other_stuff_to_process...>
}
I'm wondering if you can add another user label to the "labelsToRemove" - I've tried simply adding another label to the array, but keep getting an error stating the label cannot be found. I'm' sure it's just a syntax error (I don't code very much), so any suggestions on how to add that?
The code I'm trying to run is:
function CleanReceipts () {
removeLabel (
'label: Receipts',
['CATEGORY_UPDATES', 'CATEGORY_SOCIAL', 'CATEGORY_FORUMS', 'CATEGORY_PROMOTIONS', '#SaneLater']
)
}
where "#SaneLater" is the name of a user label I'd like to remove as well. Thanks in advance.

The reason you are getting the Label not found error is because the threads.modify method is expecting a label id and not a label name.
In order to retrieve the id of this specific label, I suggest you take a look at labels.list and make the request to get the appropriate value:
let labels = Gmail.Users.Labels.list('me');
console.log(labels);
Reference
Gmail API users.threads.modify.

Related

ngOnChanges only works when it's not the same value

So basically I have a modal component with an input field that tells it which modal should be opened (coz I didn't want to make a component for each modal):
#Input() type!:string
ngOnChanges(changes: SimpleChanges): void {
this.type = changes["type"].currentValue;
this.openModal();
}
that field is binded to one in the app component:
modalType = "auth";
HTML:
<app-modal [type] = modalType></app-modal>
In the beginning it's got the type "auth" (to login or register), but when I click on an icon I want to open a different modal, I do it like so:
<h1 id="options-route"
(click) ="modalType = 'settings'"
>⚙</h1>
but this only works the first time, when modalType already has the value "settings" the event doesn't trigger even though the value has technically changed
I think the problem is that it's the same value because i tried putting a button that does the exact same thing but with the value "auth" again and with that it was clear that the settings button only worked when tha last modal opened was auth and viceversa
any ideas? I want to be able to open the settings modal more than once consecutively possibly keeping onChange because ngDoCheck gets called a whole lot of times and it slows down the app
You need to include the changeDetectorRef, in order to continue in this way.
More about it https://angular.io/api/core/ChangeDetectorRef
Although, a better and a faster alternative is the use of a behavior Subject.
All you have to do is create a service that makes use of a behavior subject to cycle through each and every value exposed and then retrieve that value in as many components as you want. To do that just check for data changes in the ngOnInit of target component.
You may modify this for implementation,
private headerData = new BehaviorSubject(new HeaderData());
headerDataCurrent = this.headerData.asObservable();
changeHeaderData(headerDataNext : HeaderData) {
this.headerData.next(headerDataNext)
console.log("subscription - changeUserData - "+headerDataNext);
}
Explanation:
HeaderData is a class that includes the various values that can be shared with respective data types.
changeHeaderData({obj: value}), is used to update the subject with multiple values.
headerDataCurrent, an observable has to be subscribed to in the target component and data can be retrieved easily.
I mean i'm too l-a-z-y to use your slightly-not-so-much-tbh complicated answers so I just did this:
I added a counter that tops to 9 then gets resetted to 0 and I add it to the value
screwYouOnChangesImTheMasterAndYouShallDoMyBidding = 0;
//gets called onClick
openSettings(){
if(this.screwYouOnChangesImTheMasterAndYouShallDoMyBidding === 9){
this.screwYouOnChangesImTheMasterAndYouShallDoMyBidding = 0;
}
this.screwYouOnChangesImTheMasterAndYouShallDoMyBidding = this.screwYouOnChangesImTheMasterAndYouShallDoMyBidding + 1;
this.modalType = "settings"+this.screwYouOnChangesImTheMasterAndYouShallDoMyBidding;
}
then in the child component I just cut that last character out:
ngOnChanges(changes: SimpleChanges): void {
let change = changes["type"].currentValue as string;
change = change.substring(0, change.length - 1);
this.type = change;
this.openModal();
}
works like a charm 😂

Inject Folder ID from selection in GDrive Addon and suppress cardflip

I am trying to get the scope of gdrive to create a file from some form values with my addon.
To achieve this, I added a handler to the manifest and implemented the corresponding function.
"onItemsSelectedTrigger": {
"runFunction": "onDriveItemsSelected"
}
In the function I can use the following as ID of the first selected item. (I currently check Mimetype to keep it simple...)
createFolderID = e['drive']['selectedItems'][0].id;
Now I have two problems:
1.
When clicking a folder within the gdrive - the event function seems to await a built card as return value. I just want to use the selected folder (or ideally the folder where I am currently "in", via getparent?), without needing an additional card. If I return null, the card is created anyway above my addon card and shown with "No content shown for this message".
Is there away to avoid this?
2.
I need to inject the folder ID of the selected folder into my form (which I created with CardService at start of the addon). Declaring a "global" var does not seem to work,I assume that the cloud context will not preserve the variable value. The value is needed as parameter to a created document of my addon.
Can anyone point me into the right direction to store this folder Id until the user runs the addons action?
EDIT:
/**
* Get the selected folder to create the offer in
*/
function onDriveItemsSelected(e) {
// We check only the first selection
if (e['drive']['selectedItems'][0].mimeType == "application/vnd.google-apps.folder")
{
createFolderTitle = e['drive']['selectedItems'][0].title;
createFolderID = e['drive']['selectedItems'][0].id;
Logger.log(e['drive']['selectedItems'][0].title + " selected. ID: " + createFolderID)
PropertiesService.getUserProperties().setProperty('selectedFolderId', createFolderID);
}
}
The following snippet is contained in the manifest to link the function to selection events.
"drive": {
"homepageTrigger": {
"runFunction": "initForm"
},
"onItemsSelectedTrigger": {
"runFunction": "onDriveItemsSelected"
}
}
I use this for catching the selection event. But the card on the right side is then overlayed with an empty card with the message I already mentioned.
You can always pass a default parameter to a function.
Example:
function createForm(selectedFolderId = PropertiesService.getUserProperties().getProperty("selectedFolderId")) {
let form;
// Create the form
return form;
}
References:
PropertiesService
Update:
When you use OnItemsSelectedTrigger you must return an array of Card objects.

VueJs component names

I'm working in VueJS and i have the following code
<li #click = "selectedComponent = 'appManagment'"><i class="ion-clipboard"></i>Management</li>
so what i try to accomplish is to display the name like {{selectedComponent}}
but as excpected it displays "appManagment" because this is the component that was selected.
So the question is, how to display a different name, for example i want just "Managment" to appear instead of "appManagment".
I'm using it for the navigation menu that displays where the user is located, so any help would be appreciated.
I would create an object like the one below
var prettyNames = {
'appManagment': 'Some very nice name'
}
and then just use it whenever you want to display text which corresponds to the currently selected component. For example
prettyNames[selectedComponent]
You can register a custom filter with the global Vue.filter() method, passing in a filterID and a filter function. The filter function takes a value as the argument and returns the transformed value:
Vue.filter('custom', function (value) {
// add your code to determine
// name based on value here
return newName;
})
Then use your filter on the text:
<i class="ion-clipboard"></i>{{ selectedComponent | custom }}

Get all sub-labels of a Gmail label through a Google Script

I would like to get all child labels of a given parent label. Is it possible?
In How to check if a Gmail label has a nested sub-label? it is checked whether all labels have a sub-label, and I tried doing something similar for an specific one, but with no results.
The parent-child relation of Gmail labels is based on their names: it you have a label "foo/bar" and there is also a label named "foo", then the former is considered a child of the latter. (I just tested this by manually creating "foo/bar" label and then "foo"; as soon as "foo" appeared, it acquired "bar" as a child.)
So, the following function will return the list of all labels that are children of the given label. (The argument parent here is a label itself, not its name).
function children(parent) {
var name = parent.getName() + '/';
return GmailApp.getUserLabels().filter(function(label) {
return label.getName().slice(0, name.length) == name;
});
}

pre-load search query to link from table and pass it to ajax

So I currently have a table that's generated by ajax and json file.
The table has 3 segments, a name, an ID and the third column is a link for more details of each result.
Example of how my table looks
PATO:0001243 light blue Details
PATO:0001246 light brown Details
PATO:0001247 light cyan Details
the current code I have to generate the table is:
$.each(data.matches, function(i, item){
var this_row_id = 'result_row_' + next_row_num++;
$('<tr/>', {"id":this_row_id}).appendTo('tbody');
$('<td/>', {"text":item.label}).appendTo('#'+this_row_id);
$('<td/>', {"text":item.value}).appendTo('#'+this_row_id);
$(''+ 'Details' +'').appendTo('#'+this_row_id);
});
Ideally, I would like to be able to click on the "Details" and it would pass the ID value to another ajax call and then create a dialog/modal to display the results of that ajax call.
EXAMPLE
From the list above, clicking on "Details" from the first entry will pass the values "PATO:0001234" to my "test.cgi" script which will use that value to process and spit back out a JSON for me to display in a dialog.
I'm not asking for someone to write my code for me, just some direction about how to approach this.
I think I'm probably wrong to link directly to my cgi script from the <a href>. But I don't know how to link that to an ajax call from a text link.
Update
Left the page loaded too long; #floatless has posted a cleaner approach with chaining, didn't think of that.
You could change the last few lines to something like what's below. The idea is to attach a handler to each link when it's created which will call the loadDetail function with the appropriate item label. In loadDetail, it's then a simple matter of making an ajax request with the label as the parameter.
Note that you don't need to use ./test.cgi - test.cgi will suffice.
...
$(''+ 'Details' +'').appendTo('#'+this_row_id);
$('#detail_' + this_row_id).click(loadDetail(item.label));
}
function loadDetail(label){
$.get('test.cgi', {label: label}, function(data){
//create your dialog to display the response data
});
}
You could append click event handler while generating table:
$(''+ 'Details' +'').appendTo('#'+this_row_id).click(function()
{
$.getJSON("./test.cgi", {label: item.label}, function(data)
{
//Do something with received data
});
return false;
});